PrimeBrickPrimeBrick
  • Docs
  • Contact
  • MIT License
  • Documentation
  • MCP Server
  • API Catalog
  • Services
  • Libraries
PrimeBrickPrimeBrick

© 2026 PrimeBrick. MIT License. v3.11.2

github
Backend
Frontend
Microservices
    Developer Guide
      Microservices OverviewArchitectureConventionsAdding a Service
      Services
powered by Zudoku
Developer Guide

Conventions

API path conventions

All HTTP routes in microservices follow standardized path conventions so the BE's MCP Server can dispatch generic CRUD tools without per-entity configuration.

Route handlers are factory-produced (MANDATORY): the service's whole HTTP surface is declared ONCE via the SDK's makeServiceRoutes — entity declarations become makeEntityRouter + entityCrudSpec, RpcRoute[] tables become makeRpcRouter + rpcSpec, and /api/v1/openapi.json via makeOpenApiHandler — all derived from that single declaration, so the published spec can never drift from the registered routes. createMicroservice refuses to boot with a hand-rolled (req, res, url) => boolean handler — auth, RBAC, body validation and RFC 7807 errors are enforced by the factory, not by convention.

Entity CRUD (/api/v1/entities/:entity/...)

Database-backed entities with standard CRUD lifecycle use this pattern:

Code
GET /api/v1/entities/:entity/meta → entity metadata (fields, types, validation) GET /api/v1/entities/:entity/list → paginated list with search/filter/sort GET /api/v1/entities/:entity/:uuid → single record by UUID POST /api/v1/entities/:entity → create new record PUT /api/v1/entities/:entity/:uuid → update record by UUID DELETE /api/v1/entities/:entity/:uuid → soft-delete record by UUID POST /api/v1/entities/:entity/:uuid/restore → restore soft-deleted record GET /api/v1/entities/:entity/:uuid/audit → audit history for record POST /api/v1/entities/:entity/bulk-delete → bulk soft-delete (array of UUIDs) POST /api/v1/entities/:entity/bulk-restore → bulk restore (array of UUIDs)

Rules:

  • :entity is the snake_case singular noun (e.g. provider, config_entry). Never plural, never camelCase.
  • :uuid is always the UUID path parameter.
  • Not all entities support all operations — unsupported operations simply don't register that route.
  • The meta endpoint returns the entity's field schema, consumed by the MCP get_entity_meta tool and the FE for dynamic form generation.
  • Write-payload standard ({entity} envelope): single-entity POST/PUT bodies MUST be { entity: {...} } — flat entity fields at the body root are rejected with 400 (hard break, same contract as the BE). A translations sibling is NOT accepted on microservice entities (no translations table in the service schema). Bulk endpoints (bulk-*), actions, DELETE and RPC routes keep their own bodies. The MCP proxy dispatch already wraps tool args into { entity } — no per-tool change needed.

Example — list providers through the BE proxy:

TerminalCode
# List with search + pagination curl -H "Authorization: Bearer <jwt>" \ "http://localhost:3001/ws/emailsender/api/v1/entities/provider/list?search=brevo&page=1&page_size=20" # Get entity metadata (field schema for dynamic forms) curl -H "Authorization: Bearer <jwt>" \ http://localhost:3001/ws/emailsender/api/v1/entities/provider/meta # Create a provider ({entity} envelope) curl -X POST -H "Authorization: Bearer <jwt>" -H "Content-Type: application/json" \ http://localhost:3001/ws/emailsender/api/v1/entities/provider \ -d '{"entity":{"provider":"brevo","api_key":"xkeysib-...","from_email":"noreply@example.com"}}' # Soft-delete by UUID curl -X DELETE -H "Authorization: Bearer <jwt>" \ http://localhost:3001/ws/emailsender/api/v1/entities/provider/550e8400-e29b-41d4-a716-446655440000 # Restore a soft-deleted record curl -X POST -H "Authorization: Bearer <jwt>" \ http://localhost:3001/ws/emailsender/api/v1/entities/provider/550e8400-e29b-41d4-a716-446655440000/restore

Service actions (/api/v1/actions/:action)

Non-CRUD business actions:

Code
POST /api/v1/actions/send-email → send an email using a template POST /api/v1/actions/test-provider-connection → test a provider's API key
  • :action is a snake_case verb-noun.
  • These are NOT exposed as MCP generic CRUD tools.

Webhooks (/webhook or /webhook/:identifier)

External callbacks (e.g. Brevo™ delivery events):

Code
POST /webhook → webhook receiver (API key auth) POST /webhook/brevo → Brevo-specific webhook
  • Webhooks use API key authentication, NOT JWT.
  • Webhook paths do NOT use the /api/v1/ prefix.

System / Health

Code
GET /health → health check (public, no auth) GET /api/v1/openapi.json → OpenAPI spec (client-shielded — the BE fetches it via internalFetch during discovery) GET /api/v1/system/info → service info (authenticated)

OpenAPI spec requirements

Every microservice MUST export a complete OpenAPI 3.x spec at GET /api/v1/openapi.json:

  1. List ALL implemented routes
  2. Use operationId in snake_case for every operation
  3. Include tags grouping operations by entity or category
  4. Include summary and description for every operation
  5. Use snake_case field names in request/response schemas

Data model rules

Naming convention

LayerName formExample
PG tablesnake_case pluralproviders, config_entries, sender_logs
TS entity classPascalCase singularProviderEntity, ConfigEntryEntity
API URL entity segmentsnake_case singular/api/v1/entities/provider/...
  • Entity class = singular (one row schema)
  • PG table = plural (collection of rows)
  • URL entity segment = singular (resource type)

Snake_case everywhere

DB columns, TS interfaces, JSON request bodies, and JSON response bodies ALL use snake_case. A field named from_email in the DB is from_email in the TS interface and from_email in the JSON response. Never rename fields between layers.

Exception: External API adapters (e.g. Brevo™ expecting camelCase). The translation happens ONLY at the adapter boundary.

No DTO transformation

The DB row IS the TS model. Do not create intermediate DTO classes that rename fields. Prefer spreading raw results (return { ...settings }) over field-by-field rebuilding.

No fake defaults on the read path

  • Forbidden: lowercasing, uppercasing, trimming on the read path
  • Forbidden: fallback string-literal defaults (|| "...", ?? "") for configuration data
  • A value either exists in the DB or it doesn't — undefined if missing, null if the row exists but value is NULL, string if present
  • Mandatory-field checks throw before the return, they don't fake a default

Type conversions are allowed

  • string (DB) → boolean (TS) via === "true" — allowed
  • string (DB) → enum (TS) via validation + normalization — allowed

These are type conversions, not data-quality enforcement. Data quality is enforced at the write path (API upsert validation).

Package versioning

All package versions in package.json MUST be pinned to exact versions (e.g. "typescript": "5.9.3"). NO ranges (^, ~, >=, *, latest) are allowed for registry packages. This ensures every dev machine, CI build, and production rebuild gets the exact same dependency tree.

Workspace dependencies use workspace:* (e.g. "@primebrick/sdk": "workspace:*").

Repo tooling

ToolWherePurpose
scripts/version-sync.mjsrepo rootversion:auto/prebuild hook — keeps version aligned across service package.jsons
<svc>/scripts/database-patch-apply.tsper servicedb:migrate — runs the dal-pg runMigrations engine against the service's own schema (same code path as boot)
<svc>/scripts/build-docs-pack.tsper servicegenerate:docs — builds dist/docs-pack (SDK buildDocsPack)

Next steps

  • Architecture — NATS™ bus, BE proxy, SDK lifecycle
  • EmailSender — Email sending microservice
Last modified on October 28, 2026
ArchitectureAdding a Service
On this page
  • API path conventions
    • Entity CRUD (/api/v1/entities/:entity/...)
    • Service actions (/api/v1/actions/:action)
    • Webhooks (/webhook or /webhook/:identifier)
    • System / Health
    • OpenAPI spec requirements
  • Data model rules
    • Naming convention
    • Snake_case everywhere
    • No DTO transformation
    • No fake defaults on the read path
    • Type conversions are allowed
  • Package versioning
  • Repo tooling
  • Next steps