On this page

Directory structure

Business modules own operations and data access. App assembly connects their explicit dependencies; reusable packages own technical behavior. The project conventions define the current defaults and ownership rules.

Find a capability#

cmd/
  app/                    HTTP, workers and local subscribers
  worker/                 Workers and local subscribers
  scheduler/              Recurring enqueue only
  cli/                    Console entry point
  labena/                 Template installer; omitted from generated applications
internal/
  app/                    Composition, process selection and lifecycle ownership
    config/               Typed environment settings and owner translations
  modules/
    identity/             Accounts and authentication
    shared/               Definitions shared across business modules
      entities/           Owned business entities, including accepted Bun mappings
      enums/              Business values grouped by concept
      events/             Published business event contracts and occurrence metadata
      domain/             Common entity identity and value objects
      migrations/         Global and published infrastructure SQL
  platform/
    auth/                 Authenticated caller identity, independent of business entities
    notification/         JSON notifications, email and durable per-channel delivery
    media/                Public/private assets and storage recovery
    lifecycle/            Process readiness, ordered drain and resource cleanup
    dependencies/         Shared resources and borrowed registration targets
    api/                  HTTP decoding, responses, middleware and health routes
    mail/                 Message types, SMTP, tracing and optional queued sending
    messaging/            Watermill GoChannel integration
    cli/                  Console and scheduled-command integration
    seeders/              Explicit seed operations
pkg/
  asynqx/                 Native Asynq integration and middleware
  database/               Connections, transactions and telemetry
    migrate/              Reusable Goose registration and execution
  cache/                  Cache contracts, drivers and telemetry
  logging/                Structured logging and context correlation
tests/                    App, cross-module and queue integration suites
examples/                 Standalone capability examples
deployments/              Local and deployment configuration
docs/                     Guide sources and static site

This is a map of the main responsibilities, not an exhaustive package listing. modules groups business code without discovery or a registration catalog. modules/shared holds definitions and is not registered as a module. Platform packages never import business modules, including their shared definitions. Shared definitions import neither those modules, platform packages nor app. Notifications implements database, email and push delivery; Media implements uploads, public/private access, internal/direct URLs and deletion recovery. SMS and media conversions remain extensions.

Package index#

Use the existing capability directly when it fits. App and module assembly pass borrowed resources; independent callers construct only the collaborators they need and own any resources they open. internal packages are usable within a copied application template, not as public libraries imported by an unrelated Go module.

Application or platform package Responsibility and guide
internal/app, platform/lifecycle Construction, process ownership and shutdown
internal/app/config Typed configuration and defaults
dependencies Borrowed Resources and registration Targets
api Routing, validation, middleware and responses
auth Transport-independent authenticated user/session principal
cli Cobra commands and scheduled commands
mail, mail/integration SMTP and optional queued mail; integration installs the existing worker handler
media, media/integration, media/migrations Media assets, transport registration and owned SQL
notification, notification/integration, notification/migrations Channel intent and delivery, transports and owned SQL
messaging, messaging/middleware Local typed events, native Watermill execution and instrumentation
seeders Explicit named seed operations
testdb Disposable integration schemas; test-only, never a production dependency
internal/reference Private syntax checks shared by Media and Notifications; not authorization or a model superclass
Reusable package Responsibility and usage
apperror Safe application errors and inspectable causes
asynqx, asynqx/middleware Native tasks, routing, worker/scheduler lifetime and instrumentation
cache and its memory/database/redis drivers Bounded cache operations; backend semantics remain explicit
database, database/migrate Connections, transactions and Goose migrations
hasher Standalone string hashing; see pkg/hasher/README.md; Identity does not use passwords
httpserver HTTP lifetime and upgraded-connection drain
httpclient Tagged outbound requests, body encodings, middleware and provider integrations
logging Named log outputs and context correlation
mapper Typed collection transformations; inspect with go doc ./pkg/mapper
mailview Embedded HTML/text rendering without a mail transport
metrics, tracing Optional OpenTelemetry providers with explicit ownership
otp, token Cryptographic code/token primitives; Identity owns account policy and session records
pagination Bounded page inputs and responses
push Independent Expo sending and receipt lookup
ratelimit Shared Redis admission; Identity's usage
redis Explicit Redis connection setup; see pkg/redis/README.md; queue/cache/limiter ownership remains separate
storage Native Go CDK buckets; Media adds metadata and recovery

For package-level APIs, run go doc ./internal/platform/notification or go doc ./pkg/storage from the repository root. These commands inspect source without constructing the application. Package READMEs contain additional native usage; they are not all published as separate website pages.

Follow startup#

Read Responsibility
cmd/app/main.go Process entry point and selected services
internal/app/app.go Public entry points and private application state
internal/app/infrastructure.go Acquire resources and register their cleanup
internal/app/auth.go Construct authentication and bind notification delivery's active-session check
internal/app/modules.go Call business registration functions
internal/app/open.go Initialize the application, bind security operations and clean up failures
internal/app/processes.go Select execution, readiness dependencies and shutdown phases
internal/app/schedules.go Declare recurring timing and conditions
internal/app/console.go Execute commands, migrations and table publication
internal/platform/media/library.go Construct and use the media Library
internal/platform/media/integration/register.go Register a constructed Library with selected transports
internal/modules/identity/delivery/http/routes.go Register account, user media, notification and session-bound subscription endpoints
internal/platform/lifecycle/lifecycle.go Supervise readiness, staged drain and resource cleanup

Configuration loads before serving. Registration does not perform I/O or start workers. Open functions acquire connections; New functions assemble borrowed dependencies. App owns cleanup. Use the documented constructor and registration contracts for each capability. All CLI commands, including help, construct the application before execution. See lifecycle and registration.

Grow a module only when needed#

The first module tutorial starts with one file. A module with persistence and several transports can grow into:

internal/modules/<module>/
  register.go             Internal construction and all registrations
  domain/                 Policies and operation errors
  service/
    service.go            Public business-service interfaces
    user.go, auth.go       Private implementations and constructors
    verification.go       Related methods on the same service receiver
    session.go            Substantial authentication use cases
  repository/
    repository.go         Focused persistence interfaces
    user.go, ...          Private repositories, constructors and queries
    transaction.go        Shared transaction helpers
  migrations/             Embedded module-owned SQL
  jobs/                   Native Asynq task types, payloads and constructors
  notifications/          Business notification content and channel choices
  mailviews/              Email content using the shared branded layout
  integrations/           External provider contracts and implementations
  delivery/
    http/                 Requests, responses, routes and handlers
    cli/                  Commands
    events/               Event handlers
    jobs/                 Queue handlers

Create only the directories your behavior needs. A matching interface for every struct, a module registry, and a generic repository are not required. Service and repository directories contain production code only; Identity's public-behavior and persistence tests live under tests/identity.

Preserve ownership across shared definitions#

Business entities and enums belong in shared; each business module retains ownership of its operations and writes. Identity follows this convention. Platform capabilities own their records, inputs, statuses, errors and storage contracts inside their packages. Mail, Media and Notifications register generic transports through integration packages; only persisted capabilities own migrations. These cores import neither app nor Resources. Identity owns user-specific media and notification HTTP operations. The generic public/signed media content route remains in platform; no platform package imports shared business definitions.

Entities may carry Bun mappings where the shapes agree. Do not duplicate an entity merely to populate a models directory. Published business event contracts and occurrence metadata live in internal/modules/shared/events. Producers own the meaning and version; consumers own handlers in delivery/events. Domain errors remain beside their owning module, entity or platform capability, using pkg/apperror for common classification and safe codes.

Each definition has an owner. That module controls writes, queries, mapping and invariants. Shared packages contain neither module services nor configuration or infrastructure setup. Cross-module SQL reads remain deliberate repository-level coupling, not permission to bypass another module's operations.

pkg must not import internal. Put reusable technical behavior there; put application assembly in internal/app and shared technical capabilities in internal/platform.

Locate a change#

Change Location
HTTP input/output Module delivery/http
Business operation or its inputs Module service
Query or persistence mapping Owner's repository
Capability entity, input, error or status Owning platform package
Business event definition internal/modules/shared/events
Job constructor / handler Module jobs / delivery/jobs
Notification content / mail view Module notifications / mailviews
Event handler Module delivery/events
Recurring timing internal/app/schedules.go
Queue routing and priorities internal/app/config/queues.go
Infrastructure acquisition App assembly using pkg constructors
Environment setting internal/app/config
Module SQL internal/modules/<module>/migrations

Register module migration sources through targets.Migrations in register.go. Module and shared SQL use one Goose history with globally unique timestamp versions. Preserve applied migrations and add new versions for schema changes. Normal application startup never runs DDL. See migrations for ordering and rollout, and shared types for definition ownership.

Documentation

Search guides, sections, and API names.