|
| 1 | +--- |
| 2 | +name: dot-add-flow |
| 3 | +description: Add a complete new flow to `dot` — a `flows/<name>.go` file with its full question graph, a `Generators` resolver, registration in `flows/registry.go`, every new generator the flow needs (delegating to `dot-add-generator`), every new question (delegating to `dot-add-question`), and a full set of `tools/test-flow/testdata/` fixtures. Trigger when the user says "add a flow", "new flow", "ajoute un flow", "create a scaffold for X", or describes a brand-new wizard that doesn't fit any existing flow. |
| 4 | +source: local-git-analysis |
| 5 | +version: 1.0.0 |
| 6 | +--- |
| 7 | + |
| 8 | +# dot — Add a Flow |
| 9 | + |
| 10 | +A **flow** is a top-level wizard entry point (`dot scaffold <flow-id>`). It is a `FlowDef` declared in `flows/<name>.go`, registered in `flows/registry.go`, and composed of: |
| 11 | + |
| 12 | +- A question graph (root → … → `confirmGenerate`) |
| 13 | +- A `Generators` resolver that maps the populated `ProjectSpec` to ordered `Invocation`s |
| 14 | +- Generators that may be reused from existing ones or freshly added |
| 15 | +- Test fixtures in `tools/test-flow/testdata/` |
| 16 | + |
| 17 | +This skill orchestrates the full flow lifecycle, deferring to `dot-add-question` and `dot-add-generator` for sub-tasks. |
| 18 | + |
| 19 | +--- |
| 20 | + |
| 21 | +## HARD RULES (Iron Law — never skip) |
| 22 | + |
| 23 | +1. **Two announcements, then act.** Before any code change: |
| 24 | + - **Phase A — Generator plan**: list every new or modified generator (per `dot-add-generator` rules), including version bumps and doc updates. |
| 25 | + - **Phase B — Question plan**: list every question in the new flow with `ID_`, type, label, options, edges, and what each answer triggers in the resolver (per `dot-add-question` rules). |
| 26 | + Then **ASK** for confirmation. Do not start writing files until the user says proceed. |
| 27 | +2. **Unique, stable, kebab-case flow ID.** Used in `dot scaffold <id>` and referenced by every fixture. Never collide with existing IDs (`init`, `fullstack`, `microservices`, `plugin-template`, …) — check `flows/registry.go`. |
| 28 | +3. **Every question ID is unique across the whole flow.** No collision with itself, no collision with existing flows if generators are shared. |
| 29 | +4. **Reuse before you create.** Walk the existing `generators/` list; reuse anything that matches. Only add a new generator when no existing one fits. Each new generator goes through the full `dot-add-generator` workflow. |
| 30 | +5. **The resolver must cover every reachable answer combination.** No silent gaps. If the user can answer X, some `Invocation` must result from it (or you must explicitly comment that X is intentionally a no-op). |
| 31 | +6. **Fixtures cover every distinct branch.** At minimum: one happy-path fixture; one fixture per major branching choice (auth on/off, db on/off, each architecture, each formatter, …). Use the timestamped naming convention `YYYYMMDDhhMM_<flow>_<variant>.json`. |
| 32 | +7. **Tests across all layers**: |
| 33 | + - Unit tests for non-trivial pure logic in any new generator (`<name>_test.go`) |
| 34 | + - Manifest `Validators` for structural checks (file presence, JSON keys) |
| 35 | + - `TestCommands` that build / typecheck / unit-test / lint the generated project |
| 36 | + - For DB generators: `drizzle-kit generate` (or equivalent) as a post-gen command |
| 37 | + - End-to-end via `make test-flows` |
| 38 | +8. **Bump version + update doc** on every modified existing generator. |
| 39 | +9. **Formatters depend on `*`** (run last). Apply to any formatter introduced by the new flow. |
| 40 | + |
| 41 | +--- |
| 42 | + |
| 43 | +## Step-by-step workflow |
| 44 | + |
| 45 | +### 1. Understand the target |
| 46 | + |
| 47 | +Capture from the user (or ASK): |
| 48 | + |
| 49 | +- **Flow ID** (kebab-case), **Title**, **Description** |
| 50 | +- **Stack** (Go, TypeScript, Rust, multi-app monorepo, …) |
| 51 | +- **Choice points** (architecture, ORM, auth, lint/format, …) |
| 52 | +- **Loops** if multi-app |
| 53 | + |
| 54 | +### 2. Inventory existing assets |
| 55 | + |
| 56 | +- Read `generators/` directory listing — note which generators map to each choice point |
| 57 | +- Read `flows/init.go` (and other flows) for established patterns (constants, terminal `confirmGenerate`, validation helpers like `nonEmpty`) |
| 58 | +- Read `internal/cli/registry.go` to know what is wired |
| 59 | + |
| 60 | +### 3. Phase A — Generator plan (MANDATORY announcement) |
| 61 | + |
| 62 | +Output: |
| 63 | + |
| 64 | +``` |
| 65 | +Flow `<flow-id>` — Generator plan |
| 66 | +
|
| 67 | +Reuse (no changes): |
| 68 | +- <name> — used when <answer> == <value> |
| 69 | +- … |
| 70 | +
|
| 71 | +Modify (existing generators that must change for this flow): |
| 72 | +- generators/<name>/ — <what changes, why> — version <old> → <new> |
| 73 | +- docs/contributor/generators/<name>.md — sections to update |
| 74 | +- … |
| 75 | +
|
| 76 | +Add (brand-new generators — each via dot-add-generator): |
| 77 | +- <name> — purpose, depends on <list>, conflicts with <list>, writes <files>, post-gen <cmds>, test cmds <cmds> |
| 78 | +- … |
| 79 | +
|
| 80 | +Resolver outline (order matters — deps will be expanded by topo sort): |
| 81 | +1. base_project |
| 82 | +2. <…> |
| 83 | +N. <formatter — DependsOn: ["*"]> |
| 84 | +``` |
| 85 | + |
| 86 | +Stop and ASK. |
| 87 | + |
| 88 | +### 4. Phase B — Question plan (MANDATORY announcement) |
| 89 | + |
| 90 | +Output: |
| 91 | + |
| 92 | +``` |
| 93 | +Flow `<flow-id>` — Question plan |
| 94 | +
|
| 95 | +Graph (root → … → confirmGenerate): |
| 96 | + <ID_> (<type>) — "<label>" |
| 97 | + └── <option/then/else> → <next ID_ or End> |
| 98 | + … |
| 99 | +
|
| 100 | +Per-answer impact on resolver: |
| 101 | +- <ID_> == <value> → add <generators> |
| 102 | +- <ID_> == <value> → add <generators> |
| 103 | +- … |
| 104 | +
|
| 105 | +Fixtures to add (under tools/test-flow/testdata/): |
| 106 | +- <timestamp>_<flow-id>_<variant>.json — covers <branch> |
| 107 | +- … |
| 108 | +
|
| 109 | +Proceed? |
| 110 | +``` |
| 111 | + |
| 112 | +Stop and ASK. |
| 113 | + |
| 114 | +### 5. Create / modify generators |
| 115 | + |
| 116 | +For each item in the Add list, run the `dot-add-generator` skill end-to-end (package layout, manifest, embedded `files/`, registration, doc, tests). For each item in the Modify list, apply the change with version bump + doc update. |
| 117 | + |
| 118 | +Do this **before** writing the flow file — the flow's resolver references generators by name, and `make build` will fail if they don't exist yet. |
| 119 | + |
| 120 | +### 6. Write `flows/<flow-id>.go` |
| 121 | + |
| 122 | +Mirror the structure of `flows/init.go`: |
| 123 | + |
| 124 | +```go |
| 125 | +package flows |
| 126 | + |
| 127 | +import ( |
| 128 | + "github.com/version14/dot/internal/flow" |
| 129 | + "github.com/version14/dot/internal/spec" |
| 130 | +) |
| 131 | + |
| 132 | +// constants for stable answer values reused across the resolver |
| 133 | +const FOO_BAR = "foo-bar" |
| 134 | + |
| 135 | +// <FlowID>Flow is the … flow. <one-paragraph description, including |
| 136 | +// the note that question IDs are stable for dot update.> |
| 137 | +func <FlowID>Flow() *FlowDef { |
| 138 | + confirmGenerate := &flow.ConfirmQuestion{ |
| 139 | + QuestionBase: flow.QuestionBase{ID_: "confirm-generate"}, |
| 140 | + Label: "Generate the project now?", |
| 141 | + Default: true, |
| 142 | + Then: &flow.Next{End: true}, |
| 143 | + Else: &flow.Next{End: true}, |
| 144 | + } |
| 145 | + |
| 146 | + // … declare questions bottom-up … |
| 147 | + |
| 148 | + return &FlowDef{ |
| 149 | + ID: "<flow-id>", |
| 150 | + Title: "<Title>", |
| 151 | + Description: "<Description>", |
| 152 | + Root: <rootQuestion>, |
| 153 | + Generators: resolve<FlowID>Generators, |
| 154 | + } |
| 155 | +} |
| 156 | + |
| 157 | +func resolve<FlowID>Generators(s *spec.ProjectSpec) []Invocation { |
| 158 | + if s == nil { return nil } |
| 159 | + out := []Invocation{{Name: "base_project"}} |
| 160 | + // … read s.Answers, append Invocations … |
| 161 | + return out |
| 162 | +} |
| 163 | +``` |
| 164 | + |
| 165 | +For loops use `LoopQuestion` + emit one `Invocation` per loop frame with `LoopStack`. See `flows/microservices.go` pattern (referenced in `docs/contributor/authoring-flows.md`). |
| 166 | + |
| 167 | +### 7. Register the flow |
| 168 | + |
| 169 | +Edit `flows/registry.go` — add `_ = r.Register(<FlowID>Flow())` in the `Default()` builder. The flow then appears in `dot flows` and `dot scaffold`. |
| 170 | + |
| 171 | +### 8. Fixtures (full coverage) |
| 172 | + |
| 173 | +Under `tools/test-flow/testdata/`, create one JSON file per distinct branch. Use timestamped filenames sorted lexicographically. Required fields (see `0_template.json`): |
| 174 | + |
| 175 | +```json |
| 176 | +{ |
| 177 | + "name": "<flow-id>_<variant>", |
| 178 | + "flow_id": "<flow-id>", |
| 179 | + "answers": { /* every required key, in the order the user would answer */ }, |
| 180 | + "expected_visited": [ /* every ID_ visited, in order */ ], |
| 181 | + "skip_post_commands": false, |
| 182 | + "skip_test_commands": false |
| 183 | +} |
| 184 | +``` |
| 185 | + |
| 186 | +Minimum coverage matrix: |
| 187 | + |
| 188 | +- Happy path (every default, simplest options) |
| 189 | +- Each architecture / ORM / auth / formatter variant the flow exposes |
| 190 | +- Loop variants (0 iterations if allowed, 1, N>1) |
| 191 | +- Boolean confirm questions: both `true` and `false` covered somewhere |
| 192 | + |
| 193 | +### 9. Verify |
| 194 | + |
| 195 | +``` |
| 196 | +make build |
| 197 | +make validate |
| 198 | +make test-flows |
| 199 | +``` |
| 200 | + |
| 201 | +Iterate until green. If a fixture's `expected_visited` mismatches the flow, fix the flow or the fixture deliberately — never blanket-edit fixtures to silence failures. |
| 202 | + |
| 203 | +### 10. Documentation |
| 204 | + |
| 205 | +- Add a row to `README.md`'s "Built-in flows" table |
| 206 | +- Add a row to `docs/contributor/authoring-flows.md`'s "Built-in flows" table |
| 207 | +- If you added new generators, ensure `docs/contributor/generators/<name>.md` exists and `docs/README.md` lists each one |
| 208 | + |
| 209 | +### 11. Commit |
| 210 | + |
| 211 | +Conventional Commits, multiple commits: |
| 212 | + |
| 213 | +- `feat(generators): add <name>` per new generator (with its doc) |
| 214 | +- `refactor(generators/<name>): <change>` per modified generator (with version bump) |
| 215 | +- `feat(flow): add <flow-id> flow` for the flow file + registration |
| 216 | +- `test(test-flow): add fixtures for <flow-id>` for the fixtures |
| 217 | +- `docs(flows): describe <flow-id> flow` if separate doc work was needed |
| 218 | + |
| 219 | +Do **not** auto-commit — wait for explicit user instruction. |
| 220 | + |
| 221 | +--- |
| 222 | + |
| 223 | +## Worked example skeleton (Go backend microservice flow) |
| 224 | + |
| 225 | +Phase A — Generator plan: |
| 226 | + |
| 227 | +``` |
| 228 | +Reuse: base_project, postgres_docker_compose, postgres_env_example |
| 229 | +Modify: (none) |
| 230 | +Add: |
| 231 | +- go_module_base — go.mod + main.go + Dockerfile + healthcheck — DependsOn: base_project |
| 232 | +- go_chi_router — Chi router + middleware + /health — DependsOn: go_module_base |
| 233 | +- go_postgres_repo — pgx pool + repo skeleton — DependsOn: go_module_base, postgres_docker_compose |
| 234 | +- go_test_setup — go test scaffolding + testcontainers helper — DependsOn: go_module_base |
| 235 | +``` |
| 236 | + |
| 237 | +Phase B — Question plan: |
| 238 | + |
| 239 | +``` |
| 240 | +project_name (Text) → module_path (Text) → router_choice (Option: chi / stdlib) |
| 241 | + → enable_db (Confirm) |
| 242 | + Then → db_type (Option: postgres) → confirm-generate |
| 243 | + Else → confirm-generate |
| 244 | +``` |
| 245 | + |
| 246 | +Then resolver pulls `go_module_base` always, `go_chi_router` when `chi`, plus postgres + `go_postgres_repo` when `enable_db && db_type == "postgres"`. |
| 247 | + |
| 248 | +Fixtures: |
| 249 | + |
| 250 | +- `..._go_chi_no_db.json` |
| 251 | +- `..._go_stdlib_no_db.json` |
| 252 | +- `..._go_chi_postgres.json` |
| 253 | + |
| 254 | +--- |
| 255 | + |
| 256 | +## Common mistakes (do not make) |
| 257 | + |
| 258 | +- Skipping Phase A or Phase B announcements |
| 259 | +- Adding a flow that depends on a generator that does not yet exist (build will fail) |
| 260 | +- Forgetting to register the flow in `flows/registry.go` |
| 261 | +- Inadequate fixture coverage — every branching choice must be exercised by some fixture |
| 262 | +- Renaming a question `ID_` after first commit (breaks `dot update`) |
| 263 | +- Modifying an existing generator without bumping its version and updating its doc |
| 264 | +- Putting a formatter ahead of architecture/feature generators in the resolver (instead set `DependsOn: ["*"]` on the formatter) |
| 265 | + |
| 266 | +--- |
| 267 | + |
| 268 | +## Skill composition |
| 269 | + |
| 270 | +This skill **delegates**: |
| 271 | + |
| 272 | +- For each new generator → invoke / follow `dot-add-generator` end-to-end |
| 273 | +- For each question → follow `dot-add-question` discipline (announcement, fixture impact, version bumps) |
| 274 | + |
| 275 | +It only owns: the flow file, the registry entry, the resolver, and the cross-cutting Phase A / Phase B announcements that make the whole thing reviewable in one pass. |
0 commit comments