150 lines
7.8 KiB
Markdown
150 lines
7.8 KiB
Markdown
# 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)_
|