Skip to main content

Naming

One page. Every AI edit must respect these. When ambiguous, match the closest existing pattern in the same service.

Services + packages

ThingPatternExample
Service dir<noun>-servicereservation-service, lock-integration-service, ai-orchestrator-service
Workspace package (service)@ghasi/service-<name>@ghasi/service-reservation, @ghasi/service-lock-integration
Workspace package (shared lib)@ghasi/<domain>@ghasi/domain-primitives, @ghasi/telemetry, @ghasi/event-envelope, @ghasi/api-contracts, @ghasi/sync-protocol, @ghasi/ui-melmastoon, @ghasi/config
Workspace package (app)@ghasi/app-<surface>@ghasi/app-web-meta, @ghasi/app-web-tenant-booking, @ghasi/app-mobile-consumer, @ghasi/app-desktop-backoffice

The 22 canonical service names are listed in docs/03-microservices/README.md. Never invent a new service name without adding it to that catalog in the same PR.

Files

ThingPatternExample
Aggregatekebab-case.tsreservation.ts, key-credential.ts, rate-plan.ts
Value objectkebab-case.tstenant-id.ts, money.ts, date-range.ts
Domain eventkebab-case.event.tsreservation-confirmed.event.ts, key-credential-revoked.event.ts
Domain errorkebab-case.error.tscross-tenant-reference.error.ts, overbooking-blocked.error.ts
Port (interface)<name>.port.tslock.port.ts, payment.port.ts, reservation.repository.port.ts
Adapter (impl)<vendor-or-tech>-<name>.adapter.tspostgres-reservation.adapter.ts, pubsub-event-publisher.adapter.ts, ttlock-lock.adapter.ts, salto-lock.adapter.ts
Use case<verb-noun>.use-case.tsconfirm-reservation.use-case.ts, issue-key-credential.use-case.ts
DTO (application)<name>.dto.tsconfirm-reservation-command.dto.ts
Mapper<name>.mapper.tsreservation.mapper.ts
Controller<resource>.controller.tsreservations.controller.ts, key-credentials.controller.ts
Guard<name>.guard.tsjwt-auth.guard.ts, tenant-context.guard.ts
Unit spec*.spec.tsreservation.spec.ts
Integration spec*.integration.spec.tsconfirm-reservation.integration.spec.ts
Contract spec*.pact.spec.ts or *.schema.spec.tsreservations.pact.spec.ts
E2E spec*.e2e.spec.tswalk-in-checkin-offline.e2e.spec.ts
React componentPascalCase.tsxRoomCard.tsx, BookingFlow.tsx
React hookuse-kebab-case.tsuse-sync-status.ts, use-tenant-theme.ts
CSS / styleskebab-case.module.cssroom-card.module.css
SQL migrationNNNN_<description>.sql (zero-padded ordinal)0007_add_key_credentials_table.sql

Symbols

ThingPatternExample
ClassPascalCaseReservation, ConfirmReservationUseCase, TtLockAdapter
Interface (port)PascalCase, no I prefixLockPort, PaymentPort, ReservationRepository
Type aliasPascalCaseConfirmReservationCommand, BookingFlowStep
Branded IDtype <Entity>Id = Branded<string, '<Entity>Id'>type TenantId = Branded<string, 'TenantId'>, type ReservationId = Branded<string, 'ReservationId'>, type KeyCredentialId = Branded<string, 'KeyCredentialId'>, type PropertyId = Branded<string, 'PropertyId'>, type RoomId = Branded<string, 'RoomId'>, type FolioId = Branded<string, 'FolioId'>
ConstantSCREAMING_SNAKE_CASEMAX_PAGE_SIZE, DEFAULT_HOLD_TTL_SECONDS
EnumPascalCase type + PascalCase membersenum ReservationStatus { Held, Confirmed, CheckedIn, CheckedOut, Cancelled, NoShow }
Variable / functioncamelCaseconfirmReservation, currentTenantId
React componentPascalCase<SyncStatusPill />, <KeyCredentialCard />
React hookuse prefixuseSyncStatus(), useTenantTheme()

Events

Event subject format: melmastoon.<service>.<aggregate>.<verb-past-tense>.v<n>

  • service: the service short name (matches service dir minus -service suffix). Examples: reservation, inventory, lock-integration, ai-orchestrator.
  • aggregate: snake_case aggregate name.
  • verb-past-tense: snake_case past-tense verb (one event = one fact that already happened).
  • v<n>: integer, starting at v1.

Examples:

  • melmastoon.reservation.booking.confirmed.v1
  • melmastoon.reservation.booking.cancelled.v1
  • melmastoon.inventory.allocation.committed.v1
  • melmastoon.pricing.rate_plan.published.v1
  • melmastoon.billing.folio.posted.v1
  • melmastoon.payment.intent.captured.v1
  • melmastoon.lock_integration.key_credential.issued.v1
  • melmastoon.lock_integration.key_credential.revoked.v1
  • melmastoon.housekeeping.task.completed.v1
  • melmastoon.ai_orchestrator.completion.refused.v1
  • melmastoon.search_aggregation.listing.indexed.v1

GCP Pub/Sub topic name = event subject (identical, dot-separated). Subscribers are named <consumer-service>.<topic> (e.g. inventory.melmastoon.reservation.booking.confirmed.v1).

Database

ThingPatternExample
Tablesnake_case_pluralreservations, key_credentials, rate_plans, outbox, inbox
Columnsnake_casetenant_id, created_at, is_confirmed, check_in_at
Indexix_<table>_<columns>ix_reservations_tenant_id_status, ix_key_credentials_reservation_id
Foreign keyfk_<table>_<referenced_table>fk_key_credentials_reservations
RLS policy<table>_tenant_isolationreservations_tenant_isolation, key_credentials_tenant_isolation
MigrationNNNN_<description>.sql (per-service, zero-padded ordinal)0006_add_reservations_table.sql

Every multi-tenant table has tenant_id uuid NOT NULL plus an RLS policy. Money is stored as bigint micro-units (no floats); the column suffix is _micro (e.g., total_amount_micro).

API paths

  • /api/v<N>/<resource-plural-kebab> with optional nested sub-resources.
  • Lowercase, kebab-case, no trailing slash.
  • Resource IDs are ULIDs with the service-chosen prefix.

Examples:

  • POST /api/v1/reservations
  • GET /api/v1/reservations/rsv_01H.../folio
  • PATCH /api/v1/reservations/rsv_01H...
  • POST /api/v1/reservations/rsv_01H.../check-in
  • POST /api/v1/key-credentials
  • DELETE /api/v1/key-credentials/key_01H...
  • GET /api/v1/properties/ppt_01H.../rooms
  • POST /api/v1/sync/v1/pull
  • POST /api/v1/sync/v1/push

BFF routes are namespaced by surface: /bff/consumer/v1/..., /bff/tenant-booking/v1/..., /bff/backoffice/v1/....

Error codes

Format: MELMASTOON.<DOMAIN>.<CODE> — three uppercase, dot-separated segments, snake_case-uppercase code suffix.

Examples:

  • MELMASTOON.RESERVATION.OVERBOOKING_BLOCKED
  • MELMASTOON.INVENTORY.ALLOCATION_NOT_FOUND
  • MELMASTOON.PAYMENT.GATEWAY_TIMEOUT
  • MELMASTOON.LOCK.VENDOR_UNREACHABLE
  • MELMASTOON.SYNC.CURSOR_OUT_OF_RANGE
  • MELMASTOON.AI.REFUSED_SAFETY

The full registry lives in ERROR_CODES.md. Never invent a new code in a PR without adding it there.

ID prefixes (declared in each service's DATA_MODEL.md)

Reserved prefixes (the canonical registry):

PrefixEntityOwning service
tnt_Tenanttenant-service
usr_User (auth subject)iam-service
mbr_Membership (user-in-tenant role)tenant-service
ppt_Propertyproperty-service
rmt_RoomTypeproperty-service
rmu_Room (sellable unit)property-service
rsv_Reservationreservation-service
bkg_Booking (in-progress)reservation-service
gst_Guestreservation-service
rate_RatePlanpricing-service
inv_InventoryAllocationinventory-service
hkt_HousekeepingTaskhousekeeping-service
mnt_MaintenanceTicketmaintenance-service
fol_Foliobilling-service
chg_Chargebilling-service
inv_doc_Invoice (document)billing-service
pay_Paymentpayment-gateway-service
pyi_PaymentIntentpayment-gateway-service
key_KeyCredentiallock-integration-service
lck_LockDevicelock-integration-service
stf_StaffMemberstaff-service
shf_Shiftstaff-service
ntf_Notificationnotification-service
tpl_Template (notification, theme)notification-service / theme-config-service
thm_Themetheme-config-service
med_MediaAssetfile-storage-service
srh_SearchableDocumentsearch-aggregation-service
dec_Decision (AI HITL)ai-orchestrator-service
dev_Device (desktop binding)iam-service
evt_Event (envelope)platform-wide
req_Request (correlation)platform-wide

When adding a new entity, pick a 3–4-character prefix, document it in the owning service's DATA_MODEL.md, and add a row to this table in the same commit.

Environment variables

  • SCREAMING_SNAKE_CASE.
  • Namespaced by concern: DATABASE_URL, REDIS_URL, PUBSUB_PROJECT_ID, KMS_KEY_RESOURCE, AI_ORCHESTRATOR_BASE_URL, OTEL_EXPORTER_OTLP_ENDPOINT.
  • Service-local vars namespaced by service short name: IAM_JWT_ISSUER, RESERVATION_HOLD_TTL_SECONDS, LOCK_TTLOCK_API_KEY.
  • Validated at startup via Zod schema in src/infrastructure/config/env.ts. Fail fast if missing.