Skip to content

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 migrations

Module 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/events

Services (services/) ​

Each service has its own go.mod with replace directives:

go
// 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? ​

AspectSingle ModuleGo Workspaces
Dependency isolationNoYes (each module has own go.mod)
Build all at onceYesYes (explicit workspace module patterns)
Extract serviceHardEasy (copy directory)
IDE supportGoodGood

Consequences ​

Positive ​

  • Dependency isolation per module
  • Easy to extract services later
  • Single repository for code sharing
  • go work sync updates all modules

Negative ​

  • More go.mod files to manage
  • Need replace directives for local packages

Documentation follows the source. Planned contracts are marked explicitly.