111 lines
3.9 KiB
Markdown
111 lines
3.9 KiB
Markdown
# Architecture Rules (ARCH-01..03)
|
|
|
|
## ARCH-01: Standard Directory Layout (CRITICAL)
|
|
|
|
Every service MUST follow this directory structure:
|
|
|
|
```
|
|
<service>/
|
|
├── domain/<aggregate>/ # Pure business logic, entities, value objects, repository interfaces
|
|
├── app/ # Application struct (app.go) with Commands + Queries
|
|
│ ├── command/ # Write use cases (command handlers)
|
|
│ └── query/ # Read use cases (query handlers + read model interfaces)
|
|
├── ports/ # Inbound adapters: HTTP handlers, gRPC servers, CLI
|
|
├── adapters/ # Outbound adapters: repository implementations, external clients
|
|
└── service/ # Composition root: wires all dependencies together
|
|
```
|
|
|
|
**Check procedure:**
|
|
1. Glob for these directories relative to the service root
|
|
2. Flag any missing standard directories
|
|
3. Flag any non-standard directories at the same level (e.g., `controllers/`, `models/`, `handlers/`)
|
|
4. Multiple aggregates can exist under `domain/` as sub-packages (e.g., `domain/hour/`, `domain/training/`)
|
|
|
|
**Reference (wild-workouts):**
|
|
```
|
|
internal/trainer/
|
|
├── domain/hour/
|
|
├── app/
|
|
│ ├── command/
|
|
│ └── query/
|
|
├── ports/
|
|
├── adapters/
|
|
└── service/
|
|
```
|
|
|
|
---
|
|
|
|
## ARCH-02: Dependency Direction (CRITICAL)
|
|
|
|
Dependencies MUST flow inward only: `ports/adapters → app → domain`
|
|
|
|
The domain layer MUST NOT import from:
|
|
- `app/`, `app/command/`, `app/query/`
|
|
- `ports/`
|
|
- `adapters/`
|
|
- Any external infrastructure package (database drivers, HTTP frameworks, etc.)
|
|
|
|
The app layer MUST NOT import from:
|
|
- `ports/`
|
|
- `adapters/`
|
|
|
|
**Check procedure:**
|
|
1. For every `.go` file in `domain/`, scan import statements
|
|
2. Flag any import that references `app/`, `ports/`, `adapters/`, or the service's own non-domain packages
|
|
3. For every `.go` file in `app/`, scan imports for `ports/` or `adapters/`
|
|
4. Domain MAY import standard library and pure utility packages
|
|
|
|
**Allowed domain imports:**
|
|
- Standard library (`context`, `time`, `errors`, `fmt`, `strings`, etc.)
|
|
- Pure value libraries (e.g., `github.com/google/uuid`)
|
|
- NOT: database drivers, HTTP routers, gRPC, logging libraries
|
|
|
|
---
|
|
|
|
## ARCH-03: Composition Root in service/ (WARNING)
|
|
|
|
All dependency wiring MUST happen in `service/application.go` (or equivalent in `service/`).
|
|
|
|
This file:
|
|
- Creates infrastructure clients (database connections, external service clients)
|
|
- Instantiates adapters (repositories, gRPC clients)
|
|
- Instantiates command/query handlers with their dependencies
|
|
- Returns a fully-wired `app.Application` struct
|
|
- Is the ONLY place that knows about concrete adapter types
|
|
|
|
**Check procedure:**
|
|
1. Look for `service/` directory and `application.go` or similar
|
|
2. Verify it returns `app.Application`
|
|
3. Check that adapter constructors are NOT called outside `service/`
|
|
|
|
**Reference:**
|
|
```go
|
|
// service/application.go
|
|
func NewApplication(ctx context.Context) app.Application {
|
|
// Create infrastructure
|
|
firestoreClient, err := firestore.NewClient(ctx, os.Getenv("GCP_PROJECT"))
|
|
// ...
|
|
|
|
// Create domain factories
|
|
hourFactory, err := hour.NewFactory(hour.FactoryConfig{...})
|
|
|
|
// Create adapters
|
|
hourRepository := adapters.NewFirestoreHourRepository(firestoreClient, hourFactory)
|
|
|
|
// Wire application
|
|
logger := logrus.NewEntry(logrus.StandardLogger())
|
|
metricsClient := metrics.NoOp{}
|
|
|
|
return app.Application{
|
|
Commands: app.Commands{
|
|
CancelTraining: command.NewCancelTrainingHandler(hourRepository, logger, metricsClient),
|
|
ScheduleTraining: command.NewScheduleTrainingHandler(hourRepository, logger, metricsClient),
|
|
},
|
|
Queries: app.Queries{
|
|
HourAvailability: query.NewHourAvailabilityHandler(hourRepository, logger, metricsClient),
|
|
TrainerAvailableHours: query.NewAvailableHoursHandler(datesRepository, logger, metricsClient),
|
|
},
|
|
}
|
|
}
|
|
```
|