7.8 KiB
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 intodocs/_plan/open-contradictions.md.- dev/contracts/ — 18 domain files + 2 convention files + the stale snapshot.
- 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 — which seams are mocked.
- DEPLOY.md · docker-compose.yml · deploy/Caddyfile
- telegram-otp-bot/README.md + 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'sApiResultenvelope, 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 — 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 underdata,requestIdis a W3C trace id (refinement-phase-9). Client unwraps inclientFetch/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 bindspageSizecase-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,
/meandme/select_role, role hydration. - Idempotency: which endpoints require
Idempotency-Keyand 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'sNEXT_PUBLIC_*IdentitySettings:SecretKey/:EncryptkeySeams: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.jsonappears in exactly onedocs/integration/domains/*.md, or is listed in that file's "undocumented, intentionally" section with a reason. - No
phantomendpoints remain undeclared — each is either removed from the doc or listed as "planned, not built" with a backlog reference for Phase 4. config-matrix.mdaccounts for every key inappsettings.Production.json,docker-compose.yml, and both.envfiles — diff mechanically, don't eyeball.DEPLOY.mdno longer instructs anyone to useuser-secrets.index.mdfits 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)