Files
baya-monorepo/docs/_plan/phase-2-integration.md
T
2026-07-29 22:46:38 +03:30

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

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 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 / :HashKeyflag 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)