# Verification — establish-core-api-architecture

Verified on 2026-10-12 from the monorepo workspace. The existing API layer
folders are preserved. Auth paths and config/prisma.ts are unchanged.
No business endpoints, database migrations, scheduler or stock/history
implementation were added.

## Commands and results

| Command (from monorepo root) | Result |
| --- | --- |
| pnpm typecheck | PASS: shared, API and frontend |
| pnpm build | PASS: shared TypeScript, API TypeScript, frontend production build |
| pnpm test | PASS: API 41 tests across 10 files; frontend 12 tests across 2 files |
| pnpm --filter express-api-starter-ts test:docs | PASS: compiled Swagger contract from routes/*.js |
| pnpm --filter express-api-starter-ts typecheck | PASS after final headers-sent sanitization |
| pnpm --filter express-api-starter-ts build | PASS after final headers-sent sanitization |
| pnpm --filter express-api-starter-ts test test/error-contract.test.ts test/error-catalog.test.ts | PASS: 8 affected error/catalog tests after final sanitization |
| openspec validate establish-core-api-architecture --strict | PASS after the architecture revision; repeated at completion |

The frontend build reports a non-failing chunk-size warning for the existing
Excel export bundle. No bundle restructuring is part of this change.

API regression files include auth, CORS, API, app, Swagger and admin-seeder
tests plus response-contract, serialization, error-contract and error-catalog.
Source and compiled Swagger assertions cover auth paths, success/failure
schemas, 400/401/403/413/422/429/500/503 responses, X-Request-Id, Retry-After
and bodyless 204 logout. Route discovery stays in the existing routes folder.

After the full regression pass, the headers-sent branch was tightened so
Express receives only a sanitized error (its default handler can log outside
test mode). API typecheck/build and the 8 affected tests were rerun.
No other runtime changes followed that verification.

## Frontend/API HTTP flow

apps/app/test/auth-http.integration.test.ts invokes the real frontend auth
service through Axios against the changed Express app listening on an ephemeral
loopback port. The observed sequence is:

1. Current-user without a cookie: 401, decoded as null.
2. Invalid login fields: 422 VALIDATION_ERROR with an Indonesian message and email detail.
3. Valid login: 200 envelope with the public user and an HttpOnly auth cookie.
4. Current-user with that cookie: 200 envelope with the public user.
5. Logout: 204, empty body and expired cookie.
6. Current-user after cookie removal: 401, decoded as null.

Each response has a distinct server request ID; JSON metadata matches its
header. Password hashing, JWT signing/verification, origin middleware,
routing, HTTP and decoding are real. Prisma user lookup uses a fixture and
Node emulates browser cookie storage. This verifies client/API compatibility
over HTTP; it is not browser automation or a live database test. No database
migration, seed write, external deployment or real account mutation was needed.

The other 11 frontend tests cover legacy/malformed bodies, nested safe error
messages/details, stable code/status handling, unauthorized state, network
fallbacks, server failures and bodyless logout. Release/rollback coordination
is documented in root AUTH.md and apps/app/README.md.

## Capability scenario coverage

| Capability / scenarios | Evidence and boundary |
| --- | --- |
| Authenticated user response; public authentication DTO | auth.test.ts and frontend HTTP flow verify data.user, current role/account checks and exclusion of hash/token fields |
| Logout response; frontend login after migration | auth.test.ts, auth.service.test.ts and auth-http.integration.test.ts verify cookie behavior, 204, nested decoding and error handling |
| Malformed versus invalid input; invalid quantity | error-contract.test.ts covers parser 400 and nested positive-quantity validation details; auth.test.ts covers real HTTP 422. No quantity mutation endpoint is implemented |
| Empty/out-of-range pages; invalid pagination | response-contract.test.ts covers defaults, limits, rejected invalid inputs, empty arrays and requested-page metadata |
| Money and time representation | serialization.test.ts covers exact decimal strings, UTC instants and date-only values under multiple timezone settings |
| Parser failure correlation | error-contract.test.ts checks header/body/log IDs, ignored inbound IDs, CORS exposure and omission of request secrets |
| Unmatched route; repeated login attempts | error-contract.test.ts and auth.test.ts check 404, 429 envelope and Retry-After; oversized parsing checks 413 |
| Private database exception; streaming completion safety | error-contract.test.ts verifies generic safe 500, safe logs, no second JSON write and sanitized delegation after headers are sent |
| Duplicate identifier; missing related data; insufficient stock | normalization tests/catalog verify contextual P2002/P2025 and domain-code mappings. These are boundary tests, not real stock/product operation coverage |
| Language separation | Indonesian error catalog/messages and unchanged English role/code values are verified. Work-order content/status scenario applies to the future Maintenance feature |
| Existing layered structure; dependency direction | Auth and Prisma restored to original paths; services use config/shared/internal contracts and do not import Express, routes, controllers or middleware. No modules/http/domain/infrastructure directories or generic repositories |

## Conditional scenarios deferred to domain feature changes

Inventory/Maintenance endpoints are not part of this baseline. The following
requirements remain acceptance constraints, documented in src/README.md,
prisma/schema-design.md and the capability delta:

- Maintenance consumption must derive from posted inventory movements and
  enforce Inventory availability/approval/ledger rules.
- Posting failure must roll back all balance, ledger, quarantine, work-order
  and audit changes atomically.
- Competing issues must not overdraw or double-post.
- A retry after a lost response must reuse the retained idempotency key;
  identical payload replays the original result, a changed payload conflicts.
- Archived master data must retain posted history and attribution.
- Overdue must remain a derived read state without overwriting lifecycle.
- Domain collection services must use identical list/count filters and a
  deterministic sort with ID tie-breaker.
- Created domain resources must return 201/Location; the generic helper is
  tested, but no resource-creation endpoint was added here.

Future Inventory/Maintenance changes must supply real transactional MySQL
concurrency, rollback, retry and historical-integrity tests. Helper/catalog
coverage in this baseline is not evidence that those domain features exist.
