Document Generation

docs specs/docs/generation.kmd

Tipos de documento gerados por categoria de objeto (Stack, Area, Sector, Module, Flow, RFC), requisitos de capa, regras de identidade visual e templates CSS para PDFs. Consultado no início da Fase 3 do `/k-housekeep`.

Quando esta spec se aplica

Todos os triggers

Corpo da especificação

Spec: Document Generation

Scope: Defines which document types are generated for each category of Koder Stack object (Stack, Area, Sector, Module, Flow, RFC), cover page requirements, and visual identity rules for generated PDFs.

Enforcement: /k-housekeep Phase 3 reads this spec and generates or updates the full PDF bundle accordingly.


1. Object categories

The Koder Stack has five object categories that drive documentation generation. Each category has a fixed set of document types (see §2).

Category Definition Examples
Stack The entire Koder Stack as a whole
Area One of the 9 canonical Areas (docs/stack/areas.md) Foundation, Data Platform, Workspace …
Sector A named grouping of related modules within an Area (second column in areas.md) Koder Linux, KDB, Edge/Jet, Intelligence …
Module Any active module in the monorepo (see areas.md rows, third column) platform/id, infra/jet, apps/keys
Flow A named cross-cutting flow that spans two or more Areas (docs/stack/diagrams/flows/) auth flow, data-write flow, AI inference flow …

2. Document types per category

2.1 Stack

Document Format Source / Generator
Technical Reference PDF (A4, Typst) docs/stack/build/technical.typout/koder-stack-technical.pdf
Executive Slides PDF (A4, Typst) docs/stack/presentation/slides/main.typout/koder-stack-slides.pdf

2.2 Area

One set of documents per Area (9 total). Output folder: <N>-<area-slug>/ in the bundle.

Document Format Content
Area Slide Deck PDF (A4 landscape, WeasyPrint) Cover + module inventory (one card per module: icon, name, one-line description) + flows & integrations diagram + integration map (which modules call which) + sector breakdown
Area Deep-Dive PDF (A4 portrait, WeasyPrint) Cover + Area description + Sector table + per-module summary (3-5 lines each) + cross-module flow descriptions + diagrams (D2 rendered to PNG and embedded)
Area Diagrams PDF (A4 landscape, WeasyPrint) One page per diagram file under docs/stack/diagrams/areas/<area>.d2 (rendered via d2 --theme 0)

2.3 Sector

One set of documents per Sector row in areas.md. Output folder: <N>-<area-slug>/sectors/<sector-slug>/.

Document Format Content
Sector Slide Deck PDF (A4 landscape, WeasyPrint) Cover + module list (icon, name, one-line description for each module in the sector) + integration diagram within the sector + relationships to other sectors
Sector Overview PDF (A4 portrait, WeasyPrint) Cover + what the sector does + why it's grouped + module summaries + typical data flows within the sector

2.4 Module

One set per active module. Output folder: <N>-<area-slug>/<module-name>/.

Document Format Content
Deep-Dive PDF (A4, WeasyPrint) docs/stack/modules/<module>.md — role, couplings, interfaces, status
RFC(s) PDF (A4, WeasyPrint) Each .md / .kmd under <module>/docs/rfcs/
Manual(s) PDF (A4, WeasyPrint) Each .md under <module>/docs/technical/, <module>/docs/user/, <module>/docs/operator/
Slide Deck PDF (A4 landscape, WeasyPrint) Cover + what it does + architecture overview + key interfaces + status + roadmap (sourced from README + deep-dive)
README PDF (A4, WeasyPrint) <module>/README.md or <module>/README.kmd
CHANGELOG PDF (A4, WeasyPrint) <module>/CHANGELOG.md if it exists

RFCs and Manuals may not exist for every module — skip silently if source files are absent.

2.5 Flow

One document per flow diagram file under docs/stack/diagrams/flows/.

Document Format Content
Flow Diagram PDF (A4 landscape, WeasyPrint) Cover + rendered D2 diagram + written description of the flow (from companion .md if present, else auto-generated from diagram node labels)

3. Cover page specification

Every generated PDF must start with a cover page. No exceptions.

3.1 Cover page layout (portrait documents)

┌─────────────────────────────────────────────┐
│                                             │
│  [icon 96×96 px, centered]   ← Module only │
│                                             │
│  ────────────────────────────────────       │
│  KODER STACK                                │ ← brand line, 10pt, #94a3b8
│  <Area / Sector / Module / Flow name>       │ ← category label, 10pt, #64748b
│                                             │
│  <Document Title>                           │ ← 28pt bold, #0f172a
│                                             │
│  <subtitle / tagline — one line>            │ ← 14pt, #475569
│                                             │
│  ────────────────────────────────────       │
│                                             │
│  <Status badge if applicable>               │ ← e.g. "Pre-Alpha", "Draft"
│  <Date>  ·  Koder                           │ ← 9pt, #94a3b8
│                                             │
└─────────────────────────────────────────────┘

3.2 Cover page layout (landscape documents — slide decks, diagrams)

Same structure as portrait but centred horizontally on an A4 landscape page. Icon is 128×128px.

3.3 Icon placement rules

  • Module documents: the module's icon.svg (rasterised to 96px for portrait, 128px for landscape) appears centred above the title on the cover page. Area-first products (RFC-001) may keep the canonical icon.svg at the product root (<area>/<product>/icon.svg) or at a distribution root (<area>/<product>/platform/icon.svg, <area>/<product>/app/icon.svg, <area>/<product>/app/<surface>/icon.svg). The generator resolves deepest-first for files inside a sub-product, falling back to the product root — it must never substitute the Koder brand mark when a module-local icon.svg exists anywhere in the product tree.
  • Area documents: use the area's representative icon if one exists under docs/stack/presentation/assets/icons/<area-slug>.svg; otherwise use the Koder brand mark (meta/brand/koder-papelaria/koder-marca.svg scaled to 96px).
  • Sector documents: use the first module icon of the sector (alphabetical by module path) as representative icon.
  • Stack documents: use the Koder brand mark.
  • Flow documents: use the Koder brand mark.

Brand-fallback policy. The Koder brand mark may only be used as a cover icon for Stack, Area, and Flow documents. For any module document, if no module icon.svg can be located, the generator must render the cover page without any icon rather than substitute the Koder mark. Logging a warning is mandatory; silent substitution hides missing-icon bugs in the catalogue.

3.4 Icon in document body (first content page)

For module documents only: on the first content page (immediately after the cover), place the module icon inline at the left of the document title heading (<h1>). Implemented in the HTML template as:

<h1 class="doc-title">
  <img src="{icon_path}" class="title-icon" alt="">
  {document_title}
</h1>
.doc-title { display: flex; align-items: center; gap: 14px; }
.title-icon { width: 48px; height: 48px; flex-shrink: 0; }

This applies to: Deep-Dive, RFC, Manual, README, CHANGELOG, and Slide Deck (first slide title).


4. Content requirements per document type

4.1 Area Slide Deck — required slides

  1. Cover (§3)
  2. "What is <Area>?" — 3-5 sentences, area rule-of-thumb
  3. Sector map — one row per Sector: sector name + modules in it (pill list)
  4. Module cards — one slide per module: icon (64px) + name + one-line description + status badge
  5. Integration map — which modules depend on which (generated from deep-dive coupling tables)
  6. Key flows — one slide per flow that is internal to this Area
  7. Connections to other Areas — list of cross-area dependencies

4.2 Module Slide Deck — required slides

  1. Cover (§3, with module icon 128px centred)
  2. "What is <Module>?" — role, one-paragraph description
  3. Architecture overview — diagram (embed docs/stack/diagrams/modules/<module>.d2 if present, else text-based)
  4. Primary couplings — table: dependency | purpose | protocol
  5. Interfaces — APIs, CLI commands, config keys (from deep-dive Interfaces section)
  6. Status & roadmap — status badge + 3-5 bullet points from backlog/STATUS

4.3 RFC — required sections

RFCs are author-written; the generator does not synthesise content. The generator only:

  • Adds the cover page (§3)
  • Adds the module icon to the first <h1> (§3.4)
  • Reformats for A4 margins and page numbering

If an RFC source file already has a cover section (frontmatter with title:, status:, date:), extract those values for the cover page instead of inferring.

4.4 Manual — required sections

Same as RFC rule: generator adds cover + icon + layout, does not synthesise content.


5. Source → output mapping

The generator traverses these source locations in priority order for each module:

<module>/icon.svg               → cover icon, h1 icon
<module>/README.md              → README.pdf
<module>/README.kmd             → README.pdf (prefer over .md if both exist)
<module>/CHANGELOG.md           → CHANGELOG.pdf
<module>/STATUS.md              → included in Slide Deck slide 6
<module>/docs/rfcs/*.md         → RFC-*.pdf (one per file)
<module>/docs/rfcs/*.kmd        → RFC-*.pdf
<module>/docs/technical/*.md    → Manual-*.pdf
<module>/docs/user/*.md         → Manual-*.pdf
<module>/docs/operator/*.md     → Manual-*.pdf
docs/stack/modules/<module>.md  → Deep-Dive.pdf

For Areas and Sectors, the generator synthesises the slide decks and overviews from:

  • docs/stack/areas.md (sector/module lists)
  • docs/stack/modules/<module>.md (summaries per module)
  • docs/stack/diagrams/areas/<area>.d2 (integration diagrams)
  • docs/stack/diagrams/flows/<flow>.d2 (flow diagrams)

6. Naming conventions for output files

Object File name pattern
Area Slide Deck <N>-<area-slug>/slides-<area-slug>.pdf
Area Deep-Dive <N>-<area-slug>/overview-<area-slug>.pdf
Area Diagrams <N>-<area-slug>/diagrams-<area-slug>.pdf
Sector Slide Deck <N>-<area-slug>/sectors/<sector-slug>/slides-<sector-slug>.pdf
Sector Overview <N>-<area-slug>/sectors/<sector-slug>/overview-<sector-slug>.pdf
Module Deep-Dive <N>-<area-slug>/<module>/deep-dive.pdf
Module Slide Deck <N>-<area-slug>/<module>/slides.pdf
Module RFC <N>-<area-slug>/<module>/rfcs/RFC-NNN-<slug>.pdf
Module Manual <N>-<area-slug>/<module>/docs/<filename>.pdf
Module README <N>-<area-slug>/<module>/README.pdf
Module CHANGELOG <N>-<area-slug>/<module>/CHANGELOG.pdf
Flow flows/<flow-slug>.pdf
Stack Technical Reference koder-stack-technical.pdf (root)
Stack Executive Slides koder-stack-slides.pdf (root)

7. What the generator must NOT do

  • Invent content: if source data is absent (no RFC file, no deep-dive, no D2 diagram), skip the document and log a warning. Do not fabricate text.
  • Override cover icons: if a module's icon.svg does not conform to the icon spec (meta/docs/stack/specs/icons/products.kmd), use it anyway and log a warning — do not substitute a generic icon silently.
  • Translate: all generated text (labels, auto-generated descriptions, slide titles) must be in en-US (meta/docs/stack/policies/language.kmd).

8. Slide deck CSS template (landscape, WeasyPrint)

@page {
    size: A4 landscape;
    margin: 1.5cm 2cm;
}
body  { font-family: -apple-system, 'Segoe UI', 'DejaVu Sans', sans-serif;
        font-size: 11pt; color: #1e293b; line-height: 1.5; }
.slide       { page-break-after: always; min-height: 18cm; display: flex;
               flex-direction: column; justify-content: flex-start; }
.slide-cover { justify-content: center; align-items: center; text-align: center; }
.slide-title { font-size: 22pt; font-weight: 700; color: #0f172a; margin-bottom: 8px; }
.slide-sub   { font-size: 13pt; color: #475569; }
.slide-h2    { font-size: 15pt; font-weight: 600; color: #1e3a8a; margin-bottom: 12px; }
.card-grid   { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.card        { border: 1px solid #e2e8f0; border-radius: 8px; padding: 12px;
               background: #f8fafc; }
.card-icon   { width: 48px; height: 48px; }
.card-name   { font-size: 11pt; font-weight: 700; color: #0f172a; margin: 6px 0 2px; }
.card-desc   { font-size: 9pt; color: #64748b; }
.status      { display: inline-block; padding: 2px 8px; border-radius: 12px;
               font-size: 8.5pt; font-weight: 600; background: #fef3c7; color: #92400e; }
.status.prod { background: #dcfce7; color: #14532d; }
table { border-collapse: collapse; width: 100%; font-size: 9.5pt; margin: 12px 0; }
th, td { border: 1px solid #e2e8f0; padding: 7px 11px; text-align: left; }
th { background: #f1f5f9; font-weight: 600; color: #0f172a; }

10. Document type taxonomy

10.1 Classification criteria

Every source file in the monorepo that is eligible for PDF generation is classified into exactly one Document Type based on its path pattern and filename. The classification is used to route files into the correct individual PDFs (§2) and the correct consolidated PDFs (§11).

Exclusions — never included in any documentation bundle:

  • context/ — internal configuration and rules
  • **/src/**/*.kmd — source-embedded documentation (not standalone docs)
  • **/.koder-rules/** — internal dev process rules
  • **/.changeset/** — release automation metadata
  • **/backlog/** — internal planning tickets (handled separately by koder-stack-backlog.pdf, see §11)
  • **/node_modules/**, **/vendor/**, **/target/** — generated artefacts

Top-level module filter: For READMEs and CHANGELOGs, only include files at depth <area>/<module>/README.{md,kmd} and <area>/<module>/CHANGELOG.md (i.e., module root level). Sub-package READMEs (e.g. platform/kdb/next/README.md) are excluded unless the sub-package is itself listed as a distinct module in areas.md.

10.2 Document type table

Code Type Source pattern(s) Quantity (surveyed)
OVW Overview / Deep-Dive docs/stack/modules/*.md · <module>/README.{md,kmd} (root only) ~50 deep-dives + ~90 module READMEs
RFC Design Proposal **/docs/rfcs/*.{md,kmd} · docs/stack/rfcs/**/*.{md,kmd} ~46
ARC Architecture **/docs/technical/architecture*.md · **/docs/technical/flows*.md · docs/stack/diagrams/**/*.d2 ~25
REF Reference **/docs/technical/api-reference*.md · **/docs/technical/*-api.md · **/docs/technical/protocols*.md · **/docs/technical/configuration*.md ~30
OPS Operations **/docs/technical/infrastructure*.md · **/docs/technical/dependencies*.md · **/docs/technical/security*.md · **/docs/operator/*.md ~25
USR User Guide **/docs/user/*.md · **/docs/technical/user-*.md ~10
REL Release / Changelog <module>/CHANGELOG.md (root only) · <module>/STATUS.md ~50
SLD Slides / Presentation docs/stack/presentation/slides/main.typ · synthesised per-area, per-module slide decks 1 Typst + N synthesised
GOV Governance <module>/CONTRIBUTING.{md,kmd} · <module>/CODE_OF_CONDUCT.{md,kmd} · <module>/SECURITY.{md,kmd} ~24
BKL Backlog **/backlog/{pending,in-progress,done}/*.md ~2920 (internal only)

10.3 Technical sub-classification rules

When a file matches multiple types (e.g. architecture.md could be ARC or OPS), apply in priority order:

  1. If filename contains architecture or flowsARC
  2. If filename contains api, reference, protocol, record-api, configurationREF
  3. If filename contains infrastructure, dependencies, security, deployment, operatorOPS
  4. If filename contains user-guide, tutorial, getting-started, or lives in docs/user/USR
  5. If none of the above and lives in docs/technical/ → classify as REF (conservative default)

11. Consolidated PDFs

At the end of Phase 3, after all individual module PDFs are generated, produce one consolidated PDF per document type that aggregates documents from every module into a single bookmarked file. These are the primary deliverables for external sharing, demos, and reference.

11.1 Consolidated PDF catalogue

File name (root of bundle) Types included Description
koder-stack-overview.pdf OVW Stack reference + area overviews + all module deep-dives, ordered by Area
koder-stack-rfcs.pdf RFC All design proposals from all modules, ordered by Area then module
koder-stack-architecture.pdf ARC All architecture docs + embedded D2 diagrams, ordered by Area
koder-stack-reference.pdf REF All API, CLI, protocol and config references, ordered by Area
koder-stack-operations.pdf OPS All operations, infrastructure and security guides, ordered by Area
koder-stack-user-guides.pdf USR All end-user documentation, ordered by Area
koder-stack-changelogs.pdf REL All module changelogs + STATUS files, ordered by Area
koder-stack-slides.pdf SLD Executive slides — Typst compiled (already generated in Phase 1)
koder-stack-technical.pdf OVW+ARC+REF+OPS Full technical reference — Typst compiled (already generated in Phase 1)
koder-stack-governance.pdf GOV Contributing guides, code of conduct, security policies
koder-stack-backlog.pdf BKL All backlog tickets across all modules — internal only

Omit a consolidated PDF if it would contain zero documents (e.g. if no USR files exist, skip koder-stack-user-guides.pdf and log a warning).

11.2 Cover page of consolidated PDFs

Each consolidated PDF has its own cover page following §3 with these specifics:

  • Icon: Koder brand mark (meta/brand/koder-papelaria/koder-marca.svg scaled to 96px) — never a module icon
  • Brand line: KODER STACK
  • Category label: Consolidated Reference
  • Title: the human-readable name (e.g. RFCs & Design Proposals)
  • Subtitle: All modules · <N> documents · <date>

11.3 Table of contents

Immediately after the cover, insert a ToC page listing every section (module or document) in the consolidated PDF, with page numbers. Format:

Area 1 — Foundation
  platform/id          Koder ID ............................. 3
  apps/keys            Koder Keys .......................... 12
  platform/kompass     Koder Kompass ....................... 19
Area 2 — Data Platform
  platform/kdb         KDB ................................. 27
  ...

11.4 Section dividers between modules

Between each module's documents, insert a section divider page:

┌─────────────────────────────────────────────┐
│  [Area colour band — left 8px]              │
│                                             │
│  [module icon 64×64]                        │
│  <Module name>                              │ ← 18pt bold
│  <Area> › <Sector>                          │ ← 10pt, muted
│  <Module one-liner from deep-dive>          │ ← 12pt
│                                             │
└─────────────────────────────────────────────┘

Area colour bands:

Area Colour
Foundation #6366f1 (indigo)
Data Platform #0891b2 (cyan)
Cloud Infrastructure #0f172a (slate)
Observability #16a34a (green)
Intelligence #7c3aed (violet)
Developer Platform #ea580c (orange)
Workspace #2563eb (blue)
Industry Solutions #b45309 (amber)

11.5 Ordering within consolidated PDFs

  1. Documents ordered by Area (1 → 8)
  2. Within each Area, ordered by Sector (as listed in areas.md)
  3. Within each Sector, alphabetically by module path
  4. Within each module, by document priority: deep-dive / README first, then by filename alphabetically

11.6 Handling the backlog consolidated PDF

koder-stack-backlog.pdf is internal and treated differently:

  • Include all pending/, in-progress/, and done/ tickets per module
  • Section dividers show module name + ticket count per status
  • No section divider page with icon — just a bold heading
  • Format ticket entries as: NNN — <title> (one line each) + full content below
  • Mark the PDF cover page as "INTERNAL — NOT FOR DISTRIBUTION" in red

11.7 Incremental update rule

A consolidated PDF is regenerated when any of its source documents changed since the last housekeep. Individual source PDFs that did not change are re-used from the previous run (their pages are extracted and re-embedded, not re-rendered).


9. Portrait document CSS template (WeasyPrint)

See meta/context/commands/k-housekeep.md §3.2 for the canonical CSS template (A4, 2cm margins, landscape fallback for wide tables).

The following additions apply to all generated module documents:

/* Cover page */
.cover        { page-break-after: always; display: flex; flex-direction: column;
                align-items: center; justify-content: center; min-height: 25cm;
                text-align: center; }
.cover-brand  { font-size: 10pt; color: #94a3b8; letter-spacing: .1em;
                text-transform: uppercase; margin-bottom: 4px; }
.cover-cat    { font-size: 10pt; color: #64748b; margin-bottom: 24px; }
.cover-icon   { width: 96px; height: 96px; margin-bottom: 24px; }
.cover-title  { font-size: 28pt; font-weight: 700; color: #0f172a;
                line-height: 1.15; margin-bottom: 12px; }
.cover-sub    { font-size: 14pt; color: #475569; margin-bottom: 32px; }
.cover-line   { width: 60%; border-top: 1px solid #e2e8f0; margin: 0 auto 20px; }
.cover-meta   { font-size: 9pt; color: #94a3b8; }
/* Title icon (first content page h1) */
h1.doc-title  { display: flex; align-items: center; gap: 14px;
                font-size: 21pt; color: #0f172a; }
h1.doc-title .title-icon { width: 48px; height: 48px; flex-shrink: 0; }

12. Screenshot capture for UI modules

Screenshots of module UIs are embedded in Manuals (USR and REF documents) and in Module Slide Decks. This section defines how they are captured, stored, named, and embedded.

12.1 Scope — which modules get screenshots

Screenshots apply only to modules that have a user-facing UI. The generator auto-detects by checking:

Signal Inferred platform
<module>/pubspec.yaml exists Flutter app (desktop + mobile + optionally web)
<module>/site/ exists with a running URL Web app
Both Flutter app with web companion
Neither No UI — skip screenshot capture entirely

Modules that never get screenshots: SDKs (sdk/), CLIs, infra (infra/), data engines (data/), pure backend services with no web UI.

12.2 Storage location

All screenshots live at:

<module>/docs/assets/screenshots/
├── web-desktop/        ← Playwright, 1440×900
│   ├── 01-home.png
│   ├── 02-login.png
│   └── …
├── web-tablet/         ← Playwright, 768×1024
│   └── …
├── web-mobile/         ← Playwright, 390×844 (iPhone 14 viewport)
│   └── …
├── desktop-linux/      ← Xvfb + flutter run -d linux
│   └── …
├── mobile-android/     ← AVD + flutter run / adb screencap
│   └── …
└── screenshots.yaml    ← optional: captions + navigation steps

Screenshots are committed to the repo — they are source assets, not build artefacts. The capture pipeline regenerates them on demand (not on every housekeep — see §12.6).

12.3 Naming convention

Files are named NN-<screen-slug>.png where NN is a two-digit sequence number that controls display order in the document:

01-home.png
02-login.png
03-dashboard.png
04-settings.png

Caption is derived from the filename: 02-login.png"Login", 03-user-dashboard.png"User dashboard". Override via screenshots.yaml (see §12.5).

12.4 Automated capture pipeline — per platform

12.4.1 Web (Playwright)

Requirements: playwright Python package, Chromium browser installed.

for each viewport in [desktop(1440,900), tablet(768,1024), mobile(390,844)]:
  folder = web-desktop | web-tablet | web-mobile
  1. Launch Playwright Chromium (headless)
  2. Navigate to module URL (from koder.toml → url, or inferred from site/ hostname)
  3. Wait for networkidle
  4. Capture full-page screenshot → 01-home.png
  5. If screenshots.yaml has navigation steps, execute each step and capture
  6. Save to <module>/docs/assets/screenshots/<folder>/

Mobile viewport uses device_scale_factor=2 (retina). If a step requires login, use the test account from meta/context/credentials/ (never hardcode in spec).

12.4.2 Desktop — Flutter Linux (Xvfb)

Requirements: Xvfb, scrot, flutter SDK, module must compile for Linux.

1. Start Xvfb on display :99 (1280×800×24)
2. Run: DISPLAY=:99 flutter run -d linux --release 2>/dev/null &
3. Wait 8 seconds for app to reach idle state
4. Capture: DISPLAY=:99 scrot -u <module>/docs/assets/screenshots/desktop-linux/01-home.png
5. If screenshots.yaml has steps, simulate keypresses/clicks via xdotool
6. Kill flutter process, stop Xvfb

Limitation: only captures the initial screen unless screenshots.yaml defines navigation steps using xdotool commands.

12.4.3 Mobile — Android (AVD + ADB)

Requirements: Android SDK, an AVD named koder-pixel7 (Pixel 7, API 34), flutter SDK.

1. Check if AVD is already running: adb devices
2. If not: emulator -avd koder-pixel7 -no-window -no-audio &
3. Wait for boot: adb wait-for-device && adb shell getprop sys.boot_completed == "1"
4. Run: flutter run -d emulator-XXXX --release &
5. Wait 10 seconds for app idle
6. Capture: adb exec-out screencap -p > 01-home.png
7. Crop to device frame (strip status bar if solid colour top 72px)
8. Save to <module>/docs/assets/screenshots/mobile-android/
9. Kill flutter process (emulator stays running for reuse across modules)

12.4.4 Mobile — iOS (Simulator)

Requirements: macOS host with Xcode, an iOS simulator named iPhone 15. Only runs on macOS — skip silently on Linux.

xcrun simctl boot "iPhone 15"
flutter run -d "iPhone 15" --release &
sleep 10
xcrun simctl io booted screenshot <dest>/01-home.png

12.5 screenshots.yaml — navigation steps and captions (optional)

If the file <module>/docs/assets/screenshots/screenshots.yaml exists, the capture pipeline reads it for navigation instructions and caption overrides. Format:

# screenshots.yaml
module: platform/id
url: https://id.koder.dev          # override auto-detected URL
auth:                               # use credential key from meta/context/credentials/
  key: koder-id-test-user

screens:
  - id: home
    caption: "Home — sign-in options"
    steps: []                       # just load the URL
  - id: login
    caption: "Email and password login"
    steps:
      - click: "[data-testid=email-login]"
      - wait: networkidle
  - id: dashboard
    caption: "User dashboard after authentication"
    steps:
      - fill: "[name=email]"
        value: "{{auth.email}}"
      - fill: "[name=password]"
        value: "{{auth.password}}"
      - click: "[type=submit]"
      - wait: networkidle

desktop_steps:                      # xdotool commands for Linux desktop
  - xdotool key Tab                 # move focus
  - sleep 0.5
  - xdotool key Return              # activate

mobile_steps: []                    # ADB/simctl input events (future)

If screenshots.yaml is absent, the pipeline captures only the initial landing screen (one screenshot per platform).

12.6 When to regenerate screenshots

Screenshots are not regenerated on every housekeep — they are expensive (require running apps, emulators). The generator regenerates a platform's screenshots for a module only when:

  1. --screenshots flag is passed explicitly to the generation script
  2. The module's screenshots.yaml changed since the last capture
  3. The <platform>/ subfolder is empty or missing
  4. The module's major version changed (detected from koder.toml or pubspec.yaml)

Otherwise, existing PNGs are reused as-is.

12.7 Embedding screenshots in documents

When generating a Manual or Slide Deck PDF for a module that has screenshots, the generator:

  1. Discovers all PNGs in <module>/docs/assets/screenshots/ recursively, sorted by subfolder then filename
  2. For Manuals (USR/REF): inserts a "Screenshots" section after the main content with one subsection per platform (Web · Desktop · Mobile). Each screenshot is full-width with a caption below.
  3. For Slide Decks: inserts a "UI Walkthrough" slide group — one slide per screenshot, with the caption as the slide title and the image filling 80% of the slide area.
  4. For Consolidated PDFs: screenshots are embedded in the per-module section just like in Manuals.

CSS for screenshot embedding in portrait documents:

.screenshot-section h3  { font-size: 11pt; color: #64748b; margin: 24px 0 8px;
                           text-transform: uppercase; letter-spacing: .06em; }
.screenshot-wrap        { margin: 12px 0 20px; }
.screenshot-img         { max-width: 100%; border: 1px solid #e2e8f0;
                           border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,.08); }
.screenshot-caption     { font-size: 9pt; color: #94a3b8; margin-top: 6px;
                           text-align: center; font-style: italic; }

12.8 Image size limits

Platform Max width Max file size
web-desktop 1440px 600 KB
web-tablet 768px 300 KB
web-mobile 390px (2× retina → 780px) 300 KB
desktop-linux 1280px 500 KB
mobile-android 1080px (native) 400 KB
mobile-ios 1179px (iPhone 15 native) 400 KB

If a captured PNG exceeds the limit, compress with pngquant --quality=65-85 before saving.

12.9 What the generator must NOT do

  • Invent screenshots: if capture fails for any reason, log a warning and skip — do not embed a placeholder image.
  • Capture production credentials: navigation steps that require login must use test accounts from meta/context/credentials/. Never embed real user data in screenshots.
  • Capture external services: only capture UIs served by the module itself (local dev server or the module's own production URL). Do not screenshot third-party pages.
  • Block the housekeep on capture failure: screenshot capture failure is a warning, not an error — the rest of Phase 3 continues normally.

13. Diagram visual standard (D2)

All D2 diagrams under docs/stack/diagrams/ (aerial + per-area + flows + per-module) follow the same visual language so they feel like one family of illustrations when embedded in PDFs and slide decks. This section is the source of truth — docs/stack/build/build.sh and every .d2 file must conform.

13.1 Build command

Render every .d2 file with:

d2 --theme=0 --layout=elk --pad 100 <file>.d2 <file>.svg
rsvg-convert -w 3000 <file>.svg -o <file>.png
  • --theme=0 (Neutral Default, light) — fundo branco; containers e nós trazem a cor via style.fill explícito. Não usar o theme 200 dark antigo.
  • --layout=elk (Eclipse Layout Kernel) — muito menos cruzamentos de arestas que dagre; arestas ortogonais e hierarquia mais limpa.
  • --pad 100 — respiração lateral generosa; evita que sombras sejam cortadas.
  • Rasterização em 3000px — nitidez em páginas A4 landscape de slide decks e no PDF técnico.

13.2 Shared classes (obrigatórias)

Todo .d2 com Áreas ou containers coloridos deve declarar o bloco classes abaixo no topo do arquivo, antes de qualquer nó. Isso é DRY: muda num lugar, aplica em todo canto.

classes: {
  area: {
    style: {
      border-radius: 20
      shadow: true
      stroke-width: 0
      font-size: 20
      bold: true
      font-color: "#ffffff"
    }
  }
  node: {
    style: {
      border-radius: 12
      stroke-width: 0
      font-size: 15
      font-color: "#0f172a"
      fill: "#ffffff"
      shadow: true
    }
  }
}

Containers de Área aplicam class: area; módulos/nós dentro deles aplicam class: node. Nunca repetir style.fill, style.font-color, border-radius inline em cada nó — use as classes.

13.3 Gradient fill por Área

Cada Área tem um par de cores (escuro → claro) que formam o fundo via linear-gradient. Isso dá profundidade e coesão — cores chapadas são proibidas para containers de Área.

Área Gradient fill
Foundation linear-gradient(#1e3a8a, #3b82f6)
Data Platform linear-gradient(#0f766e, #14b8a6)
Cloud Infrastructure linear-gradient(#0369a1, #0ea5e9)
Observability linear-gradient(#6d28d9, #a855f7)
Intelligence linear-gradient(#9f1239, #f43f5e)
Developer Platform linear-gradient(#a16207, #eab308)
Workspace linear-gradient(#166534, #22c55e)
Industry Solutions linear-gradient(#9a3412, #f97316)
Brand & Presence linear-gradient(#334155, #64748b)

Aplicar no container de Área:

foundation: Foundation {
  class: area
  icon: /home/koder/dev/koder/sites/foundation/icon.svg
  style.fill: "linear-gradient(#1e3a8a, #3b82f6)"
  linux: Koder Linux {class: node; icon: /home/koder/dev/koder/linux/distro/icon.svg}
  ...
}

13.4 Ícones embutidos nos nós

Cada container de Área recebe o ícone de sites/<area>/icon.svg (9 áreas têm todos). Cada nó de módulo recebe seu próprio icon.svg se existir; sem ícone, cai em pílula só-texto — não inventar placeholder. O /k-housekeep §1.6 já reporta módulos sem icon.svg como ⚠️.

  • Usar caminho absoluto (/home/koder/dev/koder/...) — D2 v0.7 não aceita paths relativos para icon:.
  • O ícone aparece no canto do container/nó (top-left) automaticamente.

13.5 Estilo das arestas

Default para todas as arestas:

style: {stroke: "#94a3b8"; stroke-width: 2}

Arestas com label ("depends on", "authenticates", etc.) recebem estilo reforçado:

style: {stroke: "#475569"; stroke-width: 3; font-size: 14; font-color: "#334155"; bold: true}

13.6 Título do diagrama

Toda .d2 começa com um título markdown no topo. Para aerial e áreas:

title: |md
  # Koder Stack
  ## Aerial view — 9 areas · 50+ modules
| {near: top-center; shape: text; style.font-size: 36; style.bold: true; style.font-color: "#0f172a"}

Fontes menores (26/22pt) para flows individuais. Cor sempre #0f172a (slate-900) para contraste em fundo branco.

13.7 Categorias de diagrama

Categoria Path Estrutura Classes usadas
Aerial diagrams/aerial.d2 9 containers de Área, um por cor; módulos como pílulas; arestas inter-Área area + node
Area diagrams/areas/<area>.d2 1 container da Área com todos os módulos; arestas internas area + node
Flow diagrams/flows/<flow>.d2 Actors + etapas numeradas; sem containers de Área node (cor neutra ou cor da Área do actor)
Module diagrams/modules/<module>.d2 Coupling deep-dive; nós = dependências externas node

Para flows, actors de Áreas diferentes recebem style.fill individual com a cor sólida base da sua Área (não gradient — actors são pontos, não blocos). Exemplo: ator foundation/idstyle.fill: "#1e3a8a"; style.font-color: white.

13.8 Proibições

  • ❌ Tema dark (--theme=200, --theme=201) — todos os diagramas são light. Inversão automática para dark mode dos PDFs fica para iteração futura.
  • ❌ Layout dagre — sempre elk.
  • style.fill chapado em containers de Área — sempre linear-gradient.
  • ❌ Repetir estilo inline — sempre via class.
  • icon.svg de placeholder ou genérico — só ícone real do módulo ou ausente.
  • stroke-width > 15 (limite do D2) ou < 1.
  • ❌ Fontes externas via --font-regular enquanto não houver Inter/JetBrains instalados no host de build — ficar no Source Sans Pro default.

13.9 Regeneração

docs/stack/build/build.sh re-renderiza todos os .d2 para .svg + .png a cada execução do /k-housekeep §1.10. Os arquivos .svg e .png sob diagrams/ são build artefacts gitignored (docs/stack/.gitignore) — só o .d2 fonte entra no git. Após clone, rodar ./build/build.sh gera os assets localmente.

13.10 Pilot de referência

O diagrama canônico do estilo é docs/stack/diagrams/aerial.d2. Ao criar ou refatorar outro .d2, abrir o aerial como template e espelhar:

  1. Bloco classes no topo
  2. Título markdown com font-size 36/26/22
  3. Containers com class: area + icon: + style.fill: "linear-gradient(...)"
  4. Nós com class: node + icon: quando existir
  5. Arestas com estilo neutro padrão (§13.5)

Referências