License.vendor (free-text string) is now vendorId, a required FK to
Vendor, per docs/asset-license-management.md's "## Vendor (chốt
2026-08-02)" spec. Mirrors the Request.employeeId string->FK precedent:
Zod validates UUID format only, Prisma's own FK constraint (P2003) is
caught at insert time and translated into a clean 400 instead of a raw
500. No License data existed yet, so this is a pure column-type
migration, no backfill needed.
Also converts createLicense() to the {ok,value}|{ok,error} result
pattern used elsewhere (createRequest, createAssetItem) instead of
returning a bare LicenseRecord promise - closes the gap flagged in
CLAUDE.md now that License has its first FK-violation error case to
handle.
Vendor entity: Prisma model+migration, Zod+CRUD, API routes, tests.
Verified green by test-runner (94/94 tests, tsc/lint/build clean)
before merge.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Stakeholder decided: createAssignment() blocks if AssetItem.status
isn't in_stock, and update routes use PATCH /api/<entity>/[id]
(applies to both Assignment and PurchaseOrder).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
BA formalizes the Vendor, PurchaseOrder (absorbs Receipt), Assignment,
and AssetCategoryAttributeDef designs decided in stakeholder brainstorm
into docs/asset-license-management.md. PM sequences the resulting work
into dependency-ordered, commit-mapped tasks across 3 independent lanes
in CLAUDE.md, surfacing that AssetCategory/AssetModel/ConsumableItem
were spec'd earlier but never actually built, and flagging two open
questions (Assignment precondition on AssetItem.status; REST shape for
update operations) that need stakeholder input before Lane C starts.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
AssetCategory/AssetModel hierarchy, ConsumableItem for low-value/
consumable items, data constraints, and open questions for the
consumable request flow — decisions already confirmed with
stakeholder, spec was written but not yet committed.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
AssetCategory/AssetModel hierarchy, ConsumableItem for low-value/
consumable items, data constraints, and open questions for the
consumable request flow — decisions already confirmed with
stakeholder, spec was written but not yet committed.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
pm now asks ba back when a spec gap could change business behavior,
instead of guessing; task lists must also map cleanly onto the
existing per-commit convention (model+migration/lib/API/tests).
Stakeholder should only need to state a business goal/priority, not
pick between implementation options or break work into tasks
themselves. `ba` turns a business ask into a concrete spec grounded in
docs/asset-license-management.md, `pm` breaks that spec into an
ordered, dependency-aware sequence of feature-implementer-sized tasks.
Neither writes code or resolves business-rule ambiguity — that stays
with the stakeholder.
Also fixes code-reviewer.md/feature-implementer.md pointing at the old
../processes/asset-license-management.md path — the doc moved into
docs/ inside this repo a while ago.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Adds a production Docker image (node:20-alpine) and an `app` service in
docker-compose.yml so the Next.js app can run as a long-lived container
instead of just build/test in ephemeral containers. Requires `apk add
openssl` before `npm ci`, otherwise Prisma silently picks the wrong query
engine binary on Alpine and only fails at runtime. Also wires
AUTH_TRUST_HOST=true, required by Auth.js when running behind the NPM
reverse proxy.
Co-Authored-By: Claude Sonnet 5 <[email protected]>