making the mess clean plans added
This commit is contained in:
@@ -0,0 +1,162 @@
|
|||||||
|
# The Clarify Chain — a plan to clean up Balinyaar's documentation
|
||||||
|
|
||||||
|
**Status:** planned, not started · **Written:** 2026-07-29 · **Baseline commit:** `96b57eb`
|
||||||
|
|
||||||
|
This folder is a **plan**, not documentation. It describes eight phases that take the repo from its
|
||||||
|
current state — 260 markdown files, ~10 competing rule sources, five unreconciled backlogs, and a
|
||||||
|
contract layer that stopped tracking the code on 2026-07-13 — to a single navigable `docs/` tree that
|
||||||
|
tells the truth.
|
||||||
|
|
||||||
|
When the chain finishes, **this folder moves to `archive/`**. It is temporary by design.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Why this exists (the diagnosis)
|
||||||
|
|
||||||
|
Measured against the working tree at `96b57eb`:
|
||||||
|
|
||||||
|
| Finding | Evidence |
|
||||||
|
| --- | --- |
|
||||||
|
| **3.0 MB / 199 files of build history in [`dev/`](../../dev/)** reads as instruction, not record | [`dev/phases/`](../../dev/phases/) last touched 2026-06-28 (already-executed prompts) sits beside [`dev/post-phase/`](../../dev/post-phase/) touched 2026-07-28 (live plan). Nothing marks the difference. |
|
||||||
|
| **Rules live in ~10 places** | root [CLAUDE.md](../../CLAUDE.md) · [client/CLAUDE.md](../../client/CLAUDE.md) **161 KB** · [server/CLAUDE.md](../../server/CLAUDE.md) 75 KB · [server/CONVENTIONS.md](../../server/CONVENTIONS.md) · [client/messages/STYLE.md](../../client/messages/STYLE.md) · [.claude/skills/frontend-designer/SKILL.md](../../.claude/skills/frontend-designer/SKILL.md) · [dev/phases/_shared/](../../dev/phases/_shared/) ×4 · [dev/contracts/conventions/](../../dev/contracts/conventions/) ×2 · 3× `AGENTS.md` · [.githooks/README.md](../../.githooks/README.md) |
|
||||||
|
| **Loading `client/CLAUDE.md` costs ~40k tokens** on any client edit | 161 KB, of which lines 103–421 are a project-structure listing and lines 421–1100 are explanatory reference |
|
||||||
|
| **Remaining work is split across 5 ledgers** | 67 REQs in a 1,115-line append-only file · **18 hardening items, none ticked** · per-phase "Follow-ups" buried in 50+ reports · backend deferrals-with-pull-triggers · [product/notes/open-questions.md](../../product/notes/open-questions.md) · two raw feedback notes in [dev/manual-testing/](../../dev/manual-testing/) |
|
||||||
|
| **Contracts drifted from code** | [`dev/contracts/`](../../dev/contracts/) frozen 2026-07-13; `server/src` moved through 2026-07-28. OpenAPI snapshot is from 07-13; a second stale copy sits at [temp/swagger.json](../../temp/swagger.json) (07-06). |
|
||||||
|
| **18 files still instruct you to use `dotnet user-secrets`** — removed in `5885280` | includes [manual-testing-plan.md](../../dev/post-phase/manual-testing-plan.md), the closest thing to a test guide |
|
||||||
|
| **No single "what's implemented + how to test it"** | knowledge split across manual-testing-plan, [RUNBOOK.md](../../dev/post-phase/refinement/RUNBOOK.md), `product/business/`, and 18 contract files |
|
||||||
|
| **The client↔server dependency is implicit** | envelope shape, casing, idempotency, cookies/refresh, CORS, `NEXT_PUBLIC_API_URL`, 3 containers + Caddy + remote SQL + the OTP bot — described nowhere as one thing |
|
||||||
|
|
||||||
|
The code itself is **not** the mess. 83 client routes, 22 service domains, 125 client tests; 56
|
||||||
|
controllers, 199 handlers, 24 migrations. The problem is that nothing tells you which parts of that
|
||||||
|
are real, which are mocked, and which are described by a document written three weeks ago.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Decisions this plan implements
|
||||||
|
|
||||||
|
Agreed 2026-07-29, before any file was written:
|
||||||
|
|
||||||
|
| Decision | Choice |
|
||||||
|
| --- | --- |
|
||||||
|
| Doc home | **New top-level `docs/` tree.** `product/` stays as-is; `dev/` becomes `archive/`; CLAUDE.md files shrink to hard rules + pointers |
|
||||||
|
| `dev/` history | **Distill, then archive in-repo.** Every live fact extracted first; raw files moved under `archive/` with a do-not-obey banner |
|
||||||
|
| Rules | **Tiered.** CLAUDE.md keeps only non-negotiables (~200 lines); everything explanatory becomes reference read on demand |
|
||||||
|
| Verification | **Verify the load-bearing claims.** Flow status, the 18 hardening items, REQ dispositions, bring-up steps, OpenAPI — checked against code, not copied |
|
||||||
|
| Flow docs | **One file per flow, indexed** by a status table |
|
||||||
|
| Backlog | **One triaged file, new `BL-###` ids**, each carrying its origin id |
|
||||||
|
| `product/` | **Untouched.** An implementation overlay in `docs/status/` maps business areas → build state |
|
||||||
|
| Language | **English throughout** |
|
||||||
|
| Skills | **Small set, reality-checked.** Rewrite `frontend-designer`; add a backend-feature and a flow-testing skill |
|
||||||
|
| Roadmap | **Record + propose** a sequenced next chain; ordering is a proposal you can overrule |
|
||||||
|
| Anti-drift | **Lightweight guardrails.** A documentation convention, `Last verified:` stamps, a pre-commit warning |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Target tree
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/
|
||||||
|
README.md the one entry point — a map, nothing else
|
||||||
|
rules/ what must never be broken
|
||||||
|
index.md
|
||||||
|
documentation.md the anti-drift convention
|
||||||
|
shared/ naming, money & types, api conventions, git
|
||||||
|
client/ structure, theme, forms, i18n, services, auth, testing
|
||||||
|
server/ structure, cqrs, persistence, identity, conventions
|
||||||
|
integration/ the client<->server dependency, in one place
|
||||||
|
index.md the seam, as a single picture
|
||||||
|
api-contract.md envelope, casing, pagination, errors, idempotency
|
||||||
|
domains/ per-domain contracts (refreshed from dev/contracts)
|
||||||
|
openapi/swagger.v1.json regenerated, dated
|
||||||
|
config-matrix.md every env var / setting, both projects + docker
|
||||||
|
topology.md 3 containers + Caddy + remote SQL + OTP bot
|
||||||
|
flows/ what is implemented and how to test it
|
||||||
|
index.md status table of every flow
|
||||||
|
testing-setup.md bring-up, accounts, seeded world, reset
|
||||||
|
<flow>.md one per flow
|
||||||
|
status/ where the project actually is
|
||||||
|
index.md
|
||||||
|
implemented.md product/business area -> build state overlay
|
||||||
|
backlog.md BL-### triaged, every open item
|
||||||
|
backlog-closed.md
|
||||||
|
decisions.md distilled ADR log from the phase chain
|
||||||
|
roadmap/ where it goes next
|
||||||
|
index.md next-up.md deferred.md tech-debt.md pre-launch.md
|
||||||
|
_plan/ this folder (moves to archive/ when done)
|
||||||
|
|
||||||
|
archive/
|
||||||
|
README.md "historical record. Do NOT treat as instructions."
|
||||||
|
build-chain/ was dev/phases + dev/shared-working-context
|
||||||
|
post-phase/ was dev/post-phase
|
||||||
|
manual-testing/ was dev/manual-testing (screenshots kept)
|
||||||
|
|
||||||
|
product/ unchanged
|
||||||
|
CLAUDE.md slim, points into docs/
|
||||||
|
DEPLOY.md stays at root — the deploy *procedure*; topology lives in docs/integration/
|
||||||
|
```
|
||||||
|
|
||||||
|
**The rule that keeps these apart:** `product/` = what the business is. `docs/` = what we built and how
|
||||||
|
we work. `archive/` = how we got here. A file belongs in exactly one.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## The eight phases
|
||||||
|
|
||||||
|
| # | Phase | Depends on | Rough size | Output |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| 0 | [Inventory & scaffold](phase-0-inventory-and-scaffold.md) | — | 1 session | `docs/` skeleton + a disposition for all 260 files + fresh OpenAPI |
|
||||||
|
| 1 | [Rules consolidation](phase-1-rules-consolidation.md) | 0 | 1–2 sessions | `docs/rules/` + slim CLAUDE.md files |
|
||||||
|
| 2 | [Integration & dependency](phase-2-integration.md) | 0 | 1 session | `docs/integration/` |
|
||||||
|
| 3 | [Flow atlas (verified)](phase-3-flow-atlas.md) | 0, 2 | 2–4 sessions | `docs/flows/` — the biggest phase |
|
||||||
|
| 4 | [Backlog reconciliation](phase-4-backlog.md) | 0, 3 | 1–2 sessions | `docs/status/` |
|
||||||
|
| 5 | [Roadmap & tech requirements](phase-5-roadmap.md) | 4 | 1 session | `docs/roadmap/` |
|
||||||
|
| 6 | [Archive & prune](phase-6-archive.md) | 1–5 | 1 session | `archive/`, `dev/` gone, links fixed |
|
||||||
|
| 7 | [Skills & guardrails](phase-7-skills-and-guardrails.md) | 1, 3 | 1 session | `.claude/skills/` rewritten + anti-drift hooks |
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─ 1 rules ──────────────┐
|
||||||
|
0 ──────┼─ 2 integration ─ 3 flows ─ 4 backlog ─ 5 roadmap ─┼─ 6 archive
|
||||||
|
└────────────────────────┴──── 7 skills ────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
Phases 1 and 2 can run in parallel with each other after 0. Everything else is a chain.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How to run a phase
|
||||||
|
|
||||||
|
Point a fresh agent session at one phase file:
|
||||||
|
|
||||||
|
> Execute `docs/_plan/phase-2-integration.md`.
|
||||||
|
|
||||||
|
Each phase file states its own inputs, outputs, steps, verification, and definition of done. It ends
|
||||||
|
by ticking its own row in the progress table below and writing a short handoff note at the bottom of
|
||||||
|
its own file. **Do not run two phases in one session** — the point of this exercise is that context
|
||||||
|
stays small.
|
||||||
|
|
||||||
|
## Non-negotiables for every phase
|
||||||
|
|
||||||
|
1. **Nothing is deleted before it is distilled.** Phase 6 is the only phase that removes files, and it
|
||||||
|
may only remove files that Phase 0's inventory marked as *archived* or *extracted*.
|
||||||
|
2. **Verify, don't copy.** If a claim is load-bearing (a flow works, an item is closed, a command
|
||||||
|
boots the app), check it against the code or run it. If you cannot verify it, write it with an
|
||||||
|
explicit `UNVERIFIED:` prefix rather than asserting it.
|
||||||
|
3. **Every status/flow doc carries a `> Last verified: <date> against <commit>` header line.**
|
||||||
|
4. **Write short.** The failure mode this chain fixes is length. A reference doc over ~400 lines
|
||||||
|
should be split. A phase that produces a 30 KB file has misunderstood the assignment.
|
||||||
|
5. **Record contradictions, don't silently pick.** When two docs disagree, check the code, write the
|
||||||
|
truth, and log the contradiction in `docs/status/decisions.md`.
|
||||||
|
6. **Update this README's progress table** in the same change that finishes a phase.
|
||||||
|
|
||||||
|
## Progress
|
||||||
|
|
||||||
|
| Phase | Status | Finished | Notes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 0 Inventory & scaffold | not started | | |
|
||||||
|
| 1 Rules consolidation | not started | | |
|
||||||
|
| 2 Integration & dependency | not started | | |
|
||||||
|
| 3 Flow atlas | not started | | |
|
||||||
|
| 4 Backlog reconciliation | not started | | |
|
||||||
|
| 5 Roadmap | not started | | |
|
||||||
|
| 6 Archive & prune | not started | | |
|
||||||
|
| 7 Skills & guardrails | not started | | |
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
# Phase 0 — Inventory & scaffold
|
||||||
|
|
||||||
|
**Depends on:** nothing · **Blocks:** every other phase · **Size:** one session
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Before anything is moved, merged, or deleted, produce two things:
|
||||||
|
|
||||||
|
1. **A disposition for every one of the ~260 markdown files in the repo** — so that "summarize
|
||||||
|
without losing data" is a checkable claim rather than a hope.
|
||||||
|
2. **The empty `docs/` skeleton** with a real entry point, so later phases have somewhere to write.
|
||||||
|
|
||||||
|
Plus one piece of housekeeping every later phase needs: a **fresh OpenAPI snapshot**, because the
|
||||||
|
committed one is 16 days behind the server code.
|
||||||
|
|
||||||
|
This phase writes almost no prose. It is a survey.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- The whole repo. Specifically: `dev/` (199 files), `product/` (48), root (4), `client/` (5),
|
||||||
|
`server/` (6), `telegram-otp-bot/` (2), `.claude/skills/` (1), `.githooks/` (1).
|
||||||
|
- [`../README.md`](README.md) — the target tree and the decisions.
|
||||||
|
|
||||||
|
## Outputs
|
||||||
|
|
||||||
|
| File | What it is |
|
||||||
|
| --- | --- |
|
||||||
|
| `docs/_plan/inventory.md` | The disposition table — every markdown file, one row |
|
||||||
|
| `docs/README.md` | The single entry point: a map of `docs/`, `product/`, `archive/` and what belongs where |
|
||||||
|
| `docs/rules/index.md` `docs/integration/index.md` `docs/flows/index.md` `docs/status/index.md` `docs/roadmap/index.md` | Stub indexes, each with a one-line purpose and a "populated by phase N" note |
|
||||||
|
| `docs/integration/openapi/swagger.v1.json` | Regenerated from the running server |
|
||||||
|
| `docs/_plan/open-contradictions.md` | Running list of doc-vs-doc and doc-vs-code conflicts spotted during the survey — later phases resolve these |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
### 1. Build the inventory
|
||||||
|
|
||||||
|
Walk every `.md` file (exclude `node_modules`, `bin`, `obj`, `.git`). For each, record:
|
||||||
|
|
||||||
|
| Column | Meaning |
|
||||||
|
| --- | --- |
|
||||||
|
| `path` | repo-relative |
|
||||||
|
| `bytes` | size |
|
||||||
|
| `last commit` | `git log -1 --format=%ad --date=short -- <path>` |
|
||||||
|
| `kind` | `rule` · `reference` · `contract` · `plan` · `report` · `history` · `business` · `ops` · `feedback` |
|
||||||
|
| `disposition` | `keep-as-is` · `move` · `distill` · `merge-into` · `archive` · `delete` |
|
||||||
|
| `target` | where its content ends up (a `docs/…` path, or `archive/…`) |
|
||||||
|
| `owner phase` | which phase (1–7) handles it |
|
||||||
|
| `live facts?` | `yes` / `no` — does it contain anything not yet captured elsewhere? |
|
||||||
|
|
||||||
|
Rules for assigning disposition:
|
||||||
|
|
||||||
|
- **`dev/phases/backend/*` and `dev/phases/frontend/*`** (32 files, ~1 MB): these are *prompts that
|
||||||
|
were already executed*. Disposition `archive`. But scan each for **decisions and constraints stated
|
||||||
|
in the prompt that are not visible in the code** — those are `live facts: yes` and go to Phase 1
|
||||||
|
(if a rule) or Phase 4 (`decisions.md`).
|
||||||
|
- **`dev/shared-working-context/reports/*` (50 files)**: `archive`, but every "Follow-ups for later
|
||||||
|
phases" / "Deferred" / "Known gap" section is a live fact for **Phase 4**. Extract the section
|
||||||
|
headings now; Phase 4 reads them in detail.
|
||||||
|
- **`dev/shared-working-context/*/STATUS.md`** (86 KB combined): `distill` → Phase 4 (`decisions.md`
|
||||||
|
+ `implemented.md`), then `archive`.
|
||||||
|
- **`dev/shared-working-context/frontend/requests/for-backend.md`** (67 REQs): `distill` → Phase 4.
|
||||||
|
- **`dev/post-phase/hardening/issues.md`** (18 open items): `distill` → Phase 4, **with
|
||||||
|
re-verification** — the UI and refinement chains ran after this file was written and some items are
|
||||||
|
probably already fixed.
|
||||||
|
- **`dev/contracts/**`**: `move` → `docs/integration/` — Phase 2 owns it, and refreshes it against code.
|
||||||
|
- **`dev/post-phase/manual-testing-plan.md`** + **`refinement/RUNBOOK.md`**: `distill` → Phase 3
|
||||||
|
(`docs/flows/testing-setup.md` + the per-flow files). Both are stale on secrets handling.
|
||||||
|
- **`dev/manual-testing/iteration-*/`**: `distill` → Phase 4 (unfinished items) then `archive`
|
||||||
|
(**keep the PNG screenshots** — they are the only visual record of the pre-overhaul UI).
|
||||||
|
- **`product/**`**: `keep-as-is`, every one. Not this chain's business.
|
||||||
|
- **`client/CLAUDE.md`, `server/CLAUDE.md`, `server/CONVENTIONS.md`, `client/messages/STYLE.md`,
|
||||||
|
`dev/phases/_shared/*`, `dev/contracts/conventions/*`, `.claude/skills/*/SKILL.md`**: `distill` →
|
||||||
|
Phase 1.
|
||||||
|
- **`DEPLOY.md`**: `keep-as-is` at root (it is the deploy *procedure* and it is current) — but Phase 2
|
||||||
|
fixes its stale `user-secrets` reference and Phase 2's `topology.md` links to it.
|
||||||
|
- **`Prompt.md`** (0 bytes): `delete`.
|
||||||
|
- **`temp/swagger.json`** (stale duplicate): `delete` — Phase 2 replaces it.
|
||||||
|
- **`client/graphify-out/GRAPH_REPORT.md`, `server/graphify-out/GRAPH_REPORT.md`**: generated tool
|
||||||
|
output. Decide `keep-as-is` if the tool is still used, else `delete`; check `.gitignore` first.
|
||||||
|
|
||||||
|
### 2. Log contradictions as you go
|
||||||
|
|
||||||
|
Write `docs/_plan/open-contradictions.md` with one row per conflict: *claim A (file:line) vs claim B
|
||||||
|
(file:line or code:line) — unresolved*. Seed it with the ones already known:
|
||||||
|
|
||||||
|
- **`user-secrets` is required** (18 files) vs **`user-secrets` was removed and the store isn't read**
|
||||||
|
(root [CLAUDE.md](../../CLAUDE.md) §6, commit `5885280`).
|
||||||
|
- **`dev/contracts/` describes the API** (frozen 2026-07-13) vs **`server/src`** (through 2026-07-28).
|
||||||
|
- **Design language in [.claude/skills/frontend-designer/SKILL.md](../../.claude/skills/frontend-designer/SKILL.md) §§1–7**
|
||||||
|
vs **[client/CLAUDE.md](../../client/CLAUDE.md) "Theme System" / "Anti-patterns"** — overlapping, possibly divergent.
|
||||||
|
- **Both** vs **the reality after iterations 1–2** (mobile-scoped shell, bottom nav, react-hook-form,
|
||||||
|
new icon set) — the skill predates that overhaul.
|
||||||
|
- **18 hardening items open** (2026-07-16) vs **UI phases 0–13 and the deploy commits that ran after**.
|
||||||
|
|
||||||
|
Do **not** resolve these here. Phase 0 only finds them.
|
||||||
|
|
||||||
|
### 3. Regenerate the OpenAPI snapshot
|
||||||
|
|
||||||
|
Boot the server and capture the live swagger document:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd server && dotnet run --project src/API/Baya.Web.Api/Baya.Web.Api.csproj
|
||||||
|
# then, from another shell:
|
||||||
|
curl -sk https://localhost:5002/swagger/v1/swagger.json -o docs/integration/openapi/swagger.v1.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Record in the file's sibling `README.md`: the date, the commit, and the endpoint count. Diff the
|
||||||
|
endpoint *paths* against the old `dev/contracts/openapi/swagger.v1.json` and write the added/removed
|
||||||
|
list into `docs/_plan/open-contradictions.md` — Phase 2 uses it as its worklist.
|
||||||
|
|
||||||
|
If the server will not boot (config, DB reachability), **stop and report** rather than guessing. A
|
||||||
|
stale snapshot is what caused half of this mess.
|
||||||
|
|
||||||
|
### 4. Scaffold `docs/`
|
||||||
|
|
||||||
|
Create the directories and stub index files from the target tree in [`README.md`](README.md). Each
|
||||||
|
stub is ~10 lines: what lives here, which phase fills it, and a `> Populated by phase N — not yet
|
||||||
|
written` banner. `docs/README.md` is the only one with real content: the map, and the
|
||||||
|
`product/` vs `docs/` vs `archive/` rule.
|
||||||
|
|
||||||
|
Do **not** create `archive/` yet — Phase 6 does that, once there is something safe to put in it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- [ ] `docs/_plan/inventory.md` has a row for every `.md` file the survey walked; the count matches
|
||||||
|
`find . -name "*.md" -not -path "./node_modules/*" … | wc -l` (~260 at baseline).
|
||||||
|
- [ ] No row has an empty `disposition` or `owner phase`.
|
||||||
|
- [ ] Every row with `live facts: yes` names the phase that will extract them.
|
||||||
|
- [ ] `docs/integration/openapi/swagger.v1.json` exists and its endpoint count is recorded.
|
||||||
|
- [ ] Every stub index exists and says which phase fills it.
|
||||||
|
- [ ] Nothing outside `docs/` was modified, except deleting `Prompt.md` and `temp/swagger.json`.
|
||||||
|
|
||||||
|
## Definition of done
|
||||||
|
|
||||||
|
You can answer, for any markdown file in the repo, "where does this end up and who handles it?"
|
||||||
|
without re-reading the file.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
_(filled in by the agent that runs this phase — file counts, surprises, anything that changes a later
|
||||||
|
phase's scope)_
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
# Phase 1 — Rules consolidation
|
||||||
|
|
||||||
|
**Depends on:** Phase 0 · **Can run in parallel with:** Phase 2 · **Size:** 1–2 sessions
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Collapse ~10 rule sources into one tiered system, and cut the cost of editing client code from
|
||||||
|
~40k tokens to ~5k.
|
||||||
|
|
||||||
|
**The tiering rule:**
|
||||||
|
|
||||||
|
| Tier | Where | What goes in it | Budget |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| **Hard rules** | `client/CLAUDE.md`, `server/CLAUDE.md`, root `CLAUDE.md` | Constraints whose violation breaks the build, the gate, or a business invariant. Stated imperatively, no explanation. | ~200 lines each |
|
||||||
|
| **Reference** | `docs/rules/{shared,client,server}/*.md` | The *how* and the *why*. Read on demand when working on that area. | ~200–400 lines per file |
|
||||||
|
| **Procedure** | `.claude/skills/` | Step-by-step playbooks for recurring tasks. **Phase 7** owns these. | — |
|
||||||
|
|
||||||
|
A rule that only matters when you are already editing theme code is **reference**, not a hard rule.
|
||||||
|
A rule like "never change `Seams:FieldEncryption:Key`" is a hard rule — it belongs inline.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
Read these in full; they are the raw material:
|
||||||
|
|
||||||
|
| Source | Size | Contains |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| [client/CLAUDE.md](../../client/CLAUDE.md) | 161 KB | 22 sections; lines 103–421 are a structure listing, 421+ is reference |
|
||||||
|
| [server/CLAUDE.md](../../server/CLAUDE.md) | 75 KB | 11 sections; lines 89–603 are the project map |
|
||||||
|
| [server/CONVENTIONS.md](../../server/CONVENTIONS.md) | 27 KB | naming, layering, CQRS shape |
|
||||||
|
| [client/messages/STYLE.md](../../client/messages/STYLE.md) | 8 KB | Persian copy rules (enforced by `lint:copy`) |
|
||||||
|
| [.claude/skills/frontend-designer/SKILL.md](../../.claude/skills/frontend-designer/SKILL.md) | 21 KB | brand, tokens, typography, component library, layout, icons |
|
||||||
|
| [dev/phases/_shared/agent-operating-rules.md](../../dev/phases/_shared/agent-operating-rules.md) | 13 KB | how agents were told to work |
|
||||||
|
| [dev/phases/_shared/definition-of-done.md](../../dev/phases/_shared/definition-of-done.md) | 3 KB | the gate |
|
||||||
|
| [dev/phases/_shared/backend-conventions-checklist.md](../../dev/phases/_shared/backend-conventions-checklist.md) | 4 KB | |
|
||||||
|
| [dev/phases/_shared/frontend-conventions-checklist.md](../../dev/phases/_shared/frontend-conventions-checklist.md) | 3 KB | |
|
||||||
|
| [dev/contracts/conventions/api-conventions.md](../../dev/contracts/conventions/api-conventions.md) | 3 KB | → **Phase 2 owns this**; read for cross-check only |
|
||||||
|
| [dev/contracts/conventions/money-and-types.md](../../dev/contracts/conventions/money-and-types.md) | 3 KB | → **Phase 2 owns this**; read for cross-check only |
|
||||||
|
| root [CLAUDE.md](../../CLAUDE.md) · 3× `AGENTS.md` · [.githooks/README.md](../../.githooks/README.md) | small | working agreements, pointers, the pre-commit hook |
|
||||||
|
|
||||||
|
Plus: `docs/_plan/inventory.md` and `docs/_plan/open-contradictions.md` from Phase 0.
|
||||||
|
|
||||||
|
## Outputs
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/rules/
|
||||||
|
index.md what's here, and the tiering rule restated
|
||||||
|
documentation.md the anti-drift convention (Phase 7 adds the hook that enforces it)
|
||||||
|
shared/
|
||||||
|
naming.md Baya* vs balinyaar-client, @/* alias, file/dir conventions
|
||||||
|
git-and-gates.md branch, commit, pre-commit hook, what "done" means per project
|
||||||
|
code-quality.md no dead code, comment the why, no starter scaffolding
|
||||||
|
client/
|
||||||
|
structure.md the route/folder map (regenerated from reality, not copied)
|
||||||
|
theme.md tokens, palette, dark mode, RTL, fonts
|
||||||
|
components.md the App* library, when to reach for it vs raw MUI
|
||||||
|
forms.md react-hook-form (post-iteration-2), validation, field components
|
||||||
|
i18n.md next-intl v4, en/fa parity, STYLE.md copy rules folded in
|
||||||
|
services.md services/{domain} pattern, fetch layer, envelope, query keys
|
||||||
|
auth.md cookies, session state, refresh, RoleGuard, middleware/PUBLIC_PATHS
|
||||||
|
testing.md what is tested, how, the 125 existing tests
|
||||||
|
server/
|
||||||
|
structure.md the project map (condensed from server/CLAUDE.md lines 89-603)
|
||||||
|
cqrs.md how a feature is shaped: command/query/handler/validator
|
||||||
|
persistence.md EF Core, migrations, interceptors, the audit interceptor
|
||||||
|
identity.md JWE, sessions, rotation, field encryption, PhoneHash
|
||||||
|
conventions.md successor to CONVENTIONS.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Rewritten in place: `CLAUDE.md` (root), `client/CLAUDE.md`, `server/CLAUDE.md`, 3× `AGENTS.md`.
|
||||||
|
Deleted after distillation: `server/CONVENTIONS.md`, `client/messages/STYLE.md` (content moves to
|
||||||
|
`docs/rules/client/i18n.md`; **check `lint:copy` doesn't read STYLE.md by path before deleting**).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
### 1. Extract every distinct rule into a ledger first
|
||||||
|
|
||||||
|
Before writing any output file, build a working list (scratch, not committed) of every *rule* found
|
||||||
|
across all inputs, tagged with: source file:line, scope (client/server/shared), tier
|
||||||
|
(hard/reference), and whether it is **contradicted or obsoleted** by another source or by the code.
|
||||||
|
|
||||||
|
This is the step that prevents loss. Merging by reading two documents side by side and writing a
|
||||||
|
third loses whatever was in neither's first half.
|
||||||
|
|
||||||
|
### 2. Reality-check the client rules against the post-overhaul code
|
||||||
|
|
||||||
|
`client/CLAUDE.md` and the frontend-designer skill both predate iterations 1–2 (commits `baa3cc6`,
|
||||||
|
`e6a8f93`). Those commits changed load-bearing things:
|
||||||
|
|
||||||
|
- **Mobile-scoped shell** — max-width container, no desktop sidebar for the nurse side
|
||||||
|
- **Bottom navigation** replacing the drawer, grouped root pages with domain summaries
|
||||||
|
- **Icon set replaced** wholesale
|
||||||
|
- **react-hook-form** for every form with >1 field (28 files currently import it — confirm coverage
|
||||||
|
and note any state-based forms left behind; that gap belongs in Phase 4's backlog)
|
||||||
|
- **Theme/language switches** moved into settings only, out of every top bar
|
||||||
|
- **Paper border-radius** reduced globally
|
||||||
|
|
||||||
|
Any rule in either document that describes the *old* behaviour is obsolete. Rewrite it against the
|
||||||
|
code, and log the correction in `docs/_plan/open-contradictions.md` as resolved.
|
||||||
|
|
||||||
|
Do the same, more briefly, for the server: `server/CLAUDE.md`'s "Project map" (514 lines) must match
|
||||||
|
the 14 `.csproj` projects and 56 controllers actually present.
|
||||||
|
|
||||||
|
### 3. Write the reference layer
|
||||||
|
|
||||||
|
One file per row of the Outputs tree. Each opens with a two-line purpose and a
|
||||||
|
`> Last verified: <date> against <commit>` line. Keep them under ~400 lines; if `client/structure.md`
|
||||||
|
wants to be longer, it is listing files it should be describing patterns for.
|
||||||
|
|
||||||
|
### 4. Rewrite the three CLAUDE.md files
|
||||||
|
|
||||||
|
Each becomes, in order:
|
||||||
|
|
||||||
|
1. One paragraph: what this project is.
|
||||||
|
2. **Stack** and **Commands** (keep — they are consulted constantly).
|
||||||
|
3. **Quality gates** — the exact commands that must pass.
|
||||||
|
4. **Hard rules** — a numbered list, imperative, no prose. Target 15–25 items.
|
||||||
|
5. **Where to read more** — a table mapping "working on X" → `docs/rules/…/X.md`.
|
||||||
|
|
||||||
|
Root `CLAUDE.md` keeps its "What Balinyaar is", "Repository layout" (updated for `docs/` and
|
||||||
|
`archive/`), and the working agreements — but agreement 7 ("keep the architecture map current") now
|
||||||
|
points at `docs/rules/` as well.
|
||||||
|
|
||||||
|
Rules that must survive into the hard-rule lists verbatim (do not soften):
|
||||||
|
|
||||||
|
- `Seams:FieldEncryption:Key` / `:HashKey` are load-bearing — changing them makes every PII read throw
|
||||||
|
and every phone lookup miss.
|
||||||
|
- Config lives in files, not a secret store — **`dotnet user-secrets` is not used and is not read**.
|
||||||
|
(This is the single most-repeated stale instruction in the repo; state it loudly.)
|
||||||
|
- Stay within one project per change.
|
||||||
|
- No dead code; the client fails the build on unused vars.
|
||||||
|
- Don't reintroduce starter scaffolding or `_TITLE_`/`_DESCRIPTION_` placeholders.
|
||||||
|
- Read `product/` before changing behaviour.
|
||||||
|
|
||||||
|
### 5. Rewrite the three `AGENTS.md`
|
||||||
|
|
||||||
|
They stay thin pointers. Update the paths they point at.
|
||||||
|
|
||||||
|
### 6. Write `docs/rules/documentation.md`
|
||||||
|
|
||||||
|
The anti-drift convention, as agreed:
|
||||||
|
|
||||||
|
- What to update when X changes (endpoint → `docs/integration/`; flow ships → `docs/flows/<flow>.md`;
|
||||||
|
backlog item closed → tick it in `docs/status/backlog.md`, never delete it; structure changes →
|
||||||
|
the matching architecture section).
|
||||||
|
- The `> Last verified: <date> against <commit>` header convention, and which docs must carry it.
|
||||||
|
- The one-home rule: `product/` = business, `docs/` = engineering + status, `archive/` = history.
|
||||||
|
- Length budgets, so this doesn't regrow.
|
||||||
|
|
||||||
|
Phase 7 adds the pre-commit warning that enforces the first bullet.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- [ ] `client/CLAUDE.md` under 250 lines; `server/CLAUDE.md` under 250 lines.
|
||||||
|
- [ ] Every rule in the Step-1 ledger appears in exactly one output file — spot-check 20 at random.
|
||||||
|
- [ ] No rule describes pre-iteration-1/2 client behaviour.
|
||||||
|
- [ ] `grep -rn "user-secrets" client/ server/ CLAUDE.md docs/` returns only statements that it is
|
||||||
|
**not** used.
|
||||||
|
- [ ] `cd client && npm run check` still passes (in case `lint:copy` referenced `STYLE.md` by path).
|
||||||
|
- [ ] Both `AGENTS.md` pointer files resolve.
|
||||||
|
- [ ] Every contradiction Phase 0 logged in the rules domain is marked resolved with its resolution.
|
||||||
|
|
||||||
|
## Definition of done
|
||||||
|
|
||||||
|
An agent opening `client/CLAUDE.md` learns what it may not do in under 250 lines, and knows exactly
|
||||||
|
which one file to open next for the area it is touching.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
_(filled in by the agent that runs this phase)_
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
# Phase 2 — Integration & dependency
|
||||||
|
|
||||||
|
**Depends on:** Phase 0 · **Can run in parallel with:** Phase 1 · **Blocks:** Phase 3 · **Size:** one session
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Make the client↔server dependency a **thing you can read in one place**, and re-sync the contract
|
||||||
|
layer with the code it stopped tracking on 2026-07-13.
|
||||||
|
|
||||||
|
Right now the seam is real but scattered: envelope shape and casing in one contract doc, cookies and
|
||||||
|
refresh in `client/CLAUDE.md`, CORS in a refinement report, `NEXT_PUBLIC_API_URL` in `.env` files,
|
||||||
|
the container topology in `DEPLOY.md` and `docker-compose.yml`, and the OTP relay in its own README.
|
||||||
|
Nobody can answer "what does the client actually need from the server?" without reading six files.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- `docs/integration/openapi/swagger.v1.json` — the **fresh** snapshot from Phase 0, plus the
|
||||||
|
added/removed endpoint diff Phase 0 wrote into `docs/_plan/open-contradictions.md`.
|
||||||
|
- [dev/contracts/](../../dev/contracts/) — 18 domain files + 2 convention files + the stale snapshot.
|
||||||
|
- [dev/shared-working-context/frontend/requests/for-backend.md](../../dev/shared-working-context/frontend/requests/for-backend.md) —
|
||||||
|
67 REQs; many *are* contract amendments that were delivered but never folded back into the domain docs.
|
||||||
|
- [dev/shared-working-context/reports/mocks-registry.md](../../dev/shared-working-context/reports/mocks-registry.md) — which seams are mocked.
|
||||||
|
- [DEPLOY.md](../../DEPLOY.md) · [docker-compose.yml](../../docker-compose.yml) · [deploy/Caddyfile](../../deploy/Caddyfile)
|
||||||
|
- [telegram-otp-bot/README.md](../../telegram-otp-bot/README.md) + [INTEGRATION-PROMPT.md](../../telegram-otp-bot/INTEGRATION-PROMPT.md)
|
||||||
|
- `client/.env.development`, `client/.env.production`, `server/src/API/Baya.Web.Api/appsettings*.json`
|
||||||
|
- Code, for the seam itself: `client/src/lib/api/`, `client/src/services/*/`, the server's
|
||||||
|
`ApiResult` envelope, CORS setup, and auth middleware.
|
||||||
|
|
||||||
|
## Outputs
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/integration/
|
||||||
|
index.md THE seam, one page: what crosses the wire and what each side owes the other
|
||||||
|
api-contract.md envelope, casing, pagination, errors, idempotency, auth headers/cookies
|
||||||
|
domains/ 22 files, one per service domain — refreshed against the live swagger
|
||||||
|
openapi/
|
||||||
|
swagger.v1.json (from Phase 0)
|
||||||
|
README.md how to regenerate, when it was last taken, endpoint count
|
||||||
|
config-matrix.md every env var / appsettings key, both projects + docker + the bot
|
||||||
|
topology.md the runtime dependency graph
|
||||||
|
```
|
||||||
|
|
||||||
|
Also updated: [DEPLOY.md](../../DEPLOY.md) — fix the stale `user-secrets` reference and link to
|
||||||
|
`docs/integration/topology.md`. It stays at root and stays the deploy *procedure*.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
### 1. Write `index.md` first — the seam on one page
|
||||||
|
|
||||||
|
Before touching the per-domain detail, answer these in one page:
|
||||||
|
|
||||||
|
- **Transport**: HTTP/JSON over `NEXT_PUBLIC_API_URL`; where gRPC exists and whether it is used.
|
||||||
|
- **The envelope**: `ApiResult` — `{ isSuccess, statusCode, message, requestId, data }`, payload
|
||||||
|
always under `data`, `requestId` is a W3C trace id (refinement-phase-9). Client unwraps in
|
||||||
|
`clientFetch`/`unwrap()`.
|
||||||
|
- **Casing**: JSON bodies camelCase; URL segments snake_case. (REQ-001 settled this — confirm against
|
||||||
|
the live swagger, don't trust the doc.)
|
||||||
|
- **Pagination**: `{ items, total, page, pageSize }`; the server binds `pageSize` case-insensitively
|
||||||
|
(REQ-010).
|
||||||
|
- **Errors**: status codes, machine-readable error codes (REQ-003), what the client does with 401 /
|
||||||
|
403 / 5xx / network.
|
||||||
|
- **Auth**: the cookie set, JWE opacity to the client, silent refresh, session rotation and
|
||||||
|
reuse-detection, `/me` and `me/select_role`, role hydration.
|
||||||
|
- **Idempotency**: which endpoints require `Idempotency-Key` and what the client generates.
|
||||||
|
- **Money**: IRR on the wire, Toman at the UI boundary — link to `docs/rules/shared/`.
|
||||||
|
- **What the server owes the client** and **what the client owes the server**, as two short lists.
|
||||||
|
|
||||||
|
### 2. Refresh the 22 domain contracts against the live swagger
|
||||||
|
|
||||||
|
For each domain, compare the contract doc against `swagger.v1.json` and the handler code. Mark each
|
||||||
|
endpoint: `matches` · `drifted (describe)` · `undocumented (in code, not in contract)` ·
|
||||||
|
`phantom (in contract, not in code)`.
|
||||||
|
|
||||||
|
Fold in the delivered REQs — 17+ were delivered in refinement-phase-3 and amended shapes that the
|
||||||
|
domain docs still describe the old way. **The domain doc is the thing that should be true; the REQ
|
||||||
|
ledger is a change log.** After this phase, a reader should never need to read the REQ file to know
|
||||||
|
the current shape.
|
||||||
|
|
||||||
|
Note the domain-file cleanup: there is both a `messaging.md` (851 B stub) and a
|
||||||
|
`messaging-notifications-admin.md` (10.6 KB) — merge. Align the file set with the client's 22
|
||||||
|
`services/` domains so the mapping is one-to-one where it can be.
|
||||||
|
|
||||||
|
Anything you cannot verify from swagger or code: mark `UNVERIFIED:` and add a row to Phase 4's input
|
||||||
|
list. Do not guess a shape.
|
||||||
|
|
||||||
|
### 3. Write `config-matrix.md`
|
||||||
|
|
||||||
|
One table: **key · where it's set (appsettings / .env / docker-compose / Caddyfile) · consumed by ·
|
||||||
|
required? · default · notes**. Cover at minimum:
|
||||||
|
|
||||||
|
- `NEXT_PUBLIC_API_URL`, `NEXT_PUBLIC_NESHAN_KEY`, and the rest of the client's `NEXT_PUBLIC_*`
|
||||||
|
- `IdentitySettings:SecretKey` / `:Encryptkey`
|
||||||
|
- `Seams:FieldEncryption:Key` / `:HashKey` — **flag as load-bearing and immutable**
|
||||||
|
- the connection strings (app DB + log DB), and that the DB is remote and **not** containerised
|
||||||
|
- `OpenTelemetry:Otlp:Endpoint`, the health endpoints (`/healthz/live`, `/healthz/ready`)
|
||||||
|
- the seam selectors that choose real vendor adapters vs mocks (refinement-phase-8)
|
||||||
|
- the Telegram OTP bot's token/chat config
|
||||||
|
- CORS origins, and the Caddy hostnames `balinyaar.ir` / `api.balinyaar.ir`
|
||||||
|
|
||||||
|
State plainly, once, that config lives in files and `dotnet user-secrets` is not used — and that this
|
||||||
|
is a deliberate pre-launch trade with live credentials in git (link to `DEPLOY.md` "Going to
|
||||||
|
Production" and to Phase 5's `pre-launch.md`).
|
||||||
|
|
||||||
|
### 4. Write `topology.md`
|
||||||
|
|
||||||
|
The runtime dependency graph — a mermaid diagram plus a short table:
|
||||||
|
|
||||||
|
```
|
||||||
|
browser -> Caddy (caddy_net) -> client container (Next.js) -> server container (ASP.NET)
|
||||||
|
-> server container -> remote SQL Server (not containerised)
|
||||||
|
-> telegram-otp-bot (OTP relay)
|
||||||
|
-> object storage / external rails (per seam config)
|
||||||
|
```
|
||||||
|
|
||||||
|
For each edge: what flows over it, what breaks if it is down, and where it is configured. This is the
|
||||||
|
"dependency between projects, documented in a proper place" deliverable.
|
||||||
|
|
||||||
|
### 5. Point the old locations at the new one
|
||||||
|
|
||||||
|
`dev/contracts/README.md` gets a one-line "moved to `docs/integration/`" banner (Phase 6 archives the
|
||||||
|
folder; until then, don't leave two live copies competing).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- [ ] Every endpoint in `swagger.v1.json` appears in exactly one `docs/integration/domains/*.md`, or
|
||||||
|
is listed in that file's "undocumented, intentionally" section with a reason.
|
||||||
|
- [ ] No `phantom` endpoints remain undeclared — each is either removed from the doc or listed as
|
||||||
|
"planned, not built" with a backlog reference for Phase 4.
|
||||||
|
- [ ] `config-matrix.md` accounts for every key in `appsettings.Production.json`,
|
||||||
|
`docker-compose.yml`, and both `.env` files — diff mechanically, don't eyeball.
|
||||||
|
- [ ] `DEPLOY.md` no longer instructs anyone to use `user-secrets`.
|
||||||
|
- [ ] `index.md` fits on one screen-and-a-half and answers the seam question without a single click.
|
||||||
|
|
||||||
|
## Definition of done
|
||||||
|
|
||||||
|
A frontend agent can build against the API by reading `docs/integration/index.md` plus one domain
|
||||||
|
file, and a deploy question is answered by `topology.md` + `config-matrix.md` without opening
|
||||||
|
`docker-compose.yml`.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
_(filled in by the agent that runs this phase — especially: the drift list, since Phase 4 turns the
|
||||||
|
`phantom` and `drifted` rows into backlog items)_
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
# Phase 3 — The flow atlas (verified)
|
||||||
|
|
||||||
|
**Depends on:** Phase 0, Phase 2 · **Blocks:** Phase 4 · **Size:** 2–4 sessions — the biggest phase
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Build **the one go-to place** that answers, for every flow in the product:
|
||||||
|
|
||||||
|
1. What is it, and who does it?
|
||||||
|
2. **Is it actually implemented — really, or only mocked?**
|
||||||
|
3. What screens and endpoints does it use?
|
||||||
|
4. **How do I test it, step by step, with which account?**
|
||||||
|
5. What's known to be broken or missing?
|
||||||
|
|
||||||
|
This is the phase where "verify the load-bearing claims" earns its keep. The existing
|
||||||
|
[manual-testing-plan.md](../../dev/post-phase/manual-testing-plan.md) is the closest predecessor and
|
||||||
|
it is already wrong about bring-up (it tells you to set `user-secrets`, which the code no longer
|
||||||
|
reads). Copying it forward would reproduce the problem this chain exists to fix.
|
||||||
|
|
||||||
|
**Run this phase in slices.** One session does `testing-setup.md` + 4–6 flows. Later sessions pick up
|
||||||
|
the next slice. The index table tracks which flows are done.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- [dev/post-phase/manual-testing-plan.md](../../dev/post-phase/manual-testing-plan.md) — flow
|
||||||
|
walkthroughs, test accounts, the seeded world, the mock-vs-real map, the numbers the UI must respect
|
||||||
|
- [dev/post-phase/refinement/RUNBOOK.md](../../dev/post-phase/refinement/RUNBOOK.md) — bring-up, demo
|
||||||
|
accounts, login round-trip, reset, troubleshooting
|
||||||
|
- [dev/shared-working-context/reports/mocks-registry.md](../../dev/shared-working-context/reports/mocks-registry.md)
|
||||||
|
- `docs/integration/` — from Phase 2, the endpoint truth
|
||||||
|
- `product/business/*` — the 14 requirement areas; what "correct" means
|
||||||
|
- The seeder code (`DemoWorldSeeder`, `DemoLifecycleSeeder`) — **the authority on test accounts and
|
||||||
|
seeded state**, over any doc
|
||||||
|
- `client/src/app/[locale]/**` — 83 routes across `(customer)`, `(customer-focused)`, `nurse`,
|
||||||
|
`admin`, `partner`, `(public-routes)`
|
||||||
|
- `client/src/services/*/` — 22 domains, each with a mock/real flag
|
||||||
|
|
||||||
|
## Outputs
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/flows/
|
||||||
|
index.md the status table — every flow, one row
|
||||||
|
testing-setup.md bring-up, accounts, seeded world, OTP, reset, troubleshooting
|
||||||
|
<flow>.md one per flow (see the candidate list)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Candidate flow list
|
||||||
|
|
||||||
|
Derived from the route groups, the 22 service domains, and the 14 business areas. Confirm and adjust
|
||||||
|
in the first session; the point is one file per *user-meaningful journey*, not per screen.
|
||||||
|
|
||||||
|
| # | Flow | Actor | Primary routes |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| 1 | `auth-login-otp` | all | `(public-routes)/login`, `select-role` |
|
||||||
|
| 2 | `public-front-door` | guest | `/`, `welcome`, `terms`, `privacy` |
|
||||||
|
| 3 | `onboarding-customer` | customer | onboarding, account |
|
||||||
|
| 4 | `care-circle-patients` | customer | patients / care-circle |
|
||||||
|
| 5 | `addresses-and-map` | customer | addresses, Neshan pin |
|
||||||
|
| 6 | `onboarding-nurse` | nurse | profile, bank account |
|
||||||
|
| 7 | `nurse-service-areas` | nurse | coverage, whole-city (`districtId = null`) |
|
||||||
|
| 8 | `nurse-verification` | nurse + admin | verification journey, document upload, review queue |
|
||||||
|
| 9 | `nurse-catalog-and-pricing` | nurse | services, variant builder |
|
||||||
|
| 10 | `search-and-discovery` | customer | C1–C3, filters, nurse profile |
|
||||||
|
| 11 | `booking-request` | customer + nurse | C4/C5, nurse inbox, countdown, accept/reject |
|
||||||
|
| 12 | `checkout-and-payment` | customer | C6, gateway return, confirmation, escrow |
|
||||||
|
| 13 | `bnpl-installments` | customer | D1–D5 |
|
||||||
|
| 14 | `booking-lifecycle-evv` | nurse + customer | check-in/out, two-stage clinical gate |
|
||||||
|
| 15 | `cancellation-and-refunds` | customer + admin | cancel, policy, refund settlement |
|
||||||
|
| 16 | `reviews` | customer | post-visit review, moderation |
|
||||||
|
| 17 | `patient-care-records` | nurse + customer | append-only records |
|
||||||
|
| 18 | `nurse-earnings-and-payouts` | nurse | earnings, weekly payout run |
|
||||||
|
| 19 | `messaging-tickets` | all | threads, `is_internal` boundary |
|
||||||
|
| 20 | `notifications` | all | bell, day-grouped list |
|
||||||
|
| 21 | `admin-backoffice` | admin | config, holidays, audit, RBAC, queues |
|
||||||
|
| 22 | `partner-center` | partner | the separately-scoped portal |
|
||||||
|
| 23 | `account-and-settings` | all | profile, theme/language (settings-only since iteration 1) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
### 1. Write `testing-setup.md` — and **actually boot it**
|
||||||
|
|
||||||
|
Do not transcribe RUNBOOK.md. Follow it, note where it is wrong, and write what really happens.
|
||||||
|
|
||||||
|
Must cover:
|
||||||
|
|
||||||
|
- Prerequisites and the two-terminal run (`dotnet run` + `npm run dev`).
|
||||||
|
- **Configuration** — the current, correct story: config in `appsettings.*.json` and `.env.*`;
|
||||||
|
`user-secrets` **is not used and is not read** (`<UserSecretsId>` was removed). The four crypto
|
||||||
|
values still matter and must match whatever the target DB was encrypted under — booting with
|
||||||
|
different `Seams:FieldEncryption` keys makes every phone lookup miss and every PII read throw
|
||||||
|
`Padding is invalid`. Say where they live now.
|
||||||
|
- **Which database.** The dev config has pointed at a *remote* SQL Server. Confirm the current
|
||||||
|
target, and give the local-DB alternative.
|
||||||
|
- **Test accounts** — read them out of the seeder, not the old doc. Note the phone-OTP admins
|
||||||
|
(`09120000020` super_admin, `09120000021` finance) and what each demo account is set up to
|
||||||
|
demonstrate.
|
||||||
|
- **Getting the OTP** — server console (`MOCK SMS — OTP code …`), `GET /api/v1/dev/last_otp/{phone}`,
|
||||||
|
or the Telegram relay. Note the limits: 120 s resend window, 5 wrong attempts, 60 s validity, and
|
||||||
|
that the OTP endpoints are IP rate-limited (scripted logins will 429).
|
||||||
|
- **The seeded world** — what `DemoLifecycleSeeder` builds (the 8-booking world), and the fact that
|
||||||
|
**time-relative scenarios age out** and need a reseed.
|
||||||
|
- **Reset** — the drop-and-reseed procedure, verified.
|
||||||
|
- **Troubleshooting** — the failures you actually hit while doing the above.
|
||||||
|
|
||||||
|
### 2. Build the mock-vs-real map — from code
|
||||||
|
|
||||||
|
The single most important input to every flow file, and the thing most likely to be stale in the
|
||||||
|
docs. For each of the 22 client `services/` domains, read the code:
|
||||||
|
|
||||||
|
- Is the mock flag on or off?
|
||||||
|
- If real, does the whole domain hit the API, or only part of it?
|
||||||
|
- Server-side: which seams are mocked (SMS, payment gateway, BNPL provider, object storage,
|
||||||
|
geocoder, search) and which have a real adapter available behind config (refinement-phase-8)?
|
||||||
|
|
||||||
|
Cross-check `mocks-registry.md` and **correct it** — Phase 0 already flagged that the registry has
|
||||||
|
had stale rows before. Put the result in `docs/flows/index.md` as a column, and in each flow file as
|
||||||
|
a header block.
|
||||||
|
|
||||||
|
Known suspects from the hardening audit (2026-07-16, never ticked off — verify each against current
|
||||||
|
code, do not assume): verification fully mocked while catalog/search are real; the refunds mock
|
||||||
|
reading a retired store; the BNPL wizard on a disconnected store; nurse earnings fabricated despite
|
||||||
|
live endpoints; `patientRecords` id-type mismatch.
|
||||||
|
|
||||||
|
### 3. Write one file per flow
|
||||||
|
|
||||||
|
Template — keep each under ~200 lines:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Flow — <name>
|
||||||
|
|
||||||
|
> Last verified: <date> against <commit>
|
||||||
|
|
||||||
|
**Actor(s):** · **Status:** built | partial | mocked | not started
|
||||||
|
**Business source:** product/business/NN-….md
|
||||||
|
|
||||||
|
## What it does
|
||||||
|
Two or three sentences. The user's intent, not the implementation.
|
||||||
|
|
||||||
|
## Screens
|
||||||
|
| Step | Route | Component/notes |
|
||||||
|
|
||||||
|
## API
|
||||||
|
| Call | Endpoint | Notes |
|
||||||
|
Link to docs/integration/domains/<domain>.md — don't restate shapes here.
|
||||||
|
|
||||||
|
## Rules that must hold
|
||||||
|
The load-bearing numbers and invariants, with their product/ source.
|
||||||
|
(e.g. commission 0.15, VAT 0.10 on commission only; forward-only status;
|
||||||
|
escrow released after confirmed check-out; whole-city = districtId NULL)
|
||||||
|
|
||||||
|
## How to test
|
||||||
|
1. Log in as <account> (see testing-setup.md)
|
||||||
|
2. …
|
||||||
|
**Expect:** …
|
||||||
|
|
||||||
|
## Known gaps
|
||||||
|
- [BL-xxx] … (filled by Phase 4; leave a plain list here for now)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Verification standard per flow.** For each, do at least the cheap check — trace the route → service
|
||||||
|
→ endpoint → handler and confirm the chain is real. For the money flows (11–15, 18) and auth (1), do
|
||||||
|
the expensive check too: run the walkthrough against a booted app. If you cannot run it, mark the
|
||||||
|
flow's status `UNVERIFIED` in the index and say why — an honest gap beats a confident guess.
|
||||||
|
|
||||||
|
### 4. Write `index.md`
|
||||||
|
|
||||||
|
The status table, and nothing else of substance:
|
||||||
|
|
||||||
|
| Flow | Actor | Status | Client | Server | Verified | File |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| booking-request | customer + nurse | built | real | real | 2026-…-… | [link] |
|
||||||
|
|
||||||
|
Statuses: `built` (end-to-end real) · `partial` (real but with gaps) · `mocked` (UI real, data fake) ·
|
||||||
|
`not started`. `Client`/`Server` columns say `real`/`mock` independently — a flow can have a real UI
|
||||||
|
on a mocked service, which is exactly the trap the hardening audit found.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- [ ] `testing-setup.md` was executed, not transcribed — the agent booted the API and the client.
|
||||||
|
- [ ] Every flow file has a status backed by a code trace, or an explicit `UNVERIFIED` mark.
|
||||||
|
- [ ] The mock-vs-real map was derived from code and disagreements with `mocks-registry.md` are logged.
|
||||||
|
- [ ] No flow file restates an API shape that `docs/integration/` already owns.
|
||||||
|
- [ ] The index accounts for all 22 client service domains and all 14 business areas — anything with
|
||||||
|
no flow is either intentional or a Phase 4 backlog item.
|
||||||
|
- [ ] Every flow file carries a `Last verified:` line.
|
||||||
|
|
||||||
|
## Definition of done
|
||||||
|
|
||||||
|
You can hand someone `docs/flows/testing-setup.md` and `docs/flows/index.md` and they can test the
|
||||||
|
product without asking you a single question — and without hitting an instruction that no longer works.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
_(filled in per slice — which flows are done, which are `UNVERIFIED` and why, and the running list of
|
||||||
|
gaps found, which is Phase 4's primary input)_
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
# Phase 4 — Backlog reconciliation
|
||||||
|
|
||||||
|
**Depends on:** Phase 0, Phase 3 (and consumes Phase 2's drift list) · **Blocks:** Phase 5 · **Size:** 1–2 sessions
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Turn **five unreconciled ledgers plus 50+ scattered "follow-ups" sections** into one triaged backlog
|
||||||
|
where every open item is real, deduplicated, and carries its origin.
|
||||||
|
|
||||||
|
This is the "remaining works from plans, dev, refine and ui phases should be well documented"
|
||||||
|
deliverable. Today the honest answer to "what's left?" is *nobody knows* — the hardening ledger has
|
||||||
|
18 items with **zero ticked**, written before three more chains ran on top of it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| Source | Volume | Note |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| [dev/post-phase/hardening/issues.md](../../dev/post-phase/hardening/issues.md) | 18 items, **all unticked** | Written 2026-07-16. UI phases 0–13 and the deploy commits ran after. **Every item must be re-verified against current code.** |
|
||||||
|
| [dev/shared-working-context/frontend/requests/for-backend.md](../../dev/shared-working-context/frontend/requests/for-backend.md) | 67 REQs, 1,115 lines | Most delivered in refinement-phase-3; some `partially delivered`; REQ-066/067 blocked on a privacy sign-off |
|
||||||
|
| `dev/shared-working-context/reports/*.md` | 50 files | Each has a "Follow-ups for later phases" / "Deferred" section |
|
||||||
|
| `dev/shared-working-context/backend/STATUS.md` + `frontend/STATUS.md` | 86 KB | Deferrals recorded with explicit **pull-triggers** (e.g. Elasticsearch `INurseSearch`, SMS/push dispatcher, analytics, holiday feed, 8 unbuilt product tables) |
|
||||||
|
| [dev/manual-testing/iteration-1/](../../dev/manual-testing/iteration-1/) + [iteration-2/](../../dev/manual-testing/iteration-2/) | 2 raw notes + screenshots | Your own most recent feedback. Some applied in `baa3cc6` / `e6a8f93`; **which parts landed is unknown** |
|
||||||
|
| [product/notes/open-questions.md](../../product/notes/open-questions.md) | build backlog + research questions | |
|
||||||
|
| Phase 2's output | drift list | `phantom` and `drifted` endpoints |
|
||||||
|
| Phase 3's output | gap list | everything found while verifying flows |
|
||||||
|
| Root [CLAUDE.md](../../CLAUDE.md) §6 | | credential rotation before real users — a real pre-launch item |
|
||||||
|
|
||||||
|
## Outputs
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/status/
|
||||||
|
index.md where the project is, in one page
|
||||||
|
implemented.md the product/business overlay: 14 areas -> build state
|
||||||
|
backlog.md BL-### — every open item, triaged
|
||||||
|
backlog-closed.md items confirmed done, with what closed them
|
||||||
|
decisions.md the distilled decision log
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
### 1. Harvest everything into one raw list
|
||||||
|
|
||||||
|
One row per candidate item, with its **origin id** (`H-01`, `REQ-042`, `ui-phase-9 follow-up`,
|
||||||
|
`iteration-2`, `deferral: elasticsearch`, `phase-3 finding`, `phase-2 drift`). Expect 150–250 raw
|
||||||
|
rows before dedup. Do not filter while harvesting.
|
||||||
|
|
||||||
|
### 2. Verify each item's current state
|
||||||
|
|
||||||
|
This is the phase's real work, and the reason it comes after Phase 3.
|
||||||
|
|
||||||
|
- **The 18 hardening items**: re-locate each in the code. The file itself warns that line numbers
|
||||||
|
drifted. Several are likely fixed by the UI chain — e.g. **H-01** (the auth gate never running,
|
||||||
|
traced to a stray `pnpm-lock.yaml` and the `middleware.ts` → `proxy.ts` question) overlaps directly
|
||||||
|
with what ui-phase-13 did to the root route and matcher. Verify; don't assume either way.
|
||||||
|
- **The 67 REQs**: classify `delivered` / `partially delivered — what's left` / `open` / `obsolete`.
|
||||||
|
The ones marked `partially delivered in refinement-phase-3` need the residue spelled out. Once
|
||||||
|
Phase 2 folded delivered REQs into the domain docs, a delivered REQ is *closed*, not an item.
|
||||||
|
- **Iterations 1 & 2**: walk each bullet against the code. The clearest testable one:
|
||||||
|
*"replace all forms with more than 1 field with react-hook-form"* — 28 files import it today;
|
||||||
|
find the forms that still use raw state and file the residue.
|
||||||
|
- **Deferrals**: these are not bugs; they are *decisions with pull-triggers*. Keep them as
|
||||||
|
`deferred`, carry the trigger, and hand them to Phase 5's `roadmap/deferred.md`.
|
||||||
|
|
||||||
|
### 3. Dedup and assign `BL-###`
|
||||||
|
|
||||||
|
Many items appear in three ledgers. Merge them into one `BL-###` carrying **all** origin ids.
|
||||||
|
Old ids stay greppable — never rewrite the archived sources.
|
||||||
|
|
||||||
|
### 4. Write `backlog.md`
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
> Last verified: <date> against <commit>
|
||||||
|
|
||||||
|
| ID | Area | Sev | Item | Origin | Status | Blocks |
|
||||||
|
|----|------|-----|------|--------|--------|--------|
|
||||||
|
| BL-001 | client | blocker | … | H-01 | open | flow: auth-login-otp |
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Area**: `client` · `server` · `contract` · `ops` · `product` · `docs`
|
||||||
|
- **Sev**: `blocker` (product is wrong or unusable) · `major` · `minor` · `deferred`
|
||||||
|
- **Status**: `open` · `in-progress` · `blocked (on what)` · `deferred (trigger)`
|
||||||
|
- **Blocks**: the flow(s) from `docs/flows/` it degrades — this is what connects the backlog to
|
||||||
|
something a user can feel
|
||||||
|
|
||||||
|
Sort by severity, then area. Anything closed goes to `backlog-closed.md` with *what* closed it
|
||||||
|
(commit or phase), so the count of open items is honest at a glance.
|
||||||
|
|
||||||
|
### 5. Write `implemented.md` — the product overlay
|
||||||
|
|
||||||
|
The agreed alternative to touching `product/`. One row per business area:
|
||||||
|
|
||||||
|
| Business area | Doc | State | Flows | Gaps |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| 08 Payments & escrow | [product/business/08-…](../../product/business/08-payments-and-escrow.md) | built | checkout-and-payment, cancellation-and-refunds | BL-023 |
|
||||||
|
|
||||||
|
States: `built` · `partial` · `mocked` · `not started` · `deferred`. Add the reverse link from each
|
||||||
|
`docs/flows/*.md` back to its business area. This gives the two-way mapping without editing a single
|
||||||
|
`product/` file.
|
||||||
|
|
||||||
|
Do the same, briefly, for the data model: the STATUS logs mention **8 product tables that were never
|
||||||
|
built** — name them here rather than leaving them in a status log.
|
||||||
|
|
||||||
|
### 6. Write `decisions.md`
|
||||||
|
|
||||||
|
The distilled decision log — the highest-value thing buried in 3 MB of reports. Extract every
|
||||||
|
**non-obvious decision with a reason** and write it as a short ADR-style entry: *what was decided,
|
||||||
|
when, why, and where it binds*. Candidates already visible in the STATUS logs and memory:
|
||||||
|
|
||||||
|
- Commission 0.15 / VAT 0.10 **on commission only** (the canonical fee model, refinement-phase-3)
|
||||||
|
- `district_id = NULL` means whole-city — in both directions
|
||||||
|
- Verification `status` is the source of truth; `is_verified` is a guarded flip
|
||||||
|
- Booking status is forward-only; the three-amount split has a CHECK constraint
|
||||||
|
- The two-stage clinical-disclosure gate; EVV is **advisory**, never a block
|
||||||
|
- Webhook idempotency is upsert-first; ledger postings must balance
|
||||||
|
- Reviews recompute from source; nurse care records are append-only
|
||||||
|
- `is_internal` ticket messages never appear in user-facing types
|
||||||
|
- One payout per booking (UNIQUE); whole-clawback greedy netting
|
||||||
|
- Escrow released after a confirmed check-out; weekly payout generation automatic, processing manual
|
||||||
|
- Config in files, not a secret store — deliberate pre-launch trade
|
||||||
|
- Error state is never an empty state (the client convention)
|
||||||
|
- Root `/` forks by auth via middleware **rewrite**, never redirect
|
||||||
|
|
||||||
|
Each entry: 3–6 lines. Where a decision is already stated in `product/`, link rather than restate —
|
||||||
|
`product/` wins for business rules; `decisions.md` is for *engineering* decisions and for business
|
||||||
|
decisions that were made **during** the build and never made it back into `product/`. Anything in the
|
||||||
|
second category should also get a note in `product/notes/` so the business truth stays complete.
|
||||||
|
|
||||||
|
### 7. Write `index.md`
|
||||||
|
|
||||||
|
One page: how many flows are built/partial/mocked, how many backlog items are open by severity, the
|
||||||
|
top five things standing between here and a usable product, and links to everything. This is the page
|
||||||
|
you open when you come back after two weeks away.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- [ ] Every one of the 18 hardening items has a verdict backed by a code check — none carried over
|
||||||
|
unexamined.
|
||||||
|
- [ ] Every REQ-001…067 is classified; the count of `open` is explicit.
|
||||||
|
- [ ] Every "Follow-ups for later phases" section across the 50 reports was read and harvested.
|
||||||
|
- [ ] Both iteration notes are fully accounted for, bullet by bullet.
|
||||||
|
- [ ] No `BL-###` duplicates another; every one names its origin id(s).
|
||||||
|
- [ ] Every `blocker` names the flow it blocks.
|
||||||
|
- [ ] `implemented.md` covers all 14 business areas and all 23 flows.
|
||||||
|
|
||||||
|
## Definition of done
|
||||||
|
|
||||||
|
"What's left?" is answered by one file, and every number in it was checked rather than inherited.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
_(filled in by the agent that runs this phase — item counts by severity, and anything that turned out
|
||||||
|
to be worse than the old ledgers claimed)_
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
# Phase 5 — Roadmap & technical requirements
|
||||||
|
|
||||||
|
**Depends on:** Phase 4 · **Size:** one session
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Answer "what next?" — recording every already-decided future item **and** proposing a sequenced
|
||||||
|
order, with the technical prerequisites each step needs. The ordering is a proposal you can overrule;
|
||||||
|
the recording is not negotiable.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- `docs/status/backlog.md` and `implemented.md` — Phase 4's output, the ground truth
|
||||||
|
- `docs/flows/index.md` — what's mocked vs built
|
||||||
|
- The **deferrals with pull-triggers** from the STATUS logs: Elasticsearch `INurseSearch`, real
|
||||||
|
SMS/push `INotificationDispatcher`, the analytics pipeline, the holiday feed, **8 unbuilt product
|
||||||
|
tables**, and the refinement-phase-9 items 9.7–9.11
|
||||||
|
- [product/notes/future-ideas.md](../../product/notes/future-ideas.md) and
|
||||||
|
[open-questions.md](../../product/notes/open-questions.md) — including PWA/Workbox caching
|
||||||
|
- ui-phase-13's follow-ups: **tier (c)** — guest search + public nurse profiles (REQ-066/067), blocked
|
||||||
|
on a backend phase **and an explicit privacy sign-off on the nurse-profile field list**; the OG
|
||||||
|
image Persian variant
|
||||||
|
- Root [CLAUDE.md](../../CLAUDE.md) §6 + [DEPLOY.md](../../DEPLOY.md) "Going to Production" — the
|
||||||
|
credential-rotation obligation
|
||||||
|
- `product/business/*` — anything specified but never built
|
||||||
|
- `product/research/*` — go-to-market, legal landscape (informs sequencing, not scope)
|
||||||
|
|
||||||
|
## Outputs
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/roadmap/
|
||||||
|
index.md the proposed sequence + the reasoning, in one page
|
||||||
|
next-up.md the next 3-5 units of work, each spec'd enough to start
|
||||||
|
deferred.md recorded, with the trigger that pulls each one forward
|
||||||
|
tech-debt.md what must be paid before scale, and what it costs to defer
|
||||||
|
pre-launch.md the hard gate before real users touch this
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
### 1. `pre-launch.md` first — it's the one with a deadline
|
||||||
|
|
||||||
|
Everything that must be true before a real user with real money uses the platform. Known already:
|
||||||
|
|
||||||
|
- **Rotate the committed credentials** and move the secret half out of git. The repo currently
|
||||||
|
contains live credentials by deliberate pre-launch decision. Note the exception: `Seams:FieldEncryption:Key`
|
||||||
|
/ `:HashKey` decrypt existing PII and derive the phone-lookup hash — rotating those requires a data
|
||||||
|
migration, not a config edit. Spell out that migration as its own item.
|
||||||
|
- **Real external rails** — which seams are still mocked in production config (payment gateway, SMS,
|
||||||
|
BNPL provider, object storage). Phase 3's mock-vs-real map is the input; this is the list of seams
|
||||||
|
that must flip.
|
||||||
|
- **Running as Development in production** — `DEPLOY.md` documents this as a deliberate trade.
|
||||||
|
State what it implies (gRPC reflection, dev endpoints such as `/dev/last_otp`, seeding behaviour,
|
||||||
|
log verbosity) and what must change.
|
||||||
|
- Anything Phase 4 marked `blocker`.
|
||||||
|
- Legal/tax items from `product/business/13-tax-invoicing-and-legal.md` that are code-side.
|
||||||
|
|
||||||
|
Each item: what, why it blocks launch, roughly what it takes.
|
||||||
|
|
||||||
|
### 2. `deferred.md` — record faithfully, don't re-decide
|
||||||
|
|
||||||
|
One row per deferral: **item · why deferred · the pull-trigger (the condition that makes it
|
||||||
|
necessary) · rough size · where it was decided**. The pull-triggers already exist in the STATUS logs
|
||||||
|
— preserve them verbatim in substance. A deferral with a trigger is a decision; a deferral without
|
||||||
|
one is just a forgotten task, so any you find without a trigger, give one.
|
||||||
|
|
||||||
|
Include the 8 unbuilt product tables, named individually.
|
||||||
|
|
||||||
|
### 3. `tech-debt.md`
|
||||||
|
|
||||||
|
Debt is different from backlog: it doesn't block a flow, it raises the cost of everything after it.
|
||||||
|
Candidates to assess: the single-instance in-process scheduler; search without Elasticsearch; the
|
||||||
|
absence of E2E tests over the money paths; the remaining raw-state forms; the Windows-generated
|
||||||
|
client lockfile wrinkle in `DEPLOY.md`; test coverage asymmetry between the two projects.
|
||||||
|
|
||||||
|
For each: what it costs now, what it costs at 10× usage, and the trigger to pay it.
|
||||||
|
|
||||||
|
### 4. `next-up.md` — the opinionated part
|
||||||
|
|
||||||
|
Three to five units of work, each with: goal, why now, what it unblocks, technical prerequisites,
|
||||||
|
affected flows, rough size, and the backlog ids it closes. Enough that a fresh agent session could
|
||||||
|
start one without re-deriving the context.
|
||||||
|
|
||||||
|
**Sequencing principle to apply, and state explicitly in `index.md`:** the product's own promise is
|
||||||
|
trust-first and money-holding. So the order is (1) anything that makes a *money or trust* flow lie to
|
||||||
|
a user, (2) anything that makes a built flow unusable, (3) anything that makes a mocked flow real,
|
||||||
|
(4) new surface area. Tier (c) guest search is new surface — it ranks below making the authenticated
|
||||||
|
flows honest, regardless of how visible it is.
|
||||||
|
|
||||||
|
Where a proposed item conflicts with something in `product/`, say so and defer to `product/`.
|
||||||
|
|
||||||
|
### 5. `index.md`
|
||||||
|
|
||||||
|
The one-page sequence: a table of the proposed order with rationale per step, plus the standing
|
||||||
|
answer to "what are we not doing, and why" (a pointer to `deferred.md`). Mark clearly which parts are
|
||||||
|
**recorded decisions** and which are **this document's proposal** — the reader must be able to tell
|
||||||
|
your judgement from the project's.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- [ ] Every `deferred` item in `docs/status/backlog.md` appears in `deferred.md` with a trigger.
|
||||||
|
- [ ] Every recorded deferral from the STATUS logs is present, including the 8 unbuilt tables.
|
||||||
|
- [ ] `pre-launch.md` covers credential rotation, every still-mocked production seam, and the
|
||||||
|
Development-in-production trade.
|
||||||
|
- [ ] Every `next-up.md` item names the backlog ids it closes and the flows it affects.
|
||||||
|
- [ ] Proposal is visibly distinguished from record.
|
||||||
|
|
||||||
|
## Definition of done
|
||||||
|
|
||||||
|
You can pick the next piece of work in five minutes, and you can explain to someone else why it's
|
||||||
|
that piece and not another.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
_(filled in by the agent that runs this phase)_
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
# Phase 6 — Archive & prune
|
||||||
|
|
||||||
|
**Depends on:** Phases 1–5 all complete · **Size:** one session
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Move the 3 MB build-chain history out of the way — **after**, and only after, every live fact in it
|
||||||
|
has been extracted. Then fix every link that pointed into it.
|
||||||
|
|
||||||
|
This phase is mechanical. Its only real risk is running it early, so it has a hard gate.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Gate — do not start until all of these are true
|
||||||
|
|
||||||
|
- [ ] Phase 0's `docs/_plan/inventory.md` has a disposition for every file, with no blanks.
|
||||||
|
- [ ] Phases 1, 2, 3, 4, 5 are marked complete in [`README.md`](README.md)'s progress table.
|
||||||
|
- [ ] `docs/_plan/open-contradictions.md` has no unresolved rows (or each remaining one is explicitly
|
||||||
|
accepted with a reason).
|
||||||
|
- [ ] Every inventory row marked `live facts: yes` has been extracted by its owner phase — check them
|
||||||
|
off one by one, not in bulk.
|
||||||
|
|
||||||
|
If any box is unticked, stop and report which phase is incomplete.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- `docs/_plan/inventory.md` — the authority on what moves where
|
||||||
|
- The whole `dev/` tree
|
||||||
|
|
||||||
|
## Outputs
|
||||||
|
|
||||||
|
```
|
||||||
|
archive/
|
||||||
|
README.md "Historical record. Do NOT treat as instructions."
|
||||||
|
build-chain/
|
||||||
|
phases/ was dev/phases (32 executed prompt files + _shared)
|
||||||
|
working-context/ was dev/shared-working-context (STATUS, handoffs, 50 reports)
|
||||||
|
contracts/ was dev/contracts (superseded by docs/integration/)
|
||||||
|
post-phase/ was dev/post-phase (hardening, refinement, server, ui + audits)
|
||||||
|
manual-testing/ was dev/manual-testing (notes + screenshots)
|
||||||
|
docs/_plan/ moved to archive/clarify-chain/ at the very end
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
### 1. Write `archive/README.md` before moving anything
|
||||||
|
|
||||||
|
It must say, unambiguously and at the top:
|
||||||
|
|
||||||
|
> **This folder is a historical record of how Balinyaar was built. It is not instruction.**
|
||||||
|
> Nothing here describes current behaviour, current rules, or current plans. Do not follow a
|
||||||
|
> procedure from this folder. Current truth lives in [`docs/`](../docs/README.md) and
|
||||||
|
> [`product/`](../product/README.md).
|
||||||
|
|
||||||
|
Then: what each subfolder was, the date range it covers, and a table mapping each archived area to
|
||||||
|
the `docs/` file that superseded it. Someone finding `archive/post-phase/hardening/issues.md` must be
|
||||||
|
able to see in one step that it became `docs/status/backlog.md`.
|
||||||
|
|
||||||
|
### 2. Move, with `git mv`
|
||||||
|
|
||||||
|
Preserve history. Move whole directories rather than file-by-file. Keep the screenshots in
|
||||||
|
`manual-testing/` — they are the only visual record of the pre-overhaul UI.
|
||||||
|
|
||||||
|
Delete outright (per Phase 0's inventory): `Prompt.md` (0 bytes), `temp/swagger.json` (stale
|
||||||
|
duplicate), and the `graphify-out/GRAPH_REPORT.md` files if Phase 0 marked them generated-and-unused.
|
||||||
|
|
||||||
|
### 3. Fix inbound links
|
||||||
|
|
||||||
|
Every doc outside `archive/` that links into `dev/` must be repointed at its `docs/` successor — not
|
||||||
|
at the archived copy. Sweep at minimum: root `CLAUDE.md`, `client/CLAUDE.md`, `server/CLAUDE.md`,
|
||||||
|
`DEPLOY.md`, all three `AGENTS.md`, `product/README.md`, `product/index.md`,
|
||||||
|
`telegram-otp-bot/README.md`, `.githooks/README.md`, and everything under `docs/`.
|
||||||
|
|
||||||
|
Mechanical check:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -rn "](\.\./dev/\|](dev/\|(dev/" --include="*.md" . | grep -v "^./archive/"
|
||||||
|
```
|
||||||
|
|
||||||
|
should return nothing. Do the same sweep for `product/*.html` — the generated view has its own
|
||||||
|
cross-links, and if any point at `dev/`, fix the **`.md` source** and regenerate
|
||||||
|
(`cd product && node build-docs.mjs`), never the HTML.
|
||||||
|
|
||||||
|
### 4. Update the architecture map
|
||||||
|
|
||||||
|
Root `CLAUDE.md`'s "Repository layout" table is canonical for repo structure (its own working
|
||||||
|
agreement 7). Update it: `dev/` is gone, `docs/` and `archive/` are in, and the sentence describing
|
||||||
|
`dev/` as the build plan is replaced.
|
||||||
|
|
||||||
|
### 5. Update the memory index
|
||||||
|
|
||||||
|
`MEMORY.md` has ~50 entries, most of them phase memories whose file paths now point into `archive/`.
|
||||||
|
Add a single note at its top recording that the build-chain docs moved and where current truth lives,
|
||||||
|
so a future session doesn't chase dead paths. Don't rewrite 50 memory files.
|
||||||
|
|
||||||
|
### 6. Retire this plan
|
||||||
|
|
||||||
|
Move `docs/_plan/` → `archive/clarify-chain/`, and leave one line in `docs/README.md` noting when the
|
||||||
|
cleanup ran and where its plan lives.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- [ ] `dev/` no longer exists.
|
||||||
|
- [ ] The link grep above returns nothing outside `archive/`.
|
||||||
|
- [ ] `cd product && node build-docs.mjs` runs clean and the regenerated HTML has no `dev/` links.
|
||||||
|
- [ ] `cd client && npm run check` passes; `cd server && dotnet build Baya.sln` passes — confirming
|
||||||
|
nothing moved was referenced by tooling.
|
||||||
|
- [ ] `git status` shows moves as renames, not delete+add.
|
||||||
|
- [ ] `archive/README.md` maps every archived area to its successor.
|
||||||
|
|
||||||
|
## Definition of done
|
||||||
|
|
||||||
|
Nothing in the repo tells you to do something that was true three weeks ago, and nothing that was
|
||||||
|
learned in those three weeks is gone.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
_(filled in by the agent that runs this phase)_
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
# Phase 7 — Skills & anti-drift guardrails
|
||||||
|
|
||||||
|
**Depends on:** Phase 1 (rules) and Phase 3 (reality) · **Can run before or after Phase 6** · **Size:** one session
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Two things:
|
||||||
|
|
||||||
|
1. **Skills that match reality.** The one existing skill was written before the UI overhaul; parts of
|
||||||
|
it describe an app that no longer exists.
|
||||||
|
2. **Guardrails so this doesn't happen again** — the reason the cleanup was needed at all.
|
||||||
|
|
||||||
|
**The division of labour, restated:** a *rule* is a constraint that must never break → `docs/rules/`.
|
||||||
|
A *skill* is a procedure for a recurring task → `.claude/skills/`. If you're writing "always do X",
|
||||||
|
it's a rule. If you're writing "to do X: first…, then…", it's a skill.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
- [.claude/skills/frontend-designer/SKILL.md](../../.claude/skills/frontend-designer/SKILL.md) — 21 KB,
|
||||||
|
10 sections (brand, tokens, typography, component library, layout, icons, hard rules, workflow,
|
||||||
|
anti-patterns, Figma)
|
||||||
|
- `docs/rules/` — Phase 1's output, so the skill can stop restating rules and link instead
|
||||||
|
- `docs/flows/` — Phase 3's output, especially `testing-setup.md` and the mock-vs-real map
|
||||||
|
- The client code as it is **after** iterations 1–2
|
||||||
|
- [.githooks/pre-commit](../../.githooks/pre-commit) (3.4 KB) + [.githooks/README.md](../../.githooks/README.md)
|
||||||
|
- `client/package.json` scripts (`check`, `lint:copy`, `test:ci`) and the server's build/test commands
|
||||||
|
|
||||||
|
## Outputs
|
||||||
|
|
||||||
|
```
|
||||||
|
.claude/skills/
|
||||||
|
frontend-designer/SKILL.md rewritten against current reality
|
||||||
|
backend-feature/SKILL.md NEW — adding a feature to the .NET server
|
||||||
|
flow-testing/SKILL.md NEW — boot, seed, and walk a flow end-to-end
|
||||||
|
```
|
||||||
|
|
||||||
|
Updated: `.githooks/pre-commit`, `docs/rules/documentation.md` (Phase 1 wrote the convention; this
|
||||||
|
phase adds the enforcement note), and status-doc headers.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
### 1. Rewrite `frontend-designer`
|
||||||
|
|
||||||
|
Reality-check every section against the code, then rewrite. Specifically at risk (confirm each):
|
||||||
|
|
||||||
|
- **§5 Layout & page shells** — the app is now **mobile-scoped**: a max-width container so the shell
|
||||||
|
never stretches on desktop, and the nurse side moved from a drawer to a **bottom navigation** with
|
||||||
|
grouped root pages that summarize their domain. Any desktop-sidebar guidance is obsolete except
|
||||||
|
where admin still uses one.
|
||||||
|
- **§6 Icons** — the icon set was replaced wholesale in iteration 1. The old mapping guidance is dead.
|
||||||
|
- **§2 Design tokens / §3 Typography** — check against the current theme, including the reduced
|
||||||
|
Paper border-radius.
|
||||||
|
- **§7 Non-negotiable rules** — most of these are now **rules**, not skill content. Cut them down to
|
||||||
|
a link into `docs/rules/client/`, keeping only what's design-specific.
|
||||||
|
- **§1 Brand / §4 Component library** — verify the `App*` inventory against `client/src/components/`
|
||||||
|
(which currently holds ~40 feature components in addition to the shared kit).
|
||||||
|
- Add what's missing: **forms are react-hook-form** now, so the "build a form" procedure changes; and
|
||||||
|
theme/language switches live **only in settings**, not in top bars.
|
||||||
|
|
||||||
|
Target: shorter than the current 21 KB, because the rules half moves out.
|
||||||
|
|
||||||
|
### 2. Write `backend-feature`
|
||||||
|
|
||||||
|
The procedure for adding a feature to the server, derived from how the 199 handlers are actually
|
||||||
|
shaped: where the command/query goes, the handler and validator, the DTO, the controller action, the
|
||||||
|
EF configuration and migration, the tests, and the doc updates it must trigger
|
||||||
|
(`docs/integration/domains/<domain>.md` + the OpenAPI snapshot). Link to `docs/rules/server/` for
|
||||||
|
constraints; keep the skill to the sequence.
|
||||||
|
|
||||||
|
### 3. Write `flow-testing`
|
||||||
|
|
||||||
|
The procedure a session follows to actually exercise a flow: boot both sides per
|
||||||
|
`docs/flows/testing-setup.md`, get an OTP, log in as the right seeded account, walk the flow, and —
|
||||||
|
importantly — **check the mock-vs-real map first** so a "working" flow isn't just a mock answering.
|
||||||
|
Include the reseed step for when the time-relative scenarios age out.
|
||||||
|
|
||||||
|
### 4. Extend the pre-commit hook
|
||||||
|
|
||||||
|
Read the existing hook first and match its style. Add **warnings, not blocks** — a hook that blocks
|
||||||
|
commits gets bypassed, and then it protects nothing.
|
||||||
|
|
||||||
|
Warn when:
|
||||||
|
|
||||||
|
- files under `server/src/**/Controllers/**` or `**/Handlers/**` changed but nothing under
|
||||||
|
`docs/integration/` did → *"API surface changed — update `docs/integration/domains/…` and refresh
|
||||||
|
the OpenAPI snapshot."*
|
||||||
|
- `client/src/services/**` changed but no `docs/integration/` or `docs/flows/` change →
|
||||||
|
*"a service domain changed — does a flow doc need updating?"*
|
||||||
|
- a file under `docs/status/` or `docs/flows/` is committed with a `Last verified:` date more than
|
||||||
|
~30 days old → *"this doc claims to be verified as of <date>."*
|
||||||
|
- root `CLAUDE.md`, `client/CLAUDE.md`, or `server/CLAUDE.md` exceeds its line budget →
|
||||||
|
*"the rulebook is regrowing; move reference material to `docs/rules/`."*
|
||||||
|
|
||||||
|
Document each warning in `.githooks/README.md` and in `docs/rules/documentation.md`.
|
||||||
|
|
||||||
|
### 5. Stamp the freshness convention
|
||||||
|
|
||||||
|
Ensure every file under `docs/status/` and `docs/flows/` carries
|
||||||
|
`> Last verified: <date> against <commit>` as its second line, and that
|
||||||
|
`docs/rules/documentation.md` names exactly which files must carry it and who updates it.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- [ ] No sentence in `frontend-designer` describes pre-iteration-1/2 behaviour — spot-check the
|
||||||
|
layout, icon, and form sections against real components.
|
||||||
|
- [ ] No skill restates a rule that `docs/rules/` owns; each links instead.
|
||||||
|
- [ ] The three skills' trigger descriptions don't overlap (a task should match exactly one).
|
||||||
|
- [ ] The pre-commit hook runs and its new warnings fire on a deliberate test commit — and **never**
|
||||||
|
block one.
|
||||||
|
- [ ] Every `docs/status/` and `docs/flows/` file has a `Last verified:` line.
|
||||||
|
|
||||||
|
## Definition of done
|
||||||
|
|
||||||
|
The skills describe the app that exists, and the next time someone changes an endpoint without
|
||||||
|
touching a doc, something says so.
|
||||||
|
|
||||||
|
## Handoff
|
||||||
|
|
||||||
|
_(filled in by the agent that runs this phase)_
|
||||||
Reference in New Issue
Block a user