add build development phases
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
# Agent Operating Rules — read this before every phase
|
||||
|
||||
> **You are an autonomous engineer working one phase of the Balinyaar build.** This file is the
|
||||
> contract for *how* you work. Every `backend-phase-N.md` / `frontend-phase-N-bM.md` links here and
|
||||
> assumes you have read it. Do not skip it. Do not be lazy. Build production-quality, scalable,
|
||||
> maintainable code — not a demo.
|
||||
|
||||
---
|
||||
|
||||
## 0. The golden behaviours
|
||||
|
||||
1. **No laziness, ever.** Implement the whole phase scope. No `// TODO: implement later`, no stubbed
|
||||
handlers that return fake data *unless the phase explicitly says "mock this behind a seam"*, no
|
||||
"left as an exercise". If you mock something, you mock it **behind a dependency-injected interface**
|
||||
and you record it in the mock registry (§7) — that is the *only* sanctioned form of "not real yet".
|
||||
2. **Read before you write.** Complete the **Required reading** list in your phase file *first*. The
|
||||
business rules are decisions, not guesses — the product docs are the source of truth. Inferring a
|
||||
rule from code instead of reading the doc is a defect.
|
||||
3. **Don't duplicate prior work.** Each phase lists **"What already exists"** with links to the prior
|
||||
phases that built it. Extend it; never re-create it. If you need to change something a prior phase
|
||||
built, change it in place and note it in your report.
|
||||
4. **Stay in your project.** Backend phases touch `server/` (+ `dev/contracts`, `dev/shared-working-context/backend`). Frontend phases touch `client/` (+ `dev/shared-working-context/frontend`). Do **not** edit the other side's app code — coordinate through contracts and the handoff (§6).
|
||||
5. **Match the surrounding style.** Mirror existing patterns; introduce no new ones without reason.
|
||||
The per-project `CLAUDE.md` (and server `CONVENTIONS.md`) are non-negotiable — follow them exactly.
|
||||
6. **Leave the tree green.** Your phase is not done until the project's own quality gate passes
|
||||
(§4) and the Definition of Done ([definition-of-done.md](definition-of-done.md)) is fully met.
|
||||
7. **Think about the future.** Every decision should consider scalability and maintenance: indexing,
|
||||
pagination, caching, idempotency, re-render cost, bundle size, the seam that lets a mock become real.
|
||||
See the conventions checklists ([backend](backend-conventions-checklist.md) ·
|
||||
[frontend](frontend-conventions-checklist.md)).
|
||||
|
||||
---
|
||||
|
||||
## 1. The canonical sources of truth (know where each rule lives)
|
||||
|
||||
| You need… | Read |
|
||||
| --- | --- |
|
||||
| Repo-wide rules, two-project layout | root [`CLAUDE.md`](../../../CLAUDE.md) |
|
||||
| Backend engineering rules | [`server/CLAUDE.md`](../../../server/CLAUDE.md) + [`server/CONVENTIONS.md`](../../../server/CONVENTIONS.md) |
|
||||
| Frontend engineering rules | [`client/CLAUDE.md`](../../../client/CLAUDE.md) |
|
||||
| Frontend design/brand rules | the **frontend-designer** skill (invoke it for any UI work) |
|
||||
| Product / business / data-model / payments truth | [`product/`](../../../product/) (start at `product/index.md`) |
|
||||
| The whole build plan + order | [`dev/phases/README.md`](../README.md) |
|
||||
| Cross-project API/flow contracts | [`dev/contracts/`](../../contracts/README.md) |
|
||||
| What the other agent has handed you | [`dev/shared-working-context/`](../../shared-working-context/README.md) |
|
||||
|
||||
**Precedence when two sources seem to conflict:** product docs (business truth) → the relevant
|
||||
`CLAUDE.md`/`CONVENTIONS.md` (engineering truth) → this file → the phase file's specifics. If a real
|
||||
conflict remains, do the safe thing, implement it, and flag it in your report — never silently guess
|
||||
on money, auth, tenancy, or clinical-data rules.
|
||||
|
||||
---
|
||||
|
||||
## 2. Phase lifecycle (do these in order)
|
||||
|
||||
1. **Orient.** Read this file, your phase file end-to-end, and the **Required reading** it lists.
|
||||
Skim the prior-phase reports in `dev/shared-working-context/reports/` for what changed recently.
|
||||
2. **Plan.** Restate the scope to yourself; list the entities/endpoints/screens you will build and the
|
||||
order. Identify every external dependency you must mock and the seam it sits behind.
|
||||
3. **Build.** Implement the full scope following the project conventions and the checklists. Wire mocks
|
||||
behind DI. Keep commits/changes coherent.
|
||||
4. **Self-verify.** Run the project's quality gate (§4) and the phase's **"How to test"** steps. Fix
|
||||
everything. Re-read your own diff as a reviewer would.
|
||||
5. **Document & hand off.** Update the project docs (§5), write the contract(s) (§6, backend), write
|
||||
the phase report and update the mock registry (§7), write the handoff note (§6), and save memory (§8).
|
||||
6. **Declare done** only when the Definition of Done is fully satisfied.
|
||||
|
||||
---
|
||||
|
||||
## 3. Best-practice mandate (this is graded, not optional)
|
||||
|
||||
**Backend** (full list in [backend-conventions-checklist.md](backend-conventions-checklist.md)):
|
||||
Clean-Architecture boundaries (Domain → Application → Infrastructure → API; dependencies point inward);
|
||||
CQRS via `martinothamar/Mediator` (`ISender`/`ICommand`/`IQuery`, `internal sealed` handlers,
|
||||
`OperationResult` for expected failures — never throw); `AsNoTracking()` + `Select()` projection on
|
||||
every read; pagination on every list; one `IEntityTypeConfiguration<T>` per entity; soft-delete query
|
||||
filters; audit fields via the SaveChanges interceptor; **caching** read-heavy/config data behind the
|
||||
cache seam; **idempotency + (where stated) Redis distributed locks** on the money path; **money is IRR
|
||||
`BIGINT`, no floats, ever**; validate at the boundary with FluentValidation; `CancellationToken`
|
||||
through every async call; zero new build warnings; no dead code; comment the *why*.
|
||||
|
||||
**Frontend** (full list in [frontend-conventions-checklist.md](frontend-conventions-checklist.md)):
|
||||
Respect the RSC/client boundary; **fetch only through `clientFetch`/`serverFetch`** in
|
||||
`services/{domain}`; use **TanStack Query with sensible `queryKey`s, `staleTime`, and cache
|
||||
invalidation** so you never re-fetch data you already have; prevent needless re-renders (stable
|
||||
references, `select`, colocated state, memo only where it pays); **MUI primitives stay MUI** (Button,
|
||||
Avatar, Paper… — never re-implement a root component), but **compose shareable mid-level components at
|
||||
the right shared level** (not buried in a page) when they'll be reused; every user-visible string is an
|
||||
i18n key in **both** `en.json` and `fa.json`; colours from `tokens.css`; RTL-correct; `npm run check`
|
||||
green; no dead code.
|
||||
|
||||
If a phase's work could be done quickly-but-wrong or properly-but-slower, **do it properly.**
|
||||
|
||||
---
|
||||
|
||||
## 4. The quality gate (run before declaring done)
|
||||
|
||||
- **Backend:** `dotnet build Baya.sln` (zero new warnings) **and** `dotnet test Baya.sln` (all pass).
|
||||
Add the handler/integration tests your phase introduces. A reachable SQL Server is required to run.
|
||||
- **Frontend:** `npm run check` (type + lint) **and** `npm run test:ci` if you touched/added a shared
|
||||
component. Keep `en.json`/`fa.json` in sync.
|
||||
|
||||
A phase that doesn't pass its own gate is **not done**, regardless of how complete the code looks.
|
||||
|
||||
---
|
||||
|
||||
## 5. Update the project documents (in the same change)
|
||||
|
||||
Keep the docs honest — stale instructions are worse than none. When your phase changes how something
|
||||
works or what the architecture is:
|
||||
|
||||
- **Architecture map:** if you add/rename/remove a project, layer, route group, provider, domain folder,
|
||||
or a cross-boundary seam, update the canonical map in the **same** change — server: the *Project map*
|
||||
in `server/CLAUDE.md`; client: the *Project Structure* tree in `client/CLAUDE.md`; repo-level: the
|
||||
*Repository layout* in root `CLAUDE.md`.
|
||||
- **Product docs:** if you discover or decide a business rule that the `product/` docs don't yet
|
||||
capture (or that drifts from them), update the relevant `product/**.md` (and regenerate the HTML view
|
||||
per `product/CLAUDE.md` guidance if you changed Markdown). Do not invent rules — record decisions.
|
||||
- **Conventions:** if you establish a new reusable pattern (a seam, a base class, a hook family), add a
|
||||
short note to the relevant `CLAUDE.md`/`CONVENTIONS.md` so the next phase reuses it.
|
||||
|
||||
Do **not** re-introduce removed starter/template scaffolding while editing docs.
|
||||
|
||||
---
|
||||
|
||||
## 6. Contracts & the parallel-agent handoff (how the two sides stay in sync)
|
||||
|
||||
Backend and frontend phases are designed to run **as two independent agents in parallel**. They never
|
||||
edit the same files. They coordinate through two folders:
|
||||
|
||||
- **`dev/contracts/`** — *backend-owned, frontend-read.* When a backend phase ships an API, it writes
|
||||
the contract: a per-domain doc under `dev/contracts/domains/<domain>.md` (request/response shapes,
|
||||
routes, status codes, enums, examples) **and** ensures the server's `swagger.json` snapshot is
|
||||
published per `dev/contracts/openapi/README.md`. Follow the envelope/format rules in
|
||||
`dev/contracts/conventions/`. The frontend treats these as the source of truth for types — it does
|
||||
**not** guess shapes.
|
||||
- **`dev/shared-working-context/`** — *the running handoff.* Strict lane ownership so parallel agents
|
||||
never collide:
|
||||
- **Backend writes only:** `shared-working-context/backend/STATUS.md` (append your phase summary),
|
||||
`shared-working-context/backend/handoff/after-backend-phase-N.md` (one new file per phase — what
|
||||
the frontend can now build, which endpoints/contracts are live, what's mocked), and your report +
|
||||
the mock registry in `shared-working-context/reports/`.
|
||||
- **Frontend writes only:** `shared-working-context/frontend/STATUS.md`, and
|
||||
`shared-working-context/frontend/requests/for-backend.md` (append contract gaps / shape requests —
|
||||
the backend agent reads this, you never edit backend files), and your frontend report in
|
||||
`shared-working-context/reports/`.
|
||||
- **Never edit a file the other lane owns.** If the frontend needs a contract change, it *requests*
|
||||
it; the backend *delivers* it in a subsequent change. This is what makes parallel runs safe.
|
||||
|
||||
When mock data is needed on the frontend before its backend phase is merged, build it behind the same
|
||||
`services/{domain}` seam (a mock `clientApi`) and record it in your frontend report so it's swapped out
|
||||
cleanly once the real endpoint lands.
|
||||
|
||||
---
|
||||
|
||||
## 7. The mock / integration report (mandatory, saved to a file — not just chat)
|
||||
|
||||
Every phase that mocks or defers an external service **must**:
|
||||
|
||||
1. Put the mock behind a **DI-registered interface** (a "seam") with a real-shaped contract, so the real
|
||||
implementation is a drop-in later. Mock and real both implement the same interface; selection is by
|
||||
configuration/registration, never by `if (mock)` scattered in handlers.
|
||||
2. Append an entry to **`dev/shared-working-context/reports/mocks-registry.md`** with: the seam
|
||||
(interface name + file), what is faked, why, the config keys it reads, and **step-by-step how to make
|
||||
it real** (which provider, which package, which settings, which methods to implement, what to test).
|
||||
3. Write a **per-phase report** at `dev/shared-working-context/reports/<backend|frontend>-phase-N-report.md`
|
||||
covering: *what was built*, *what is now testable and exactly how*, *what is mocked / waiting on a real
|
||||
service*, *contracts produced/consumed*, *follow-ups for later phases*. (See
|
||||
[reports/README.md](../../shared-working-context/reports/README.md) for the template.)
|
||||
|
||||
Services that will be mocked across the chain and the seam each lives behind (define once, reuse):
|
||||
SMS/OTP delivery (`ISmsSender`), object storage / MinIO/S3 (`IObjectStorage`), cache/Redis
|
||||
(`ICacheService`), distributed locks/Redis (`IDistributedLock`), search/Elasticsearch (`INurseSearch`),
|
||||
PSP card gateway (`IPaymentProvider`), settlement-sharing/تسهیم (`ISettlementSplitProvider`), BNPL
|
||||
(`IBnplProvider`), bank transfer PAYA/SATNA (`IBankTransferProvider`), webhook verification
|
||||
(`IWebhookVerifier`), Shahkar (`IShahkarVerifier`), identity KYC/liveness (`IIdentityKycProvider`),
|
||||
credential/license check (`ICredentialVerifier`), IBAN ownership (`IBankAccountOwnershipVerifier`),
|
||||
geocoding/maps (`IGeocoder`), مودیان e-invoicing (`IMoadianClient`), AI review moderation
|
||||
(`IReviewModerationService`), field encryption/KMS (`IFieldEncryptor`), notification dispatch
|
||||
(`INotificationDispatcher`). The exact phase that *introduces* each seam is in the roadmap; later phases
|
||||
*reuse* the seam, they do not redefine it.
|
||||
|
||||
---
|
||||
|
||||
## 8. Write memory & context when done
|
||||
|
||||
After the work passes its gate, record what a future agent would need and could not cheaply re-derive:
|
||||
|
||||
- **Persistent memory** (the Claude memory dir, per the repo's memory instructions): save/update a
|
||||
`project`-type memory note for any non-obvious decision, new seam, or gotcha this phase introduced,
|
||||
and add a one-line pointer to `MEMORY.md`. Don't record what the code/docs already make obvious.
|
||||
- **Working context:** the handoff note (§6) and the phase report (§7) — these are the durable record
|
||||
the *other* agent and the *next* phase rely on.
|
||||
|
||||
---
|
||||
|
||||
## 9. When you're genuinely blocked
|
||||
|
||||
Some things are intentionally out of scope and must be **mocked, not invented**: real PSP/BNPL
|
||||
connections, the Shahkar/MoH/INO/criminal-record vendors, MinIO/S3 credentials, the مودیان enrollment.
|
||||
If you reach one, implement the seam + a faithful mock + the registry entry, and move on — do not stall
|
||||
and do not fabricate a real integration. If a *business* rule is truly undecided (the product docs say
|
||||
"open question"), pick the safe default, implement it config-drivenly where possible, and flag it in
|
||||
your report for the human to confirm. Never block the chain on an external unknown.
|
||||
@@ -0,0 +1,59 @@
|
||||
# Backend conventions checklist (quick reference)
|
||||
|
||||
The authoritative rules are [`server/CLAUDE.md`](../../../server/CLAUDE.md) and
|
||||
[`server/CONVENTIONS.md`](../../../server/CONVENTIONS.md). This is a tick-list to keep handy while you
|
||||
build. If anything here seems to conflict with those files, **those files win**.
|
||||
|
||||
## Architecture
|
||||
- [ ] Clean Architecture respected: Domain → Application → Infrastructure → API; **dependencies point
|
||||
inward**. Domain references nothing; Application references only Domain; Infrastructure/API
|
||||
implement Application contracts. Never reference Infrastructure/API from Domain/Application.
|
||||
- [ ] New cross-layer dependency or project/folder ⇒ update the **Project map** in `server/CLAUDE.md`.
|
||||
- [ ] New infrastructure is registered via a `ServiceConfiguration/` extension method called from
|
||||
`Program.cs` — never inline in `Program.cs`.
|
||||
|
||||
## CQRS / features
|
||||
- [ ] Feature lives in `Baya.Application/Features/<Area>/{Commands|Queries}/<Name>/`.
|
||||
- [ ] Requests are `record`; handlers are `internal sealed`; one handler per request.
|
||||
- [ ] **Never throw for expected failures** — return `OperationResult.SuccessResult/FailureResult/NotFoundResult`.
|
||||
- [ ] Contracts the handler needs are interfaces in `Application/Contracts/`, implemented in Infrastructure.
|
||||
- [ ] Input-bearing commands have a FluentValidation validator (picked up by `ValidateCommandBehavior`).
|
||||
|
||||
## Persistence (EF Core)
|
||||
- [ ] Read queries use `AsNoTracking()` **and** project with `.Select(...)` to a DTO — never hydrate
|
||||
entities to map them. Mapping (Mapster) happens in the handler after the query.
|
||||
- [ ] Every unbounded list is **paginated** (`Skip`/`Take`); no unbounded `ToListAsync()`.
|
||||
- [ ] Access the DB via `IUnitOfWork` in handlers; commit once per command (`CommitAsync`).
|
||||
- [ ] One `IEntityTypeConfiguration<T>` per entity in `Persistence/Configuration/<Area>Config/`.
|
||||
- [ ] Soft-deletable entities declare a global query filter (`!IsDeleted` / `deleted_at IS NULL`).
|
||||
- [ ] Audit fields (`CreatedAt/ModifiedAt/CreatedById/ModifiedById`) are set by the SaveChanges
|
||||
interceptor via `ICurrentUser` — handlers don't pass them.
|
||||
- [ ] Encrypted PII columns (phone, national_id, IBAN, addresses, clinical notes) go through the field
|
||||
encryptor seam — never stored or logged in plaintext.
|
||||
|
||||
## Performance, caching, money, idempotency
|
||||
- [ ] Read-heavy/config/reference data is cached behind the cache seam with sensible invalidation;
|
||||
`platform_configs` values are read through the typed config accessor (cached), not hardcoded.
|
||||
- [ ] **Money is IRR `BIGINT` — no floats, anywhere.** Toman conversion happens only inside a provider
|
||||
adapter at its boundary. The three booking amounts always satisfy
|
||||
`gross = commission + payout`.
|
||||
- [ ] Money-path writes are **idempotent** (webhook dedup on the unique external-event key; filtered
|
||||
unique on succeeded transaction; forward-only state machines) and, where the phase says so, guarded
|
||||
by a Redis **distributed lock** — with the DB constraint as the authoritative backstop.
|
||||
- [ ] `ledger_entries` is append-only and balanced (Σdebit = Σcredit per `transaction_group_id`).
|
||||
|
||||
## API surface
|
||||
- [ ] Controllers are `sealed`, inherit `BaseController`, inject `ISender`, return
|
||||
`base.OperationResult(...)` — never `Ok()/BadRequest()/NotFound()` directly. (Note: the baseline
|
||||
has **no** controllers yet — REST is introduced in an early phase; follow that pattern thereafter.)
|
||||
- [ ] Routes use `[controller]`/`[action]` tokens (snake_case transformer); pass `CancellationToken`.
|
||||
- [ ] Authorize with the narrowest fitting policy; auth/OTP/refund/payout-sensitive endpoints are
|
||||
rate-limited.
|
||||
- [ ] The endpoint's contract is published to `dev/contracts/` (see operating-rules §6).
|
||||
|
||||
## Quality
|
||||
- [ ] `async`/`await` all the way; `CancellationToken` threaded through; no `.Result`/`.Wait()`/`async void`.
|
||||
- [ ] Package versions only in `Directory.Packages.props`.
|
||||
- [ ] Handler unit tests (NSubstitute) + at least one `WebApplicationFactory` integration test per new
|
||||
feature area (happy path, 401, validation 400).
|
||||
- [ ] `dotnet build` zero new warnings; `dotnet test` green; no dead code.
|
||||
@@ -0,0 +1,43 @@
|
||||
# Definition of Done — applies to every phase
|
||||
|
||||
A phase is **done** only when *all* of the following are true. Each phase file adds its own
|
||||
phase-specific criteria on top of this shared baseline.
|
||||
|
||||
## Code
|
||||
- [ ] The full scope in the phase file is implemented — no laziness, no unsanctioned stubs. Anything
|
||||
not real is mocked **behind a DI seam** and recorded in the mock registry.
|
||||
- [ ] It follows the project conventions exactly (server `CLAUDE.md` + `CONVENTIONS.md`, or client
|
||||
`CLAUDE.md` + the frontend-designer skill) and the relevant conventions checklist.
|
||||
- [ ] No dead code (unused vars/imports/usings/params/members). Comments explain *why*, not *what*.
|
||||
- [ ] Best practices honoured: (backend) clean-arch boundaries, projected/paginated reads, caching where
|
||||
it pays, idempotency/locks on the money path, IRR `BIGINT` money, validation at the boundary;
|
||||
(frontend) RSC/client boundary, query caching + no needless refetch, minimal re-renders, MUI
|
||||
primitives reused, i18n in both locales, tokens-based colours, RTL-correct.
|
||||
|
||||
## Gate
|
||||
- [ ] **Backend:** `dotnet build Baya.sln` has zero new warnings **and** `dotnet test Baya.sln` passes,
|
||||
including the tests this phase adds.
|
||||
- [ ] **Frontend:** `npm run check` passes **and** `npm run test:ci` passes if a shared component was
|
||||
touched/added; `en.json` and `fa.json` are in sync.
|
||||
|
||||
## Documentation
|
||||
- [ ] The relevant architecture map is updated in the same change (server *Project map* / client
|
||||
*Project Structure* / root *Repository layout*) if the structure changed.
|
||||
- [ ] Any business rule discovered/decided is reflected in the `product/` docs (no invented rules).
|
||||
- [ ] New reusable patterns/seams are noted in the relevant `CLAUDE.md`/`CONVENTIONS.md`.
|
||||
|
||||
## Contracts & handoff
|
||||
- [ ] **Backend:** the API contract for what shipped is written to `dev/contracts/domains/<domain>.md`
|
||||
and the `swagger.json` snapshot is published per `dev/contracts/openapi/README.md`.
|
||||
- [ ] **Frontend:** types/services are derived from the published contract (not guessed); any contract
|
||||
gap is appended to `dev/shared-working-context/frontend/requests/for-backend.md`.
|
||||
- [ ] The handoff note `dev/shared-working-context/<lane>/...` is written (backend: a new
|
||||
`handoff/after-backend-phase-N.md`; both lanes: a STATUS append).
|
||||
|
||||
## Reporting & memory
|
||||
- [ ] The per-phase report `dev/shared-working-context/reports/<lane>-phase-N-report.md` is written:
|
||||
what was built, **what is now testable and exactly how**, what is mocked + how to make it real,
|
||||
contracts produced/consumed, follow-ups.
|
||||
- [ ] The mock registry `dev/shared-working-context/reports/mocks-registry.md` is updated for every
|
||||
seam this phase mocked/touched.
|
||||
- [ ] Persistent memory is saved for any non-obvious decision/seam/gotcha, with a `MEMORY.md` pointer.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Frontend conventions checklist (quick reference)
|
||||
|
||||
The authoritative rules are [`client/CLAUDE.md`](../../../client/CLAUDE.md) and the **frontend-designer**
|
||||
skill (invoke it for any visual work). This is a tick-list. If anything here seems to conflict with
|
||||
those, **they win**.
|
||||
|
||||
## Boundaries & structure
|
||||
- [ ] Never add a layout above `[locale]`; `src/app/[locale]/layout.tsx` is the root layout.
|
||||
- [ ] Respect the RSC/client boundary: no `next/headers`, `next-intl/server`, or `@/lib/cookies/server`
|
||||
in client components; no `@/lib/cookies/client` in an RSC.
|
||||
- [ ] New route group / provider / top-level `src/` folder ⇒ update the **Project Structure** tree in
|
||||
`client/CLAUDE.md`.
|
||||
|
||||
## Data fetching & caching (prevent extra fetches and re-renders)
|
||||
- [ ] Fetch **only** through `clientFetch`/`serverFetch` (`@/lib/api`); domain calls live in
|
||||
`src/services/{domain}/apis/`. Never raw `fetch()`.
|
||||
- [ ] Server state is **TanStack Query**: a `keys.ts` factory per domain, deliberate `staleTime`/`gcTime`,
|
||||
and **cache invalidation on mutation** (`invalidateQueries`/`setQueryData`) so you never refetch
|
||||
data you already hold. Prefer prefetch/`initialData` from RSC where it removes a client round-trip.
|
||||
- [ ] One hook per file (`use{Action}.ts`), `useQuery`/`useMutation`. Don't toast 401/403/5xx in hooks
|
||||
(the fetch layer already does) — only domain-specific 4xx messages.
|
||||
- [ ] Minimise re-renders: stable references (`useCallback`/`useMemo` only where it pays), `select` to
|
||||
subscribe to slices, colocate state low, lift only when shared. Don't put fast-changing state in
|
||||
a high context provider.
|
||||
|
||||
## UI composition
|
||||
- [ ] **Concrete MUI primitives stay MUI** — use `Button`, `Avatar`, `Paper`, `TextField`, etc. (or the
|
||||
existing `App*` wrappers); never invent a new root-level Button/Avatar.
|
||||
- [ ] **Composite/shareable components** (built from primitives, reused in >1 place — a nurse card, an
|
||||
OTP input, a price-breakdown, a step header) live at the right **shared** level (`src/components/…`),
|
||||
not inline in a page or buried in a leaf. A component imported from >1 place gets a co-located
|
||||
`*.test.tsx`.
|
||||
- [ ] Page-only, never-reused composition can stay in the page.
|
||||
|
||||
## i18n, theme, direction
|
||||
- [ ] Every user-visible string is a key in **both** `messages/en.json` and `messages/fa.json` (in sync).
|
||||
`fa` is default and **RTL** — design RTL-first; verify mirroring.
|
||||
- [ ] Colours come from `tokens.css` (`var(--bal-…)` / brand tokens), never hardcoded in `sx`. Use the
|
||||
pre-built `APP_THEME_LTR/RTL`; never `createTheme()` in a component.
|
||||
- [ ] MUI **v9** API only (`sx={{ mb: 4 }}`, no v5/v6-only props).
|
||||
|
||||
## Quality
|
||||
- [ ] Magic strings → named constants (`src/constants/` or a colocated `constants.ts`).
|
||||
- [ ] Cookies/app state only through the cookie manager; never `document.cookie`/`localStorage` for auth.
|
||||
- [ ] No dead code (unused vars/imports are lint **errors**). Comment the *why*, not the *what*.
|
||||
- [ ] `npm run check` green; `npm run test:ci` green when a shared component changed.
|
||||
- [ ] Types come from the published contract in `dev/contracts/` — don't guess server shapes; if a shape
|
||||
is missing, append a request to `dev/shared-working-context/frontend/requests/for-backend.md` and
|
||||
mock behind the `services/{domain}` seam meanwhile.
|
||||
@@ -0,0 +1,63 @@
|
||||
# Phase prompt template (the skeleton every phase file follows)
|
||||
|
||||
> This is the shape of every `backend-phase-N.md` and `frontend-phase-N-bM.md`. It exists so the
|
||||
> chain is uniform and an agent always knows where to find each thing. When you (a planning author)
|
||||
> create or edit a phase file, fill every section. When you (an executing agent) run a phase, expect
|
||||
> every section to be present.
|
||||
|
||||
---
|
||||
|
||||
```
|
||||
# <Backend|Frontend> Phase N — <Title>
|
||||
|
||||
> One-paragraph mission: what this phase delivers and why it matters to the product.
|
||||
> **Track:** backend|frontend · **Depends on:** <prior phases / backend phase bM> · **Unlocks:** <what comes next>
|
||||
> **Before you start, read [_shared/agent-operating-rules.md](../_shared/agent-operating-rules.md).** It is not optional.
|
||||
|
||||
## 1. Context — where this sits
|
||||
- Where we are in the chain; the 2–3 sentence product framing.
|
||||
- **What already exists (do not rebuild):** bullet list linking the prior phases + the baseline
|
||||
facts (from `dev/shared-working-context/...` and the project state).
|
||||
|
||||
## 2. Required reading (do this first)
|
||||
- Exact product docs to read (with paths) and *why* each matters.
|
||||
- Exact code areas to read (existing patterns to mirror).
|
||||
- Contracts to consume (frontend) / prior handoff notes.
|
||||
|
||||
## 3. Scope — build this
|
||||
- The precise, enumerated deliverables: entities/migrations, commands/queries, endpoints
|
||||
(backend); screens/flows, services/hooks, components (frontend). Each with enough detail to build
|
||||
without guessing. Tag anything (DEFERRED) that is explicitly out of scope.
|
||||
|
||||
## 4. Mocks & seams in this phase
|
||||
- Which external services are mocked, the interface each sits behind, what the mock returns, and the
|
||||
pointer to record it in the mock registry. (Reuse seams introduced earlier; only *introduce* the
|
||||
ones this phase owns.)
|
||||
|
||||
## 5. Critical rules you must not get wrong
|
||||
- The domain-specific invariants (money correctness, idempotency, tenancy, two-stage clinical
|
||||
disclosure, same-gender matching, RSC boundary, re-render/caching, etc.) relevant to this phase.
|
||||
|
||||
## 6. Definition of Done
|
||||
- The phase-specific acceptance criteria, on top of the shared
|
||||
[definition-of-done.md](../_shared/definition-of-done.md).
|
||||
|
||||
## 7. How to test (what a human can verify after this phase)
|
||||
- Concrete, runnable steps (endpoints to curl / Swagger calls / screens to click) and the expected
|
||||
result for each. This becomes the "what can be tested" section of your report.
|
||||
|
||||
## 8. Hand off & document (close the phase)
|
||||
- Docs to update (which CLAUDE.md / product doc).
|
||||
- Contract(s) to write (backend) / consume (frontend).
|
||||
- The handoff note + report files to write, and the memory to save. (Mechanics in operating-rules §5–8.)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Authoring notes
|
||||
|
||||
- Keep each phase **self-contained**: an agent should be able to execute it having read only the phase
|
||||
file + the files it links. Link generously to prior phases and to `product/` — don't restate them.
|
||||
- Phases are **vertical slices** where possible (entity → handler → endpoint → contract for backend;
|
||||
service → hook → screen for frontend) so each ends in something testable.
|
||||
- Never let a phase silently expand scope. If something belongs to a later phase, say so and link it.
|
||||
Reference in New Issue
Block a user