clients routing - BevvyTech/BrewskiDocs GitHub Wiki
This note documents the refactored clients API structure. Use it as the reference point for where handlers live, which helpers they depend on, and how managed-account safeguards are enforced across the feature set.
-
API/src/routes/clients/index.ts— Fastify registrar that wires each scoped client plugin. -
API/src/routes/clients/*.ts— Top-level handlers (create,update,detail,list,search, claim flows). -
API/src/routes/clients/contacts/*.ts— Contact CRUD endpoints grouped by action. -
API/src/modules/clients/— Shared utilities extracted from the legacy monolith:-
activity.service.ts— wraps activity log writes for consistent metadata. -
access.ts— authentication/membership helpers (ensureAuthenticated,ensureTeamMembership,ensureClientAccess). -
constants.ts— enums, defaults, and guard-rail constants (filters, AWRS pattern, restricted keys, pricebook error codes). -
errors.ts— typed error helpers (ErrorWithCode,createErrorWithCode). -
mappers.ts—membershipInclude, response builders, and membership typing helpers. -
normalizers.ts— shared string normalisation (emails, phone numbers, AWRS, postcode). -
pricebook.ts— logic to resolve team pricebooks (with descriptive error codes). -
schemas.ts— Zod schemas for list/search/create/update/claim/contact payloads.
-
| File | HTTP Surface | Notes |
|---|---|---|
create.ts |
POST /clients |
Creates a client, validates uniqueness (email/AWRS/company), builds address book entries, honours managed-account safeguards. |
claim-email.ts |
POST /clients/claim/email |
Links an existing wholesale client via contact email using default pricebook fallback. |
claim-code.ts |
POST /clients/claim/code |
Links clients via pairing codes, tracks usage, and enforces expiry/single-use rules. |
update.ts |
PATCH /clients/:clientId |
Applies partial updates, rewrites address books, enforces managed-account restrictions, and syncs membership metadata. |
detail.ts |
GET /clients/:clientId |
Returns a membership-scoped client payload after access checks. |
list.ts |
GET /clients |
Aggregates client memberships with order/deposit summaries, supports filtering/sorting/pagination. |
search.ts |
GET /clients/search |
Lightweight search returning { id, name } tuples for name/site matches. |
contacts/create.ts |
POST /clients/:clientId/people |
Adds contacts when the client is not managed; logs activity events. |
contacts/update.ts |
PATCH /clients/:clientId/people/:personId |
Partial updates on contact records with managed-account guard rails. |
contacts/remove.ts |
DELETE /clients/:clientId/people/:personId |
Removes contacts (or rejects when client is managed) and records audit metadata. |
Every handler:
- Calls
ensureAuthenticatedplus eitherensureTeamMembershiporensureClientAccessbefore mutating/reading data. - Delegates pricebook resolution and response shaping to the shared modules to avoid duplication.
- Emits activity records (
marketingcategory) so timelines remain in sync with previous behaviour. - Keeps individual files well under 500 lines; shared logic lives in
modules/clients/to facilitate future reuse.
- Managed clients reject field updates (name/contact info/addresses) and contact CRUD attempts from brewery teams.
- Wholesale checks live in the claim helpers; creation already verifies conflicts (email, company number, AWRS, postcode+name combos).
- Pairing code flows centralise expiry and single-use handling in the claim route so UI and future automations share the same rules.
- Pricebook selection always routes through
resolvePricebookId, generating a labelled error when a requested pricebook does not belong to the team.
Update this document whenever new client routes or helpers are introduced. Keep the helper modules focused—if a route grows beyond 300 lines, split the logic into a dedicated helper before proceeding.