doc clean up phase 2

This commit is contained in:
hamid
2026-07-30 12:49:46 +03:30
parent c889c46110
commit c841bded26
36 changed files with 2970 additions and 51 deletions
+133 -2
View File
@@ -145,5 +145,136 @@ file, and a deploy question is answered by `topology.md` + `config-matrix.md` wi
## 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)_
> Run 2026-07-30 against commit `d3ec723`. **All verification items pass**, checked mechanically
> (script in the session scratchpad, results reproduced below).
### What shipped
```
docs/integration/
index.md 153 lines — the whole seam, one screen and a half
api-contract.md envelope · casing · status codes · auth · pagination · idempotency · money · enums · rate limits
config-matrix.md every key in both appsettings, docker-compose, 3 .env files, the bot, Caddy, CORS
topology.md mermaid graph + a 10-edge table + ports + startup order + the local variant
domains/
index.md the census, the route-shape exceptions, the enum map, what-replaced-what
<22 files> one per client services/ domain, 1:1
openapi/README.md updated: C-9 resolved, the servers-block provenance wrinkle recorded
```
Also updated: `DEPLOY.md` (links topology + config-matrix; states there is no `appsettings.Production.json`
so step 2 of "Going to Production" is a *create*), `docs/README.md` (integration → **written**),
`dev/contracts/README.md` + `openapi/README.md` + `domains/messaging.md` (moved/merged banners).
### Verification
| Item | Result |
| --- | --- |
| Every swagger path declared in exactly one `domains/*.md` | **178/178**, 0 unreferenced, 0 duplicated |
| Operation census adds up | 186 = 184 domain + 2 `ping` in `api-contract.md` |
| Every phantom declared with a reason + REQ | **24/24** |
| `config-matrix.md` accounts for every key | Diffed mechanically; 5 gaps found and written up |
| `DEPLOY.md` no longer instructs `user-secrets` | Pass — it already documented the removal; now also links the new files |
| `index.md` fits a screen and a half | 153 lines |
| Every doc carries a `Last verified` stamp | 27/27 |
| No reference file over 400 lines | Pass |
| Relative links resolve | **216 checked, 0 broken** |
### Scope note
`api-contract.md` was **merged into `index.md`'s siblings as planned**, but the plan's `domains/` count of
22 was met by re-cutting the file set along the **client's** domain boundaries rather than the backend
phases the old 17 files used. That is what makes the mapping 1:1 and is why the file names changed.
`swagger.v1.json` was **not** re-fetched — Phase 0's 2026-07-29 snapshot is 1 day older than this run and
the server was not booted. Everything here is derived from that snapshot plus current source.
---
### Drift list — Phase 4's input
**A. Phantom endpoints (24).** The client's real API clients call 24 routes the server does not expose.
Each is declared in its domain file with its REQ. Grouped by REQ:
| REQ | Status | Phantoms | Domain |
| --- | --- | --- | --- |
| REQ-031 | deferred | 3 (`admin_roles/*`) | admin |
| **REQ-061** | **never filed** | 2 (`admin_users/search`, `/lookup`) | admin |
| REQ-022 | partial | 3 (`checkout_bnpl/options`, `/schedule`, `/wallet_installments`) | bnpl |
| REQ-032 | partial | 5 (`centers/me/*`, `partner-centers/{id}/nurses`) | partner-center |
| REQ-033 | partial | 1 (`centers/me/settlement`) | partner-center |
| REQ-064 | open | 1 (`centers/me/bookings/{id}`) | partner-center |
| REQ-034 | deferred | 3 (`admin_verifications` documents-url / approve / reject) | verification |
| REQ-035 | deferred | 3 (`admin_refunds` preview / approve / reject) | refunds |
| REQ-036 | deferred | 1 (`admin_payouts/{id}/transfer_reference`) | payouts |
| REQ-047 | open | 1 (`bookings/payment_history`) | payment |
| REQ-048 | open | 1 (`refunds/my`) | refunds |
| REQ-063 | open | 1 (`tickets/{id}/assign`) | tickets |
**Two are live 404s** because their domain's mock is off: `bookings/payment_history` (payment) and
`tickets/{id}/assign` (tickets). Both are guarded in the client, so neither is user-visible — but they are
reachable, not hypothetical.
**B. Five REQs whose filed status is wrong or narrower than reality.** Each was checked against the
swagger, not against another document. Phase 4 should re-triage these rather than copy the ledger.
| REQ | Filed as | Actually |
| --- | --- | --- |
| REQ-050 | open — "the list DTO carries neither field" | `BookingRequestListItemDto` **has `variantLabel`** (and `patientAge`). It lacks `variantPrice`/`variantPriceUnit` and the `status=answered` group filter. The REQ was verified against the *client type*, not the wire |
| REQ-063 | open — "no close/reopen/assign routes yet" | `tickets/{id}/close` and `/reopen` **exist and are wired**. Only `assign` is missing. `tickets/constants.ts` carries the stale reason |
| REQ-066 | open — needs an anonymous search read | `GET /search/nurses` **is already anonymous**. What is missing is the rate limit — `SearchController` has no `[EnableRateLimiting]` |
| REQ-067 | open — needs an anonymous profile read | `GET /nurses/{id}/profile` **is already anonymous**. What is missing is the privacy review |
| REQ-029 / REQ-030 | delivered | Correct — but `admin/constants.ts` still names them as reasons the admin mock is primary. The only live reasons are REQ-031 and REQ-061 |
**C. Client-side drifts (client work, not contract work).**
| # | Where | What |
| --- | --- | --- |
| 1 | `client/src/lib/api/types.ts` | `ApiEnvelope<T>` omits **`code`**, which the server sends and `clientFetch` already reads at runtime. Incomplete type, no defect |
| 2 | `client/src/services/admin/apis/clientApi.ts` | `pageQuery()` sends **`page_size`**; these endpoints declare `PageSize`. Model binding is case-insensitive, **not separator-insensitive**, so it binds nothing and every admin list silently gets the default page size. Latent until `USE_ADMIN_MOCK` flips |
| 3 | `client/src/services/bookingRequests/types.ts` | Marks `variantLabel` as client-augmented/absent; the server serves it. Widening the type would light up the redesigned inbox card today |
| 4 | `client/src/services/payouts/apis/clientApi.ts` | Comment says `NursePayoutHistoryDto` has no `failureReason`; **the wire has it** on all three payout read models |
| 5 | `client/src/services/tickets/constants.ts` | Says the backend has no close/reopen/assign; close and reopen exist (B, above) |
| 6 | `client/src/services/payouts/apis/clientApi.ts` | Sends `Idempotency-Key` on `admin_payouts` process/retry, where the server never reads it. Decorative, not harmful |
| 7 | `client/.env.sample` | Still `NEXT_PUBLIC_API_URL = https://localhost:5002` — the `https` half of **C-3**, in the file a fresh clone copies. `.env.development` is correct |
| 8 | `client/src/services/profiles/` | `POST customer_profiles/avatar` exists and is live; the client only wires the nurse route, so a customer cannot set a photo |
**D. Cross-side vocabulary asymmetry (1).** The client's `TicketAuthorRole` includes **`system`**;
`Entities/Messaging/TicketCodes.cs` defines only `customer`/`nurse`/`admin`. Safe on the reading side, but a
reader of the client types would wrongly conclude the server emits it. All other 17 shared vocabularies
match exactly, both directions.
**E. Route-shape exceptions (4).** `admin/partner-centers` (+ `/set-active`, `/sponsor-nurse`),
`admin/tickets`, `admin/reviews/…` and `internal/bookings/…` hardcode route strings instead of using the
`[controller]`/`[action]` tokens; three introduce hyphens, against the snake_case rule. **Because the route
also derives the dynamic-permission key, normalising them breaks permissions as well as URLs** — recorded,
not fixed.
**F. Config gaps (5).** Written up in
[config-matrix.md § What the diff found](../integration/config-matrix.md#what-the-diff-found):
`NEXT_PUBLIC_EVV_MOCK_GPS` and `NEXT_PUBLIC_VERSION` read but declared in no `.env`;
`OpenTelemetry:Otlp:Endpoint`, `Search:Backend` and `Seed:Admin*` read but set nowhere (and a bad
`Search:Backend` **throws at startup**); `.env.sample`'s stale `https`; the Telegram shared secret
duplicated across two files with nothing keeping them equal; no `appsettings.Production.json`.
**G. Unfiled REQ (1).** `ui-phase-11-report.md` records "REQ-061…064 appended" to the ledger. **Only
062/063/064 were.** Ten live client files cite REQ-061 for the admin user directory
(`admin_users/search`, `admin_users/lookup`). Phase 4 must **file it**, not assume it is tracked.
### Contradictions resolved here
**C-6** · **C-7** · **C-8** · **C-9** closed; **C-2** closed as a documentation decision; **C-3**'s
contract-layer half closed. Decisions recorded in
[open-contradictions.md § Resolved](open-contradictions.md#resolved).
### What Phase 3 should know
- The seam facts it needs are settled and mechanically verified: camelCase bodies, snake_case URLs, bearer
header (**not** cookie auth), money as a digit string outbound and an int64 inbound, `Idempotency-Key` on
exactly two endpoints, 20 anonymous operations.
- **`GET /api/v1/dev/last_otp/{phone}` is live on `api.balinyaar.ir`** — the deployment runs as Development
with a capture-safe SMS provider, so both gate conditions hold. Any flow doc that describes logging in
should say this is how you do it today, and that it is the deployment's largest exposure.
- C-4 (the `dev-certs` step) is confirmed dead: the API binds plain HTTP locally, so there is no certificate
to trust. C-5's two bring-up worlds are real and give **different data** — the committed dev config points
at the same remote, already-seeded database the deployment uses.