doc clean up phase 2
This commit is contained in:
@@ -153,8 +153,8 @@ stays small.
|
||||
| Phase | Status | Finished | Notes |
|
||||
| --- | --- | --- | --- |
|
||||
| 0 Inventory & scaffold | **done** | 2026-07-29 | 275 files surveyed (not ~260). OpenAPI refreshed — drift is **1 endpoint**, not a rewrite. 3 of 5 seeded contradictions were narrower than stated; see [open-contradictions.md](open-contradictions.md#corrections-to-the-seeded-list). Phase 4 owns 149 files |
|
||||
| 1 Rules consolidation | not started | | |
|
||||
| 2 Integration & dependency | not started | | |
|
||||
| 1 Rules consolidation | **done** | 2026-07-30 | Row reconstructed by phase 2 — phase 1 finished without updating it. Evidence: all 18 `docs/rules/**` files exist and are stamped `2026-07-30 against d3ec723`, `docs/README.md` marks the section **written**, and C-11 + R-1…R-6 are recorded as resolved-by-phase-1 |
|
||||
| 2 Integration & dependency | **done** | 2026-07-30 | 27 files under `docs/integration/`. All 186 operations assigned to exactly one of 22 domain files (1:1 with `client/src/services/`). **Main finding: 24 phantom endpoints** — the client↔swagger axis nobody had checked; 2 are live 404s. Also 5 mis-filed REQs, 1 never-filed REQ (**C-15**), 8 client drifts, 5 config gaps. Resolved C-2, C-6, C-7, C-8, C-9 + C-3's contract half |
|
||||
| 3 Flow atlas | not started | | |
|
||||
| 4 Backlog reconciliation | not started | | |
|
||||
| 5 Roadmap | not started | | |
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
> Opened 2026-07-29 by [phase 0](phase-0-inventory-and-scaffold.md), against commit `c99e3f4`.
|
||||
> **Phase 0 only finds these. It resolves none of them.**
|
||||
> Last updated 2026-07-30 by [phase 2](phase-2-integration.md), against commit `d3ec723`:
|
||||
> **C-2, C-6, C-7, C-8 and C-9 resolved**, C-3's contract-layer half resolved, **C-15 and C-16 added**.
|
||||
|
||||
Each row is *claim A* vs *claim B* with a location for both, and the phase that owns the resolution.
|
||||
When a phase resolves one, it moves the row to **Resolved** at the bottom with the decision, and — per
|
||||
@@ -17,18 +19,15 @@ written up as they actually are, with the evidence, in [§ Corrections to the se
|
||||
| # | Claim A | Claim B | Owner | Status |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| C-1 | **Set the crypto keys with `dotnet user-secrets`** — [manual-testing-plan.md:22](../../dev/post-phase/manual-testing-plan.md), [:233](../../dev/post-phase/manual-testing-plan.md) | **`user-secrets` is not used; `<UserSecretsId>` was removed so the store is not read** — [CLAUDE.md:90](../../CLAUDE.md), [DEPLOY.md:20](../../DEPLOY.md), [server/CLAUDE.md:70](../../server/CLAUDE.md), and `Baya.Web.Api.csproj` (no `UserSecretsId` element) | 3 | open |
|
||||
| C-2 | **Placeholder value is literally `SET_VIA_USER_SECRETS_OR_ENV`** — `server/src/API/Baya.Web.Api/appsettings.json` (6 occurrences), enforced by `StartupSecretsGuard` and by the pre-commit hook | **That store does not exist any more** (C-1's B side). The name instructs a reader to use a removed mechanism | 2 | open — naming only, behaviour is correct |
|
||||
| C-3 | **The server listens on `https://localhost:5002`** — [CLAUDE.md:62](../../CLAUDE.md), [:135](../../CLAUDE.md), [api-conventions.md:6](../../dev/contracts/conventions/api-conventions.md), [RUNBOOK.md:7](../../dev/post-phase/refinement/RUNBOOK.md), [:84](../../dev/post-phase/refinement/RUNBOOK.md), [:112](../../dev/post-phase/refinement/RUNBOOK.md), + 12 more | **It listens on `http://localhost:5002`** — `launchSettings.json:25` (`"applicationUrl": "http://localhost:5002"`), and `client/.env.development:20` (`NEXT_PUBLIC_API_URL = http://localhost:5002`) | 2 + 3 | **partly resolved by phase 1** — the three rule-file occurrences (root `CLAUDE.md` ×2, `server/CLAUDE.md`) now say `http`. `api-conventions.md` (phase 2) and `RUNBOOK.md` + the remaining 12 (phase 3) are untouched |
|
||||
| C-3 | **The server listens on `https://localhost:5002`** — [CLAUDE.md:62](../../CLAUDE.md), [:135](../../CLAUDE.md), [api-conventions.md:6](../../dev/contracts/conventions/api-conventions.md), [RUNBOOK.md:7](../../dev/post-phase/refinement/RUNBOOK.md), [:84](../../dev/post-phase/refinement/RUNBOOK.md), [:112](../../dev/post-phase/refinement/RUNBOOK.md), + 12 more | **It listens on `http://localhost:5002`** — `launchSettings.json:25` (`"applicationUrl": "http://localhost:5002"`), and `client/.env.development:20` (`NEXT_PUBLIC_API_URL = http://localhost:5002`) | 2 + 3 | **partly resolved by phases 1 + 2** — the three rule-file occurrences now say `http`; phase 2's [api-contract.md](../integration/api-contract.md) states `http` and banner-marks `api-conventions.md` as history. **Phase 2 also found a new occurrence the survey missed: `client/.env.sample:20`**, the file a fresh clone copies. `RUNBOOK.md` + the remaining occurrences are phase 3 |
|
||||
| C-4 | **RUNBOOK's `dotnet dev-certs https --trust` step is required**, because the browser would otherwise reject the API — [RUNBOOK.md:26](../../dev/post-phase/refinement/RUNBOOK.md) | **The API is plain HTTP locally** (C-3's B side), so there is no certificate to trust | 3 | open — likely a dead step |
|
||||
| C-5 | **Bring-up starts a local SQL Server in Docker on `localhost:1433`** — [RUNBOOK.md:18](../../dev/post-phase/refinement/RUNBOOK.md), [:35–48](../../dev/post-phase/refinement/RUNBOOK.md), [:63](../../dev/post-phase/refinement/RUNBOOK.md) | **The committed dev config points at a remote SQL Server** — `appsettings.Development.json` (`Server=87.107.152.16,1433`), and [manual-testing-plan.md:20](../../dev/post-phase/manual-testing-plan.md) calls the remote one "currently" the target | 3 | open — the two bring-up paths give *different worlds*: the remote DB is already seeded, a fresh local one is not |
|
||||
| C-6 | **`GET /api/v1/webhooks/payouts/{provider}` does not exist** — absent from `dev/contracts/openapi/swagger.v1.json` (frozen 2026-07-13) and from every `dev/contracts/domains/*.md` | **It exists** — present in the fresh snapshot `docs/integration/openapi/swagger.v1.json` (2026-07-29). See [§ OpenAPI drift](#openapi-drift) | 2 | open |
|
||||
| C-7 | **`GeneratePayoutBatchCommand`'s shape** per the 07-13 snapshot | **A different shape** in the 07-29 snapshot — the only schema of 339 whose definition changed | 2 | open |
|
||||
| C-8 | **Two contract files describe the same domain** — [`dev/contracts/domains/messaging.md`](../../dev/contracts/domains/messaging.md) is a headerless 851-byte fragment ("Refinement phase 3 additions (REQ-028)") sitting beside the 10.8 K [`messaging-notifications-admin.md`](../../dev/contracts/domains/messaging-notifications-admin.md), which it silently amends | — | 2 | open — merge, don't move both |
|
||||
| C-9 | **The OpenAPI folder publishes documents `v1` *and* `v1.1`** — [openapi/README.md:3](../../dev/contracts/openapi/README.md) | **Only `swagger.v1.json` has ever been committed**; `v1.1` was not fetched during this survey | 2 | open — `UNVERIFIED`, check `/swagger/v1.1/swagger.json` when the server is next up |
|
||||
| C-10 | **18 hardening items are open** — [issues.md](../../dev/post-phase/hardening/issues.md), 18 of 18 checkboxes unticked, last touched 2026-07-17 | **Fourteen UI phases, two manual-testing iterations, a Telegram integration and a deploy commit ran afterwards** (`12ce7fa` → `96b57eb`, 07-20 → 07-28) without ticking any box | 4 | open — Phase 4 must re-verify each item against code, not trust the checkbox |
|
||||
| C-12 | **The skill is current** | **It is exactly one iteration behind the code.** SKILL.md's last commit is `baa3cc6` ("manual improvement 1"); `client/CLAUDE.md`'s is `e6a8f93` ("manual improvement 2"), which changed **44 files, +3419/−2449** under `client/src`. Anything iteration 2 changed is absent from the skill | 7 | **partly resolved by phase 1** — the design-language half is corrected (see R-2); phase 7 still owns the skill's own workflow/procedure content |
|
||||
| C-13 | **`dev/` is "the plan for building Balinyaar"**, written in the imperative — [dev/README.md:3](../../dev/README.md) | **It is a record of work already done.** `dev/phases/` last touched 2026-06-28; the code it describes shipped weeks ago | 6 | open — resolved by the archive banner, not by editing 199 files |
|
||||
| C-14 | **`temp/swagger.json` is a stale committed duplicate** — [_plan/README.md](README.md) diagnosis table | **It is not committed at all** — `.gitignore:1` ignores `temp`, and `git ls-files temp/` is empty. It is local clutter, not repo content | 0 | see [§ Corrections](#corrections-to-the-seeded-list) |
|
||||
| C-15 | **`ui-phase-11-report.md:235` records "REQ-061…064 appended"** to the frontend request ledger | **REQ-061 was never appended.** The ledger goes 060 → 062; **ten live client files** cite REQ-061 for the admin user directory (`admin_users/search`, `admin_users/lookup`), which are 2 of the 24 phantom endpoints | 4 | **found by phase 2** — phase 4 must *file* it, not assume it is tracked |
|
||||
| C-16 | **Five REQs' filed status** — REQ-050, REQ-063, REQ-066, REQ-067 (open, as filed) and the reasons `admin/constants.ts` gives for the admin mock | **All five are wrong or narrower than filed**, checked against the live swagger rather than against another document. `variantLabel` already ships; `tickets/close`+`reopen` already ship; `search/nurses` and `nurses/{id}/profile` are already anonymous; REQ-029/030 already shipped | 4 | **found by phase 2** — the table is in [phase-2's handoff § B](phase-2-integration.md) |
|
||||
|
||||
---
|
||||
|
||||
@@ -52,14 +51,27 @@ at `dev/contracts/openapi/swagger.v1.json`:
|
||||
|
||||
**Schema definitions changed (1)**
|
||||
|
||||
- `GeneratePayoutBatchCommand`
|
||||
- `GeneratePayoutBatchCommand` — gained `systemInitiated: boolean` (**C-7**, resolved)
|
||||
|
||||
> **This is Phase 2's worklist for the machine contract, and it is two lines long.** The 16-day gap
|
||||
> between the snapshot and the code produced almost no wire-level drift. Phase 2 should therefore spend
|
||||
> its budget on the **hand-written** `dev/contracts/domains/*.md` — 17 files, frozen the same day, never
|
||||
> mechanically checked against anything — rather than on the JSON. See
|
||||
> **This was Phase 2's worklist for the machine contract, and it was two lines long.** The 16-day gap
|
||||
> between the snapshot and the code produced almost no wire-level drift. Phase 2 therefore spent its
|
||||
> budget on the **hand-written** contract docs instead. See
|
||||
> [§ Corrections](#corrections-to-the-seeded-list) C-14b.
|
||||
|
||||
### What phase 2 found once it looked
|
||||
|
||||
Re-scoping was right, but the conclusion "the hand-written docs are where the drift is" turned out to be
|
||||
only half true, and the more useful axis was a third one nobody had checked:
|
||||
|
||||
| Axis | Result |
|
||||
| --- | --- |
|
||||
| Old contract docs → live swagger, at **route** level | **Clean.** Every route named across the 17 files exists in the live API (the two apparent misses are prose counter-examples: "X, *not* Y") |
|
||||
| Old contract docs → live swagger, at **convention** level | **Drifted.** Body casing ("typically snake_case" vs. proven camelCase), the server's local URL scheme, the envelope's field count (5 vs. 6 — `code` was added), and the enum vocabularies |
|
||||
| **Client's real API clients → live swagger** | **24 phantom routes** — calls to endpoints the server does not expose, 2 of them reachable today. This axis had never been checked and is where the real gap was |
|
||||
|
||||
The third row is the phase's main finding, and it is in
|
||||
[phase-2's handoff § A](phase-2-integration.md).
|
||||
|
||||
---
|
||||
|
||||
## Corrections to the seeded list
|
||||
@@ -105,6 +117,11 @@ when phase 4 creates it** — that file does not exist yet, so this table is the
|
||||
| # | Was | Decision | By |
|
||||
| --- | --- | --- | --- |
|
||||
| **C-11** | The frontend-designer skill and `client/CLAUDE.md` both claimed the design language, with no stated precedence | **Precedence is now stated in both directions.** The skill is the **design** contract (brand, tone, logo construction, the visual decisions, and the workflow for turning a design into a screen); [`docs/rules/client/`](../rules/client/) is the **engineering** contract and **wins on every overlap** — tokens, typography, the component library, shells, icons. SKILL.md's header carries the precedence statement plus a table pointing at the four files it defers to, and the overlapping detail was removed from the skill rather than duplicated. `client/CLAUDE.md` no longer restates design content at all. | phase 1 |
|
||||
| **C-2** | The placeholder `SET_VIA_USER_SECRETS_OR_ENV` names a store that was removed, so its *name* instructs a reader to use a removed mechanism | **The name stays; the mechanism is documented authoritatively elsewhere.** The string is a load-bearing sentinel in **seven live files** — `appsettings.json` (×6), `StartupSecretsGuard.PlaceholderMarkers`, `.githooks/pre-commit`, `.githooks/README.md`, `Baya.Test.Api/StartupSecretsGuardTests.cs` (×2), `docs/rules/shared/git-and-gates.md`, `docs/rules/server/structure.md`. Renaming it is a server-code + git-hook + test change needing `dotnet build`/`dotnet test` to prove the gate still fires — outside a documentation phase's scope. [config-matrix.md](../integration/config-matrix.md#the-placeholders-name) is now the single authoritative statement that **config lives in appsettings files and environment variables and `user-secrets` is not read**, and `DEPLOY.md` says the same. **The rename is filed for phase 4 with that exact seven-file worklist.** | phase 2 |
|
||||
| **C-6** | `POST /api/v1/webhooks/payouts/{provider}` was absent from the frozen contract | **It exists and is now documented** — the payout transferor's reconciliation callback, anonymous, `webhook` rate-limit policy, in [domains/payouts.md](../integration/domains/payouts.md). | phase 2 |
|
||||
| **C-7** | `GeneratePayoutBatchCommand` changed shape between the two snapshots, unexplained | **It gained `systemInitiated: boolean`** alongside `periodStart`/`periodEnd`. That is the refinement-phase-7 scheduler flag distinguishing a job-generated draft batch from an admin-generated one — which is what keeps the "generation may be automatic, *processing* is always an explicit admin action" rule auditable. Recorded in [domains/payouts.md](../integration/domains/payouts.md). | phase 2 |
|
||||
| **C-8** | Two live contract files for one domain: a headerless 851-byte `messaging.md` silently amending the 10.6 K `messaging-notifications-admin.md` | **Merged and split three ways along the client's real domain boundaries** — tickets → [domains/tickets.md](../integration/domains/tickets.md), the notification feed → [domains/notifications.md](../integration/domains/notifications.md), config/holidays/audit/alerts → [domains/admin.md](../integration/domains/admin.md). Every REQ-028 amendment is folded in as current fact, not as a change log. Both old files carry a merged-into banner so neither reads as live; phase 6 archives them. | phase 2 |
|
||||
| **C-9** | The OpenAPI folder claimed documents `v1` **and** `v1.1`; only `v1` was ever committed | **Both documents genuinely are registered** (`AddSwagger("v1","v1.1")` in `Program.cs`), so `/swagger/v1.1/swagger.json` is served — **and it contains zero paths.** `ApiVersionDocumentProcessor` drops every path whose URL lacks the document's version segment, and all **55 controllers are `[ApiVersion("1")]`** on the route template `api/v{version:apiVersion}/…`. The old claim was literally true and substantively empty. `v1` is the contract; only `v1` is worth committing. **Resolved by reading the code — no server boot needed, so the `UNVERIFIED` marker is retired.** | phase 2 |
|
||||
|
||||
### Corrections landed by phase 1 that were not on the seeded list
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user