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