diff options
| author | erdgeist <erdgeist@erdgeist.org> | 2026-07-19 18:22:47 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@erdgeist.org> | 2026-07-19 18:22:47 +0200 |
| commit | f9e4623dfc3a1349522ada1be90703bf7160bf06 (patch) | |
| tree | 334e2e0d865b408783730ff2f7257e5aaaf2ba5c /doc | |
| parent | 68368d6cff798a9df8e931e8ee1f44ae0dc02a14 (diff) | |
Add section about the nodes life cycle to history book
Diffstat (limited to 'doc')
| -rw-r--r-- | doc/DESIGN_HISTORY.md | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/doc/DESIGN_HISTORY.md b/doc/DESIGN_HISTORY.md index 0bf780a..1836333 100644 --- a/doc/DESIGN_HISTORY.md +++ b/doc/DESIGN_HISTORY.md | |||
| @@ -1,3 +1,76 @@ | |||
| 1 | ## The head / draft / autosave / translation lifecycle | ||
| 2 | |||
| 3 | ### Era 1 — the original design (2009, `doc/README_FOR_APP`). | ||
| 4 | |||
| 5 | Two layers only: `head` (the published, public revision) and `draft` | ||
| 6 | (a full copy of head's content, created the moment someone starts | ||
| 7 | editing). | ||
| 8 | |||
| 9 | No separate lock concept. The draft's *author* was the lock. | ||
| 10 | Pessimistic, one editor at a time, enforced by ownership rather than | ||
| 11 | a distinct column. An author could withdraw authorship (the draft | ||
| 12 | becomes author-less, open for someone else to pick up) or discard | ||
| 13 | the draft entirely, reverting to head. | ||
| 14 | |||
| 15 | Admins could override any lock or remove any stuck draft on another | ||
| 16 | editor's behalf. No autosave. | ||
| 17 | |||
| 18 | Globalize wasn't part of the permission model (`Permission` grants | ||
| 19 | admin rights to steal a lock a node. | ||
| 20 | |||
| 21 | ### Why a third layer got added. | ||
| 22 | |||
| 23 | Under the original model, the moment someone started typing, a real, | ||
| 24 | numbered revision already existed: `acts_as_list` assigns revision | ||
| 25 | numbers at creation, scoped to `node_id`. | ||
| 26 | |||
| 27 | A speculative edit (open the editor, type a few words, close the tab) | ||
| 28 | still counted as a real Draft, and a real future revision if it were | ||
| 29 | ever published. | ||
| 30 | |||
| 31 | The rebuild introduced `autosave` as a genuinely separate layer: the | ||
| 32 | same `Page` model, but created with `node_id: nil` specifically so | ||
| 33 | it's excluded from `Node#pages`, the actual revision list. | ||
| 34 | |||
| 35 | Typing progress survives a crash or a closed tab, but nothing becomes | ||
| 36 | a real revision until the editor deliberately saves, which promotes | ||
| 37 | the autosave's full content, wholesale, into the draft layer via | ||
| 38 | `clone_attributes_from`. | ||
| 39 | |||
| 40 | A canonical six-state reference table (head / draft / autosave present | ||
| 41 | or absent, and what each combination permits) lives alongside the model | ||
| 42 | code as the authority for any future work on this lifecycle. | ||
| 43 | |||
| 44 | ### Translations (Globalize), layered on top | ||
| 45 | |||
| 46 | The governing principle for admin views from that rebuild: | ||
| 47 | |||
| 48 | *presentation locale* (what language the admin chrome renders in) and | ||
| 49 | *content-target locale* (which translation a given screen reads or | ||
| 50 | writes) are separate concerns that must never share a mechanism. | ||
| 51 | |||
| 52 | The route's `:locale` segment governs only the former. A locale is | ||
| 53 | either the default one — edited exclusively through the primary node | ||
| 54 | editor, pinned via `Globalize.with_locale` regardless of what the route | ||
| 55 | happens to say, so a stray `/en/` URL can't silently edit the German | ||
| 56 | content (as has been the case before the rewrite in 2026), or one of | ||
| 57 | the non-default locales, edited exclusively through a Translations | ||
| 58 | sub-resource under a deliberately distinct route parameter | ||
| 59 | (`translation_locale`), chosen specifically because it must never leak | ||
| 60 | into `default_url_options` the way the chrome locale does. Never both | ||
| 61 | paths for the same locale. | ||
| 62 | |||
| 63 | For now, admin chrome language stays tied to the route locale for now. | ||
| 64 | A per-editor preference column was considered and set aside as | ||
| 65 | revisit-later, not built. | ||
| 66 | |||
| 67 | Translations carry no independent publish state: a translation goes | ||
| 68 | live exactly when the draft containing it is promoted to head, same | ||
| 69 | as everything else in that `Page` row. Both a per-translation | ||
| 70 | `published_at` and full per-locale draft/head/autosave parity with | ||
| 71 | `Node` were considered and rejected as unneeded machinery absent a | ||
| 72 | real editorial need for staggered release timing. | ||
| 73 | |||
| 1 | ## Events and the calendar | 74 | ## Events and the calendar |
| 2 | 75 | ||
| 3 | ### Problem | 76 | ### Problem |
