ADR-010: Go Workspace Structure
Status
Accepted
Context
We need to organize our Go modules for dependency isolation while maintaining a single repository.
Decision
We will use Go workspaces (go.work) with separate go.mod files for each module.
Directory Structure
prescriptoo-api/
├── go.work # Workspace definition
├── go.work.sum
├── pkg/ # Shared packages
│ ├── api/ # Huma/Chi setup
│ ├── config/ # Env var helpers
│ ├── errors/ # AppError type
│ ├── events/ # Event bus interface
│ ├── infrastructure/ # Postgres, Redis
│ └── logger/ # Structured logging
├── services/ # Business services
│ ├── api/ # Single entry point
│ ├── admin/ # Admin service
│ ├── authorization/ # Scoped roles, permissions and overrides (ADR-017)
│ ├── health/ # Health check
│ ├── doctor/ # Professional profiles and onboarding (ADR-013)
│ ├── identity/ # Identity service
│ ├── notification/ # Notification service
│ ├── organization/ # Organization service
│ ├── patient/ # Patient profiles and search (ADR-015)
│ ├── prescription/ # Prescription service
│ └── subscription/ # Subscription service
├── proto/ # Protobuf definitions
├── deploy/ # Docker, K8s configs
├── docs/ # Documentation
│ └── adr/ # Architecture Decision Records
├── scripts/ # Build scripts
└── migrations/ # Database migrationsModule Organization
Shared Packages (pkg/)
Each package has its own go.mod:
pkg/config/go.mod → github.com/prescriptoo/prescriptoo-api/pkg/config
pkg/errors/go.mod → github.com/prescriptoo/prescriptoo-api/pkg/errors
pkg/events/go.mod → github.com/prescriptoo/prescriptoo-api/pkg/eventsServices (services/)
Each service has its own go.mod with replace directives:
// services/identity/go.mod
module github.com/prescriptoo/prescriptoo-api/services/identity
require (
github.com/prescriptoo/prescriptoo-api/pkg/config v0.0.0
github.com/prescriptoo/prescriptoo-api/pkg/events v0.0.0
)
replace (
github.com/prescriptoo/prescriptoo-api/pkg/config => ../../pkg/config
github.com/prescriptoo/prescriptoo-api/pkg/events => ../../pkg/events
)Internal Packages
Each service uses internal/ for private packages:
services/identity/
├── module/ # Composition and capability facades
│ └── module.go
├── public/ # Curated DTOs, capabilities and stable errors (ADR-012)
└── internal/ # Private (cannot be imported)
├── domain/
├── ports/
├── usecase/
├── adapters/
└── presentation/Patient and Prescription each have their own go.mod/go.sum and are included in go.work. Their module packages register HTTP contracts in the single API process; separate Go modules do not imply separate deployments. Runtime and offline OpenAPI composition register both services. Public DTOs remain distinct from internal persistence entities, and Patient has no dependency on Prescription (ADR-015).
Why Go Workspaces?
| Aspect | Single Module | Go Workspaces |
|---|---|---|
| Dependency isolation | No | Yes (each module has own go.mod) |
| Build all at once | Yes | Yes (explicit workspace module patterns) |
| Extract service | Hard | Easy (copy directory) |
| IDE support | Good | Good |
Consequences
Positive
- Dependency isolation per module
- Easy to extract services later
- Single repository for code sharing
go work syncupdates all modules
Negative
- More
go.modfiles to manage - Need
replacedirectives for local packages
Related Decisions
ADR-001: Modular Monolith Architecture