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