Contents

Layers

Layer Path Responsibility
Domain internal/domain/* Entity, value object, domain event, repository port
Application internal/application/* Use case, DTO, orchestration, CQRS command/query
Adapters internal/adapters/{http,goui,persistence,shared} Fiber handler, GoUI, sqlc repo, shared adapter helpers
Infrastructure internal/infrastructure/* Config, DB, JWT/Argon2/TOTP, SMTP, SMS, payment gateway, outbox, cache
Bootstrap internal/bootstrap (Build + wire_*.go) Manual DI; composition root split across wiring files

Domain does not depend on application or outer layers. Application only references domain ports and its own DTOs.

Bounded contexts

Context Domain Application Notes
User domain/user application/user CRUD, profile, soft-delete
Auth domain/auth application/auth Token, MFA, OAuth events
Authz / RBAC domain/rbac application/authz Role/permission aggregate; resolution in authz
Notification domain/notification application/notification Dispatcher, inbox, bulk
Settings domain/settings application/settings Active SMS/payment provider
Payment domain/payment application/payment 3DS, transaction
Contact domain/contact application/contact Public form + admin inbox
Upload domain/upload application/upload Secure file upload
Audit application/audit No domain aggregate; application service
Idempotency / Outbox application/{idempotency,outbox} Infrastructure-backed

Shared domain types: domain/shared.

pkg/ contracts

These are not domain; they are cross-cutting helper packages.

Package Usage
pkg/rbac Perm* constants, Catalog, Checker — aggregate in domain/rbac, use cases in application/authz
pkg/recipients CSV/XLSX recipient import (notification bulk) — distinct from contact form domain/contact
pkg/tabular List export (CSV/XLSX)
pkg/i18n Locale files (locales/tr.json, en.json)
pkg/validation go-playground tag registration + field messages
pkg/pagination Offset/limit helpers
pkg/fieldenc Sensitive field encryption (payment card, etc.)

There is no pkg/user; user lives only under internal/domain/user.

Surfaces (adapters)

HTTP API — internal/adapters/http

  • Registration: server.go/api/v1/...
  • Handlers: handler/*.go
  • Middleware: auth, i18n, idempotency, permission

Summary groups:

  • Public: health, OpenAPI, contact submit, auth login/refresh/oauth, payment callback/webhook
  • Protected: /me, users, notifications send/bulk, rbac, settings, payments, audit, contacts, uploads

GoUI panel — internal/adapters/goui

  • Page routes: routes.gopageRoutes()
  • Controllers: controller_*.go
  • Export: export_routes.go
  • Utilities (OAuth, locale, 3DS start): utility_routes.go

Web session uses HttpOnly cookies; API uses Bearer JWT. Both call the same application use cases.

Example panel paths: /dashboard, /dashboard/users, /dashboard/notifications/bulk, /dashboard/payments/checkout, /dashboard/audit/logs.

Data

Piece Path
Migration migrations/000001_schema.*, 000002_seed.* (embed: migrations.go)
sqlc source db/queries/*.sql
sqlc output internal/adapters/persistence/postgres/db/

During development the schema is kept in a single file (000001). After production launch, incremental migrations are added.

Notification flow (brief)

  1. Use case → Dispatcher (channel: inapp | sms | email)
  2. Recipient resolution: user ID, email, phone, or pkg/recipients parse
  3. In-app: DB record + inbox.updated over /api/v1/ws (panel/mobile/API)
  4. SMS/email: active provider (settings) + worker/async

Related documentation