# Architecture Decision Records — Wedding Newspaper Generator > Durable ADR log for the significant design choices made in Domain Design. ## ADR-001: Cohesive Generator component over fine-grained splitting - **Context** — The generator is a single-purpose, fully-local tool. The team had to choose between one cohesive orchestrator with separated internal responsibilities (Q1=A) and several fine-grained independent components (ContentLoader, FunniesBuilder, LayoutEngine, Renderer). - **Decision** — Adopt a single `Generator` component that owns content parsing, the layout model, multi-page rendering, and emission, with its funnies and AI-draft concerns delegated to two distinct components (`Funnies`, `AiDraft`). - **Consequences** — (+) Simpler for a local tool; fewer moving parts; layout/print changes land in one place. (−) The Generator is larger; if the tool grows into a larger system this may need splitting later. - **Alternatives Rejected** — Option B (fine-grained components): over-fragmented for this scope. Option C (minimal thin script): collapses concerns and loses testability. ## ADR-002: Distinct optional AiDraft component (local Ollama only) - **Context** — AI copy generation (US8/US9/FR8) uses local Ollama and must be fully optional and stay on-machine (NFR9). The team chose whether to isolate it. - **Decision** — Model `AiDraft` as a distinct, fully-optional component that talks only to local Ollama and owns the draft + per-article review contract. When `--draft` is absent it does nothing. - **Consequences** — (+) No-draft runs never touch AI; the AI integration is isolated and easier to test/disable; content stays local. (−) One more component boundary to document. - **Alternatives Rejected** — Folding Ollama calls into the generator: couples the optional AI path into the core and makes "no AI" runs carry AI code. ## ADR-003: Funnies generation owned by a distinct component - **Context** — The funnies (crossword, find-a-word, comics, xkcd cartoon) are generated from the content itself (US3/FR4/Q5=X), which is non-trivial work. - **Decision** — Give `Funnies` its own component that derives theme words/context from content and produces the crossword/find-a-word grids and the embedded cartoon. It emits A4-printable, self-contained blocks. - **Consequences** — (+) Puzzle logic is isolated from layout so layout changes don't destabilize generation; content-derived puzzles feel hand-crafted. (−) The content→puzzle heuristic is genuinely complex and must handle a no-cartoon fallback (mockups R-02). - **Alternatives Rejected** — Folding funnies into the generator: couples puzzle heuristics into layout; separate puzzle-gen and cartoon-fetch sub-components: over-split for now. ## ADR-004: Draft bundle read via native file picker (no-server review handoff) - **Context** — The per-article review page (US9/Q3=A) is a single `file://` page, and the no-server/zero-network constraints (NFR3–NFR5) forbid `fetch()` of sibling files and forbid running a server during review (Q1=A / Q4=B). - **Decision** — The CLI writes the AI draft as a JSON `DraftBundle`; the review page loads it through the **native file picker** (user-granted read, NFR5). This resolves the mockups R-01 finding. - **Consequences** — (+) Review works fully offline, no server, no CORS workaround (§12 of the empirical file:// research). (−) The couple must pick the draft bundle in the file dialog once per run. - **Alternatives Rejected** — Serving a temporary localhost just during review (violates the no-server decision and adds a process to the flow); CLI prompt loop instead of an HTML review page (departs from confirmed Q3=A). ## ADR-005: Lightweight plain-data entities, filesystem as store - **Context** — The project is a local generator with no deployment; the entities are Issue, Article, MastheadConfig, Puzzle, DraftBundle. - **Decision** — Model them as lightweight plain-data shapes owned by the generator; the content `config.json` + `content/` filesystem is the store. No database. - **Consequences** — (+) No infra to run; entities are trivially serializable (the DraftBundle JSON is one shape); fits the static-generator model. (−) No built-in indexing/querying — not needed at this scale. - **Alternatives Rejected** — A formalized strict-schema data layer: unnecessary overhead for a static local tool. No explicit entity model: would make the review handoff and traceability harder to test.