Stage 7 · Master
Phase 1 — Project Foundation
Go Workspace (go.work)
Compose independently versioned Go modules for local development with go.work, without a root go.mod pretending to own them all.
Why This Repository Never Gets a Root go.mod
A go.mod file declares an importable Go module rooted at the directory that contains it. If hoa-platform had a root go.mod, the whole repository — pkg/, services/, docs/, everything — would be one Go module, and every service would have to import shared code through that single module's path. That directly contradicts ADR 0001: pkg/config, pkg/logging, and services/organization are meant to be independently versioned modules, each free to bump its own go.mod dependencies without forcing a version bump on the others. The tool for composing several independent modules for local development, without merging them into one, is go.work.
go.work is never imported, never published, and (by convention) frequently left out of an image build's Docker context — the Dockerization lesson in Phase 2 revisits this. Its only job is to tell the go command, when run from inside this tree, which modules to resolve locally instead of downloading a tagged version from a proxy.
Creating the Organization Service's First Module
The organization service becomes the first real Go module in the repository. Its module path mirrors its location in the repo — github.com/hoa-platform/backend/services/organization — even though there is no repository-wide module wrapping it; the path is a namespace convention, not proof that a root module exists.
module github.com/hoa-platform/backend/services/organization
go 1.26.0
package main
import "fmt"
func main() {
fmt.Println("organization service placeholder booting")
}
Deliberately trivial. Its only job right now is to prove the module compiles and go.work can see it.
Wiring go.work to See This Module Locally
go 1.26.0
use ./services/organization
Every later lesson that creates a new module — pkg/config, pkg/logging, pkg/apperr — adds one more use line to this same file. go.work.sum, which records checksums for dependencies shared across workspace modules, does not exist yet; it appears automatically the first time two workspace modules pull in overlapping third-party dependencies, starting in the Configuration Management lesson.
What Happens If You Run a Go Command From the Repository Root
Because there is still no root go.mod, running a bare go command from the repository root fails, even though go.work exists there. This is the first concrete evidence of the ADR 0001 decision, and it is worth seeing the exact failure now rather than being surprised by it later.
go: go.mod file not found in current directory or any parent directory.
'go env GOWORK' indicates '/path/to/hoa-platform/go.work' will be used
but 'go.work' is not associated with any module in the current directory
go.work tells Go which modules exist; it does not create an implicit module at the workspace root. Every Go command must run from inside a specific module directory, or use the -C flag introduced in the Makefile lesson.
Verifying the Workspace Resolves Correctly
Applied exercise
Add a second, throwaway module to prove go.work composes more than one module
go.work currently lists one module. Confirm you understand the mechanics by adding a second one before the Folder Structure lesson gives services/organization real internal packages.
- Create pkg/ping with its own go.mod (module github.com/hoa-platform/backend/pkg/ping) and a single exported function Ping() string returning "pong".
- Add it to go.work with go work use ./pkg/ping, run from the repository root.
- From services/organization, temporarily import it in main.go, print the result, and confirm go run ./cmd/api prints pong.
- Revert the import in main.go (keep the pkg/ping module and its go.work entry — it will not be used again in this course, but leaving it demonstrates a workspace can safely hold unused-by-others modules).
Deliverable
A go.work file listing two modules, and a terminal transcript showing go run ./cmd/api printing pong before you revert main.go.
Completion checks
- pkg/ping/go.mod declares its own module path, independent of services/organization.
- go.work lists both use ./services/organization and use ./pkg/ping.
- After reverting main.go's import, go run ./cmd/api still builds and prints the original placeholder message.
Why does `go build ./...` fail when run from the hoa-platform repository root, even though go.work exists there?
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.