Skip to main content

Naming

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

Services + packages

ThingPatternExample
Service dir{bounded-context}-serviceidentity-service, ai-gateway-service
Workspace package (service)@ghasi/service-{name}@ghasi/service-identity
Workspace package (shared lib)@ghasi/{domain}@ghasi/domain-primitives, @ghasi/telemetry, @ghasi/event-envelope, @ghasi/api-contracts, @ghasi/sync-protocol, @ghasi/ui, @ghasi/config
Workspace package (app)@ghasi/app-{surface}@ghasi/app-web-learner, @ghasi/app-web-authoring

Files

ThingPatternExample
Aggregatekebab-case.tscourse-draft.ts
Value objectkebab-case.tstenant-id.ts, email-address.ts
Domain eventkebab-case.event.tscourse-draft-published.event.ts
Domain errorkebab-case.error.tscross-tenant-reference.error.ts
Port (interface){name}.port.tsai-client.port.ts, course-draft.repository.port.ts
Adapter (impl){name}.adapter.tspostgres-course-draft.adapter.ts, nats-event-publisher.adapter.ts
Use case{verb-noun}.use-case.tspublish-course.use-case.ts
DTO (application){name}.dto.tspublish-course-command.dto.ts
Mapper{name}.mapper.tscourse-draft.mapper.ts
Controller{resource}.controller.tscourses.controller.ts
Guard{name}.guard.tsjwt-auth.guard.ts
Unit spec*.spec.tscourse-draft.spec.ts
Integration spec*.integration.spec.tspublish-course.integration.spec.ts
Contract spec*.pact.spec.ts or *.schema.spec.tscourses.pact.spec.ts
E2E spec*.e2e.spec.tslearner-first-lesson.e2e.spec.ts
React componentPascalCase.tsxCourseCard.tsx
React hookuse-kebab-case.tsuse-sync-status.ts
CSS / styleskebab-case.module.csscourse-card.module.css

Symbols

ThingPatternExample
ClassPascalCaseCourseDraft, PublishCourseUseCase
Interface (port)PascalCase, no I prefixAIClient, CourseDraftRepository
Type aliasPascalCasePublishCourseCommand
Branded IDtype {Entity}Id = Branded<string, '{Entity}Id'>type UserId = Branded<string, 'UserId'>
ConstantSCREAMING_SNAKE_CASEMAX_PAGE_SIZE
EnumPascalCase type + PascalCase membersenum CourseDraftStatus { Draft, DraftAi, Reviewed, Published }
Variable / functioncamelCasepublishCourse, currentTenantId
React componentPascalCase<SyncStatusPill />
React hookuse prefixuseSyncStatus()

Events

Event type format: {service}.{aggregate}.{event}.v{N}

  • service: one of the 19 canonical names (lowercase, matches service dir minus -service suffix).
  • aggregate: snake_case.
  • event: snake_case, past tense verb or state.
  • v{N}: integer, starting at 1.

Examples:

  • authoring.course_draft.published.v1
  • progress.statement.recorded.v2
  • marketplace.order.paid.v1
  • identity.user.registered.v1
  • ai.completion.refused.v1

Subject (NATS) = event type (identical).

Database

ThingPatternExample
Tablesnake_case_pluralcourse_drafts, play_sessions, outbox, inbox
Columnsnake_casetenant_id, created_at, is_published
Indexix_{table}_{columns}ix_course_drafts_tenant_id_status
Foreign keyfk_{table}_{referenced_table}fk_lessons_course_drafts
RLS policy{table}_tenant_isolationcourse_drafts_tenant_isolation
MigrationYYYYMMDDHHMMSS_{description}.sql20260416093000_add_course_drafts_table.sql

API paths

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

Examples:

  • POST /api/v1/course-drafts
  • GET /api/v1/course-drafts/drf_01H.../blocks
  • PATCH /api/v1/course-drafts/drf_01H.../blocks/blk_01H...
  • DELETE /api/v1/course-drafts/drf_01H...

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

Common conventions (reserve these in the canonical registry):

PrefixEntity
ten_Tenant
usr_User
org_OrgUnit
dev_Device
req_Request
evt_Event
crs_Course
drf_CourseDraft
lsn_Lesson
blk_Block
asn_Assignment
atp_AssessmentAttempt
enr_Enrollment
ord_Order
lic_License
cer_Certificate
bun_PlayPackage Bundle
med_MediaAsset
ntf_Notification
smt_Statement (xAPI)
ses_PlaySession
dec_Decision (AI HITL)

When adding a new entity, pick a three-letter prefix, document in the owning service's DATA_MODEL.md, and add to this table in the same commit.

Environment variables

  • SCREAMING_SNAKE_CASE.
  • Namespaced by concern: DATABASE_URL, REDIS_URL, NATS_URL, KMS_KEY_ARN, AI_GATEWAY_BASE_URL, OTEL_EXPORTER_OTLP_ENDPOINT.
  • Service-local vars namespaced: IDENTITY_JWT_ISSUER, AUTHORING_STORAGE_BUCKET.
  • Validated at startup via Zod schema in src/infrastructure/config/env.ts. Fail fast if missing.