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.go→pageRoutes() - 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)
- Use case →
Dispatcher(channel:inapp|sms|email) - Recipient resolution: user ID, email, phone, or
pkg/recipientsparse - In-app: DB record +
inbox.updatedover/api/v1/ws(panel/mobile/API) - SMS/email: active provider (settings) + worker/async
Related documentation
- First read / golden path → READING.md
- Context maps → map/ (
user,auth,contact,notification,audit) - Auth/RBAC details → AUTH.md
- Payments → PAYMENT.md
- New module → YENI_MODUL_EKLEME.md