@naswerks/engineering-loop 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +15 -0
- package/.claude-plugin/plugin.json +8 -0
- package/CHANGELOG.md +32 -0
- package/LICENSE +21 -0
- package/README.md +78 -0
- package/bin/verify-staged.mjs +247 -0
- package/package.json +35 -0
- package/references/docs-workflow.md +417 -0
- package/references/engineering-loop.md +298 -0
- package/skills/docs-audit-feature/SKILL.md +88 -0
- package/skills/docs-audit-full/SKILL.md +54 -0
- package/skills/docs-backlog/SKILL.md +41 -0
- package/skills/docs-process/SKILL.md +146 -0
- package/skills/docs-status/SKILL.md +47 -0
- package/skills/docs-write/SKILL.md +43 -0
- package/skills/init/SKILL.md +163 -0
- package/skills/init/scripts/doctor.mjs +176 -0
- package/skills/spec-child/SKILL.md +149 -0
- package/skills/spec-ignite/SKILL.md +277 -0
- package/skills/spec-parent/SKILL.md +634 -0
- package/skills/spec-pipeline/SKILL.md +453 -0
- package/skills/spec-retro/SKILL.md +398 -0
- package/skills/spec-review/SKILL.md +266 -0
- package/skills/spec-seat/SKILL.md +512 -0
- package/skills/spec-witness/SKILL.md +222 -0
- package/templates/claude-md-stanza.md +13 -0
- package/templates/docs/_meta/doc-index.md +90 -0
- package/templates/docs/infrastructure/background-work.md +53 -0
- package/templates/docs/infrastructure/realtime-events.md +54 -0
- package/templates/docs/patterns/backend-patterns.md +96 -0
- package/templates/docs/patterns/codegen.md +69 -0
- package/templates/docs/patterns/frontend-patterns.md +92 -0
- package/templates/docs/patterns/state-management.md +73 -0
- package/templates/docs/patterns/testing.md +103 -0
- package/templates/docs/patterns/ui-style-guide.md +76 -0
- package/templates/docs/patterns/vertical-slice-anatomy.md +61 -0
- package/templates/docs/readme-archive.md +9 -0
- package/templates/docs/readme-features.md +7 -0
- package/templates/docs/readme-guides.md +7 -0
- package/templates/docs/readme-infrastructure.md +7 -0
- package/templates/docs/readme-patterns.md +9 -0
- package/templates/docs/readme-research.md +9 -0
- package/templates/docs/readme-working.md +9 -0
- package/templates/settings-pin.json +10 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Frontend Patterns
|
|
2
|
+
|
|
3
|
+
> Rules and conventions for the client side of this repository. Last verified {today}.
|
|
4
|
+
<!-- meta: type=pattern; status=draft; verified={today}; lineage=0 -->
|
|
5
|
+
<!-- naswerks-loop: draft; scanned={files} -->
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
<!-- init: scan — a frontend framework config (angular.json, next.config.*, vite.config.*, nuxt.config.*,
|
|
12
|
+
svelte.config.*, a React/Vue dependency), the app roots.
|
|
13
|
+
fill — two to four sentences: what the client side is, the framework, and the claim "every client
|
|
14
|
+
feature follows these conventions; read this before writing any client code."
|
|
15
|
+
absent — "No frontend detected — fill this in when a client-side stack appears. This file exists so
|
|
16
|
+
the reading floor resolves; a seat with a frontend role has nothing to read here yet." -->
|
|
17
|
+
|
|
18
|
+
## Stack
|
|
19
|
+
|
|
20
|
+
<!-- init: scan — framework + version, state library, data-fetching client, realtime client, styling
|
|
21
|
+
library, auth library — from the manifest with versions.
|
|
22
|
+
fill — one bullet per item: name, version, role.
|
|
23
|
+
absent — "No frontend dependencies detected — fill this in." -->
|
|
24
|
+
|
|
25
|
+
## Architecture rules
|
|
26
|
+
|
|
27
|
+
<!-- init: scan — tsconfig strictness, lint config rules, a framework's recommended conventions the repo
|
|
28
|
+
has pinned (standalone components, a change-detection strategy, hooks rules).
|
|
29
|
+
fill — the table `Rule | Pattern | Legacy (never use)` — the modern form the repo uses beside the
|
|
30
|
+
form it forbids, each row from a real config or an existing component.
|
|
31
|
+
absent — "No architecture rules found written down — fill this in: the component/module model, the
|
|
32
|
+
change-detection or rendering model, the DI or hook conventions, each with its forbidden legacy." -->
|
|
33
|
+
|
|
34
|
+
| Rule | Pattern | Legacy (never use) |
|
|
35
|
+
|------|---------|-------------------|
|
|
36
|
+
|
|
37
|
+
## Component architecture
|
|
38
|
+
|
|
39
|
+
<!-- init: scan — one feature folder in the client app; the kinds of component it holds.
|
|
40
|
+
fill — the kinds table (`Type | Store access | Location | Role`) and an ASCII tree of one REAL feature.
|
|
41
|
+
absent — "No component folders detected — fill this in: the component kinds and where each lives." -->
|
|
42
|
+
|
|
43
|
+
## Component files
|
|
44
|
+
|
|
45
|
+
<!-- init: scan — how existing components lay out their template, styles and spec (inline vs separate
|
|
46
|
+
files; the file naming).
|
|
47
|
+
fill — the rule as this repo practises it (e.g. "template and styles are separate files beside the
|
|
48
|
+
component, named {component}.component.{html,css}; a spec sits beside them"), citing two existing
|
|
49
|
+
components. This is the rule a coordinator enforces at every seat's commit.
|
|
50
|
+
absent — "No component-file convention detected — fill this in: whether templates and styles are
|
|
51
|
+
inline or separate files, and how they are named." -->
|
|
52
|
+
|
|
53
|
+
## State
|
|
54
|
+
|
|
55
|
+
<!-- init: scan — the state library, one store folder.
|
|
56
|
+
fill — the store convention in one paragraph and a pointer to `patterns/state-management.md` when
|
|
57
|
+
that doc exists (Snapshot — the authority is state-management.md).
|
|
58
|
+
absent — "No state library detected — fill this in: how client state is held and shared." -->
|
|
59
|
+
|
|
60
|
+
## Styling
|
|
61
|
+
|
|
62
|
+
<!-- init: scan — the styling library, a tokens/theme file, a global stylesheet.
|
|
63
|
+
fill — the approach in three bullets (utility-first / component CSS / tokens), the one rule for
|
|
64
|
+
component-scoped CSS, and a pointer to `patterns/ui-style-guide.md` when it exists.
|
|
65
|
+
absent — "No styling library detected — fill this in: how components are styled and themed." -->
|
|
66
|
+
|
|
67
|
+
## Realtime
|
|
68
|
+
|
|
69
|
+
<!-- init: scan — a realtime client (signalr, socket.io, ws, sse, pusher, ably).
|
|
70
|
+
fill — one paragraph: how server events reach the client and the poke/refetch rule; a pointer to
|
|
71
|
+
`infrastructure/realtime-events.md` when it exists.
|
|
72
|
+
absent — "No realtime client detected — the client reads on navigation and on user action only;
|
|
73
|
+
fill this in when a realtime channel appears." -->
|
|
74
|
+
|
|
75
|
+
## Codegen pointer
|
|
76
|
+
|
|
77
|
+
<!-- init: scan — a generated/ folder inside the client app, a codegen config.
|
|
78
|
+
fill — "Never hand-write or edit files in `{generated folder}` — they are produced by {tool} and
|
|
79
|
+
overwritten on the next run. Everything else is the authority of `patterns/codegen.md`."
|
|
80
|
+
absent — "No generated client code detected — fill this in when a codegen pipeline appears." -->
|
|
81
|
+
|
|
82
|
+
## Key Files
|
|
83
|
+
|
|
84
|
+
| File | Purpose |
|
|
85
|
+
|------|---------|
|
|
86
|
+
<!-- init: scan — the app config/composition root, the router, the shared components folder, the global
|
|
87
|
+
stylesheet, the constants file.
|
|
88
|
+
fill — one row per file, verbatim path.
|
|
89
|
+
absent — "| (none detected) | fill this in: the app config, the routes, the shared components |" -->
|
|
90
|
+
|
|
91
|
+
## Lineage
|
|
92
|
+
- **Related** — [vertical-slice-anatomy](vertical-slice-anatomy.md) · [testing](testing.md) · [codegen](codegen.md) · [backend-patterns](backend-patterns.md)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# State Management
|
|
2
|
+
|
|
3
|
+
> The store convention for the client side of this repository: the files per store, how a store is
|
|
4
|
+
> registered, how a component consumes it. Last verified {today}.
|
|
5
|
+
<!-- meta: type=pattern; status=draft; verified={today}; lineage=0 -->
|
|
6
|
+
<!-- naswerks-loop: draft; scanned={files} -->
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Structure
|
|
11
|
+
|
|
12
|
+
<!-- init: scan — the state library (from the manifest) and ONE existing store folder.
|
|
13
|
+
fill — the library and version, then an ASCII tree of one REAL store with a comment per file, and the
|
|
14
|
+
rule for sub-stores if the repo has them.
|
|
15
|
+
absent — this doc is only drafted when a state library is found; if you are reading a draft with this
|
|
16
|
+
line, the scan found the library but no store folder: "No store folder detected — fill this in: the
|
|
17
|
+
files a store is made of." -->
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
{feature}/store/
|
|
21
|
+
...
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Actions / events
|
|
25
|
+
|
|
26
|
+
<!-- init: fill — how actions are declared and named (the naming convention read off the existing store,
|
|
27
|
+
e.g. `[Feature] Verb Noun`), with a real example.
|
|
28
|
+
absent — "No action convention detected — fill this in." -->
|
|
29
|
+
|
|
30
|
+
## Model
|
|
31
|
+
|
|
32
|
+
<!-- init: fill — where the state types come from (derived from generated types? hand-written?), with a
|
|
33
|
+
real example.
|
|
34
|
+
absent — "No model convention detected — fill this in." -->
|
|
35
|
+
|
|
36
|
+
## Data access
|
|
37
|
+
|
|
38
|
+
<!-- init: fill — the file that talks to the server on the store's behalf, and the rule that components
|
|
39
|
+
never call it directly, with a real example.
|
|
40
|
+
absent — "No data-access convention detected — fill this in." -->
|
|
41
|
+
|
|
42
|
+
## State class / reducer
|
|
43
|
+
|
|
44
|
+
<!-- init: fill — selectors, handlers, error handling, the realtime-event handlers if any, with a real
|
|
45
|
+
example. -->
|
|
46
|
+
|
|
47
|
+
## Registration
|
|
48
|
+
|
|
49
|
+
<!-- init: scan — where stores are registered (app config, root module, a provider list).
|
|
50
|
+
fill — the exact file and the one line to add.
|
|
51
|
+
absent — "No registration point detected — fill this in." -->
|
|
52
|
+
|
|
53
|
+
## Component consumption
|
|
54
|
+
|
|
55
|
+
<!-- init: fill — how a component reads (a selector, a signal, a hook) and writes (dispatch), with a real
|
|
56
|
+
example. -->
|
|
57
|
+
|
|
58
|
+
## Rules
|
|
59
|
+
|
|
60
|
+
<!-- init: scan — lint rules or CONTRIBUTING notes about state.
|
|
61
|
+
fill — bold-lead imperative bullets, each citing its source when written down; the loop supplies one:
|
|
62
|
+
"**Keep high-frequency streams OUT of the store** — a byte/token stream belongs in a plain service the
|
|
63
|
+
component subscribes to; only low-frequency control events go through the store."
|
|
64
|
+
absent — the one loop-supplied bullet, then "- No further store rules found written down — fill this
|
|
65
|
+
in." -->
|
|
66
|
+
|
|
67
|
+
## Key Files
|
|
68
|
+
|
|
69
|
+
| File | Purpose |
|
|
70
|
+
|------|---------|
|
|
71
|
+
|
|
72
|
+
## Lineage
|
|
73
|
+
- **Related** — [frontend-patterns](frontend-patterns.md) · [vertical-slice-anatomy](vertical-slice-anatomy.md)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Testing Patterns
|
|
2
|
+
|
|
3
|
+
> How to write and run tests in this repository — every lane. Last verified {today}.
|
|
4
|
+
<!-- meta: type=pattern; status=draft; verified={today}; lineage=0 -->
|
|
5
|
+
<!-- naswerks-loop: draft; scanned={files} -->
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
<!-- init: scan — the test frameworks in the dependency manifests and the CI jobs that run tests.
|
|
12
|
+
fill — two to four sentences: which kinds of test carry the weight here (unit / integration / e2e),
|
|
13
|
+
against what (real database, real HTTP, fakes), ending with the claim "every feature follows these
|
|
14
|
+
conventions; read this before writing any test."
|
|
15
|
+
absent — "No test framework detected — fill this in: what kinds of test this repository relies on,
|
|
16
|
+
and against what boundaries." -->
|
|
17
|
+
|
|
18
|
+
## Stack
|
|
19
|
+
|
|
20
|
+
<!-- init: scan — every test-related dependency with its version (vitest, jest, mocha, xunit, nunit,
|
|
21
|
+
pytest, go test, cargo test, playwright, cypress, testcontainers, wiremock, msw …).
|
|
22
|
+
fill — one bullet per tool: name, version, what it is for.
|
|
23
|
+
absent — "No test framework detected — fill this in: the runner, the assertion library, the fakes." -->
|
|
24
|
+
|
|
25
|
+
## Running tests
|
|
26
|
+
|
|
27
|
+
<!-- init: scan — package.json scripts, Makefile/justfile targets, *.sln/*.csproj test projects, CI
|
|
28
|
+
workflow steps; the app roots (one lane per app or project).
|
|
29
|
+
fill — ONE fenced block per lane: the exact command, the working directory it runs from, and a
|
|
30
|
+
comment saying what a green run prints (the summary line). Commands verbatim from the scan, never
|
|
31
|
+
paraphrased.
|
|
32
|
+
absent — "No test command detected — fill this in: the exact invocation per lane, from the
|
|
33
|
+
directory it runs in, and what a green run prints." -->
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
# lane: {name} — from {directory}
|
|
37
|
+
{the exact command} # green prints: {the summary line}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## The run protocol
|
|
41
|
+
|
|
42
|
+
Follow this before trusting any red OR green:
|
|
43
|
+
|
|
44
|
+
- **Suites run SERIALLY, never concurrently** — concurrent runners flake, and a failure seen only in a
|
|
45
|
+
concurrent run is rerun standalone before it is investigated.
|
|
46
|
+
- **Capture the full runner output to a UTF-8 file and search failure names** — a "last N lines" filter
|
|
47
|
+
destroys the names; a run whose output file is empty proved nothing.
|
|
48
|
+
- **Read the summary block, never the exit code alone** — a run that printed no totals ran nothing,
|
|
49
|
+
whatever its exit code said; a green exit is a claim, not a receipt. Implausible speed is a failure
|
|
50
|
+
signal.
|
|
51
|
+
- **Disclose every red run WITH its rerun** — never present a flake as clean.
|
|
52
|
+
- **A number without its invocation is not a receipt** — quote what ran, from where, and the scope.
|
|
53
|
+
|
|
54
|
+
<!-- init: scan — FLAKY-TESTS.md, a "known flaky" list in CONTRIBUTING.md, CI retry configuration.
|
|
55
|
+
fill — a "Known flaky tests" list by name, with the reason and what to do (rerun once; stop on two).
|
|
56
|
+
absent — leave the five bullets above as they are; add nothing. -->
|
|
57
|
+
|
|
58
|
+
## What to test where
|
|
59
|
+
|
|
60
|
+
<!-- init: scan — the folder layout (Features/, apps/*, packages/*), existing test folders and their
|
|
61
|
+
naming, one existing test file per kind as the example.
|
|
62
|
+
fill — one bullet per slice kind ("a sync endpoint: …", "a repository: …", "a store: …", "a pure
|
|
63
|
+
service: …"), each naming an existing test file as its reference. Plus the test-naming convention
|
|
64
|
+
read off the existing tests (plain-English behavioural sentences, or the repo's own).
|
|
65
|
+
absent — "No test folders detected — fill this in: what each kind of code is tested with, and one
|
|
66
|
+
reference test per kind." -->
|
|
67
|
+
|
|
68
|
+
## Controls — a pin must be able to fail
|
|
69
|
+
|
|
70
|
+
A test that cannot go red is a green light with a test's name on it. For every probe, pin or scanner:
|
|
71
|
+
|
|
72
|
+
- **Name its positive control** — the case that MUST go red — and state what would make it fail.
|
|
73
|
+
- **The pair must disagree.** One variable changes between the subject and its control; if the same
|
|
74
|
+
input produces the same verdict on both sides, you have one observation wearing two names.
|
|
75
|
+
- **Prove it once:** break the thing on purpose, watch the control go red, fix it, watch it go green,
|
|
76
|
+
and quote both runs. A control asserted is a control assumed.
|
|
77
|
+
- **Pin the PROPERTY, not the wording.** Assert the behaviour in the assertion's own message; source
|
|
78
|
+
any literal you must name from the producer's own constant, and assert that constant is non-empty.
|
|
79
|
+
|
|
80
|
+
<!-- init: scan — an existing test that pairs a subject with its own control (a "CONTROL" or "inverted"
|
|
81
|
+
case), if one exists.
|
|
82
|
+
fill — name that test as the shape to copy.
|
|
83
|
+
absent — leave the four bullets; add "No paired control found in the existing tests — fill this in:
|
|
84
|
+
the first pin that carries its own control becomes the reference here." -->
|
|
85
|
+
|
|
86
|
+
## Coverage
|
|
87
|
+
|
|
88
|
+
<!-- init: scan — coverage configuration (a floor file, a threshold in the runner config, a CI gate).
|
|
89
|
+
fill — the floor, the command that measures it, and the gate that enforces it.
|
|
90
|
+
absent — "No coverage gate detected — fill this in: whether coverage is measured, the floor, and
|
|
91
|
+
the gate." -->
|
|
92
|
+
|
|
93
|
+
## Key Files
|
|
94
|
+
|
|
95
|
+
| File | Purpose |
|
|
96
|
+
|------|---------|
|
|
97
|
+
<!-- init: scan — every file the sections above named (runner configs, shared fixtures, CI workflows,
|
|
98
|
+
the flaky list).
|
|
99
|
+
fill — one row per file, verbatim path.
|
|
100
|
+
absent — "| (none detected) | fill this in: the runner config, the shared fixtures, the CI workflow |" -->
|
|
101
|
+
|
|
102
|
+
## Lineage
|
|
103
|
+
- **Related** — [backend-patterns](backend-patterns.md) · [frontend-patterns](frontend-patterns.md) · [vertical-slice-anatomy](vertical-slice-anatomy.md)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# UI Style Guide
|
|
2
|
+
|
|
3
|
+
> Which class or component to reach for, for which job, and the composition rules that keep screens
|
|
4
|
+
> consistent — plus the design tokens and how to consume them. Last verified {today}.
|
|
5
|
+
<!-- meta: type=pattern; status=draft; verified={today}; lineage=0 -->
|
|
6
|
+
<!-- naswerks-loop: draft; scanned={files} -->
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## The mental model
|
|
11
|
+
|
|
12
|
+
Every element on screen falls into one of these roles. Name the role before you pick a class.
|
|
13
|
+
|
|
14
|
+
| Role | What it is | Visual weight | Example |
|
|
15
|
+
|------|-----------|---------------|---------|
|
|
16
|
+
| **Primary action** | the thing you WANT the user to do | highest — filled, coloured | Create, Send, Save |
|
|
17
|
+
| **Secondary action** | useful but not the main goal | medium — outlined | View, Details, Refresh |
|
|
18
|
+
| **Passive action** | navigation away, undo, dismiss | lowest — ghost / minimal | Back, Cancel, Close |
|
|
19
|
+
| **Destructive action** | permanent data loss | high, danger-coloured | Delete, Remove |
|
|
20
|
+
| **User content** | text the user wrote or data they own | emphasised | names, values, messages |
|
|
21
|
+
| **System content** | app-generated text, metadata | neutral, de-emphasised | helper text, timestamps |
|
|
22
|
+
| **Status indicator** | communicates state without action | colour-coded by meaning | badges, alerts |
|
|
23
|
+
| **Navigation** | moves between pages | subtle until hovered | breadcrumbs, tabs, sidebar |
|
|
24
|
+
| **Metadata** | labels, counts, ids | minimal, neutral outline | pagination, "Showing X of Y" |
|
|
25
|
+
|
|
26
|
+
## Action hierarchy
|
|
27
|
+
|
|
28
|
+
**One primary action per context** (page header, card, modal, form). Everything else is secondary or
|
|
29
|
+
passive.
|
|
30
|
+
|
|
31
|
+
<!-- init: scan — the UI library (tailwind, daisyui, mui, chakra, bootstrap, shadcn …) and two existing
|
|
32
|
+
pages/components (a header with actions, a form footer).
|
|
33
|
+
fill — the button decision tree in this repo's class names, then "Current patterns": a fenced
|
|
34
|
+
snippet each for a page header, card actions, a modal footer, a form bottom, copied from real files.
|
|
35
|
+
absent — "No UI library detected — fill this in: the class or component for each role above." -->
|
|
36
|
+
|
|
37
|
+
## Content roles
|
|
38
|
+
|
|
39
|
+
<!-- init: fill — three tables (`Element | Style | Why`) for user content, system content, and status
|
|
40
|
+
indicators (positive / warning / error / info / neutral / category), in this repo's classes.
|
|
41
|
+
absent — "No content-role classes detected — fill this in." -->
|
|
42
|
+
|
|
43
|
+
## Page layout and page states
|
|
44
|
+
|
|
45
|
+
Every data-driven page handles four states: **loading**, **error**, **empty**, **content**.
|
|
46
|
+
|
|
47
|
+
<!-- init: scan — a shared page-header / empty-state / loading / error component, if any.
|
|
48
|
+
fill — the standard page skeleton (an ASCII box), the shared components to use for the four states,
|
|
49
|
+
and the state-switch idiom the repo uses.
|
|
50
|
+
absent — "No shared page components detected — fill this in: the page skeleton and the four-state
|
|
51
|
+
components." -->
|
|
52
|
+
|
|
53
|
+
## Tokens
|
|
54
|
+
|
|
55
|
+
<!-- init: scan — a tokens/theme file, a global stylesheet, the UI library's token variables.
|
|
56
|
+
fill — a table `Token | CSS variable | Purpose | When to use` for brand, base and status tokens,
|
|
57
|
+
then the ONE consumption rule for component CSS (use `var(--…)` tokens, never a literal colour; how to
|
|
58
|
+
express opacity), and the dead forms to grep for if the library moved majors.
|
|
59
|
+
absent — "No design tokens detected — fill this in: the colour and spacing tokens and how component
|
|
60
|
+
CSS consumes them." -->
|
|
61
|
+
|
|
62
|
+
## Forms
|
|
63
|
+
|
|
64
|
+
<!-- init: fill — the field pattern, input states, validation display, in this repo's classes.
|
|
65
|
+
absent — "No form convention detected — fill this in." -->
|
|
66
|
+
|
|
67
|
+
## Quick reference: element to style
|
|
68
|
+
|
|
69
|
+
<!-- init: fill — a two-column table `Element | Style` compiled from the sections above.
|
|
70
|
+
absent — "Compile this table once the sections above are filled." -->
|
|
71
|
+
|
|
72
|
+
| Element | Style |
|
|
73
|
+
|---------|-------|
|
|
74
|
+
|
|
75
|
+
## Lineage
|
|
76
|
+
- **Related** — [frontend-patterns](frontend-patterns.md)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Vertical Slice Anatomy
|
|
2
|
+
|
|
3
|
+
> Where to place each piece when building a feature in this repository. Last verified {today}.
|
|
4
|
+
<!-- meta: type=pattern; status=draft; verified={today}; lineage=0 -->
|
|
5
|
+
<!-- naswerks-loop: draft; scanned={files} -->
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Feature structure
|
|
10
|
+
|
|
11
|
+
<!-- init: scan — the folder layout two deep for every stack (Features/, src/app/, apps/*, packages/*,
|
|
12
|
+
cmd/, internal/, lib/), and ONE existing feature per stack.
|
|
13
|
+
fill — one ASCII tree per stack showing a REAL feature as it exists, side by side when there are
|
|
14
|
+
two, with a comment per folder saying what goes there; then one sentence per stack on what lives
|
|
15
|
+
OUTSIDE a feature (shared infrastructure, cross-cutting stores).
|
|
16
|
+
absent — "No feature layout detected — fill this in: where a feature's files go, per stack, as a
|
|
17
|
+
tree copied from a real one." -->
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
{stack A} {stack B, if any}
|
|
21
|
+
{root}/{Feature}/ {root}/{feature}/
|
|
22
|
+
... ...
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## The kinds of file, and their roles
|
|
26
|
+
|
|
27
|
+
<!-- init: scan — the kinds the trees above show (endpoint / model / query / service; page / component /
|
|
28
|
+
store; command / handler).
|
|
29
|
+
fill — a table `Kind | Role | Where | Owns` with one row per kind.
|
|
30
|
+
absent — "No kinds detected — fill this in: each kind of file a feature holds, and what it owns." -->
|
|
31
|
+
|
|
32
|
+
| Kind | Role | Where | Owns |
|
|
33
|
+
|------|------|-------|------|
|
|
34
|
+
|
|
35
|
+
## Checklist: new feature
|
|
36
|
+
|
|
37
|
+
<!-- init: scan — the trees above, the registration points (composition root, router, module list), the
|
|
38
|
+
test conventions in patterns/testing.md § What to test where.
|
|
39
|
+
fill — an ordered `- [ ]` checklist per stack: create X in {path} (one line on what it must extend
|
|
40
|
+
or implement), register it in {file}, add the route/handler in {file}, add the tests the testing doc
|
|
41
|
+
names for each kind, run the build. Each item is a real path.
|
|
42
|
+
absent — "- [ ] No feature layout detected — fill this in: the ordered steps that add a feature,
|
|
43
|
+
each naming its file." -->
|
|
44
|
+
|
|
45
|
+
### {stack A}
|
|
46
|
+
|
|
47
|
+
- [ ]
|
|
48
|
+
|
|
49
|
+
### {stack B}
|
|
50
|
+
|
|
51
|
+
- [ ]
|
|
52
|
+
|
|
53
|
+
## Gotchas
|
|
54
|
+
|
|
55
|
+
<!-- init: scan — CONTRIBUTING.md, CLAUDE.md, AGENTS.md, lint rules that fire on layout (import
|
|
56
|
+
boundaries, dependency-cruiser, ArchUnit-style rules).
|
|
57
|
+
fill — one `### Gotcha:` per written-down layout rule, citing its source file.
|
|
58
|
+
absent — "No layout gotchas written down yet — fill this in the first time one bites." -->
|
|
59
|
+
|
|
60
|
+
## Lineage
|
|
61
|
+
- **Related** — [backend-patterns](backend-patterns.md) · [frontend-patterns](frontend-patterns.md) · [testing](testing.md)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# archive/
|
|
2
|
+
|
|
3
|
+
Completed or abandoned efforts, grouped into topic folders. Write-once: frozen history, never edited — a
|
|
4
|
+
stale reference in an archived doc is the record of what was believed at the time. A spec-driven effort
|
|
5
|
+
archives in the split shape (`project-status.md` at the root, `specs/`, `implementation/`,
|
|
6
|
+
`sessions/`); a small effort is flat. `archive/audit/` is the one exception to topic grouping: audit
|
|
7
|
+
reports sit beside the living docs they audit, and the cross-cutting health report sits at its root.
|
|
8
|
+
|
|
9
|
+
A README in this folder is never a queue entry.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# features/
|
|
2
|
+
|
|
3
|
+
What exists — one doc per feature. Descriptive: born from `docs-process` after code ships, verified
|
|
4
|
+
against the code, and audited by `docs-audit-feature` (folder mode also flags code with no doc). The
|
|
5
|
+
folder IS the feature inventory; there is no separate catalogue.
|
|
6
|
+
|
|
7
|
+
A README in this folder is never a queue entry.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# guides/
|
|
2
|
+
|
|
3
|
+
How to ADD a new thing — step-by-step walkthroughs (a new service, a new app, a new worker). Prescriptive:
|
|
4
|
+
the guide is the decided way, and code conforms to it. Patched by `docs-process` when a session changes
|
|
5
|
+
the way; audited by `docs-audit-feature` for whether the code still follows it.
|
|
6
|
+
|
|
7
|
+
A README in this folder is never a queue entry.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# infrastructure/
|
|
2
|
+
|
|
3
|
+
What runs under the hood — the technologies and plumbing. Descriptive: the code is truth, and these docs
|
|
4
|
+
are verified against source (`docs-audit-feature` fixes the doc to match the code). Born from
|
|
5
|
+
`docs-process` after something ships, or drafted by `init` from a scan and marked `status=draft`.
|
|
6
|
+
|
|
7
|
+
A README in this folder is never a queue entry.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# patterns/
|
|
2
|
+
|
|
3
|
+
Conventions to FOLLOW when writing code. Prescriptive: truth is by decision, so a mismatch between a
|
|
4
|
+
pattern doc and the code is usually a code problem to flag, not a doc to rewrite. Every seat reads the
|
|
5
|
+
floor (`vertical-slice-anatomy`, `backend-patterns`, `frontend-patterns`, `testing`, `codegen`)
|
|
6
|
+
before it writes a line; a doc marked `status=draft` was scanned by `init`, not decided — promote it as
|
|
7
|
+
you confirm each section.
|
|
8
|
+
|
|
9
|
+
A README in this folder is never a queue entry.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# research/
|
|
2
|
+
|
|
3
|
+
The running tab of ideas not yet built. `docs-backlog` creates a research doc here; a spec pipeline lives
|
|
4
|
+
in `research/{topic}/` (an ignition brief, an umbrella, one numbered spec per session, the tracker, the
|
|
5
|
+
live-checks). A research doc stays here through the build — however many sessions and working docs that
|
|
6
|
+
takes — and is archived WITH its working docs by `docs-process` when the effort finishes. The folder is
|
|
7
|
+
the queue; nothing here is done.
|
|
8
|
+
|
|
9
|
+
A README in this folder is never a queue entry.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# working/
|
|
2
|
+
|
|
3
|
+
Per-session handoff docs. `docs-write` finishes one at the end of every build session and leaves it here;
|
|
4
|
+
one effort may chain several (each `Builds on` the last, all with the same `Source:`). They leave only
|
|
5
|
+
through `docs-process`, which patches the living docs from their **Living Docs to Update** checklists and
|
|
6
|
+
then files the whole effort into `archive/{topic}/`. The folder is a shared queue: other efforts' docs may
|
|
7
|
+
sit beside yours, and membership is never inferred from the folder.
|
|
8
|
+
|
|
9
|
+
A README in this folder is never a queue entry.
|