Files
mercadodevida/work/artifacts/F-153/implementer.md
2026-08-22 07:41:08 +02:00

57 lines
3.3 KiB
Markdown

# F-153 — Implementer Evidence
## Build
Feature: F-153 — Orders: associate the linked customer's email to the order read
model and display it (customer email was missing despite the user having an email).
### Changes (production)
- `src/modules/orders/domain/order.ts` — added `email?: string | null` to `OrderView`
(read model). `Order` core aggregate is untouched (email is a denormalized read attr).
- `src/modules/orders/infrastructure/pg-order-repository.ts`:
- added `email: string | null` to `OrderRow`;
- added `toOrderView(row, items)` helper;
- `findById`, `findByIdAndUserId`, `findAll`, `search` now `SELECT o.*, u.email` with
`LEFT JOIN identity_users u ON u.id = o.user_id` (reuses the existing `search` join pattern);
- every `OrderView` is built via `toOrderView`, so `email` is always populated
(`string | null`; `null` when the order has no linked identity_user).
- `src/modules/orders/api/orders.routes.ts`:
- `serializeOrder` now emits `email: order.email ?? null` (detail + list);
- admin force-transition (`POST /orders/:id/transitions/admin`) consumes
`order.email` (the associated email) and no longer issues a separate inline
`SELECT email FROM identity_users` lookup → no N+1, single source of truth.
### Changes (tests)
- new `src/modules/orders/infrastructure/pg-order-repository.test.ts`:
- `findById` resolves `email` via the `identity_users` join (asserts the query contains
`identity_users` + `u.email` and returns the row's email);
- returns `null` when the order has no linked identity_user;
- returns `undefined` when the order does not exist.
- existing `OrderView` literals (`order-service`, `payments-service`, `checkout-service`)
needed no change (`email` is optional on the view; fixtures omit it → serialized as `null`).
### Boundary / compatibility notes
- `identity_users` is referenced only as a SQL table name (pre-existing pattern in `search`);
no TypeScript import crosses the identity↔orders boundary → `lint:boundaries` unchanged.
- No migration (`identity_users.email` already `citext NOT NULL UNIQUE`).
- Additive API field; no state-machine / endpoint / contract change.
## Evidence (commands + results)
- `npx tsc --noEmit`**0 errors** (`TSC_EXIT:0`).
- `npx vitest run`**200 passed | 56 skipped (50 files)**; new F-153 suite
`orders/infrastructure/pg-order-repository.test.ts`**3 passed**.
- `npx eslint` (touched files) → **0 errors / 0 warnings** (`ESLINT_EXIT:0`).
- `npx prettier --check` on touched files → only **pre-existing baseline warnings**
(identical to `HEAD` for both `pg-order-repository.ts` and `orders.routes.ts`; my added
lines are short / long string literals accepted by Prettier; no new reformatting).
- `npm run lint:boundaries`**1 violation, pre-existing** (`security/routes` R1);
**0 new violations** from F-153.
- `git diff --check`**clean** (no whitespace errors).
- `./scripts/verify.sh`**exit 0** (backlog 270 features valid; runtime-status advance to
build/running with F-153 in_progress — see below).
## Decisions
- Resolved via the read model (Option A in ADR) rather than route-layer lookups (Option B)
because `orders` already joins `identity_users` in SQL for `search`; generalizing that join
to all order reads gives the email as a first-class read attribute and removes the
per-request lookup from the admin transition.