docs(01): create phase 1 foundation plans
Phase 01: Foundation - 2 plans in 2 waves - Plan 01: Go project + Dockerfile (wave 1) - Plan 02: Dev environment + verification (wave 2) - Ready for execution Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
202
.planning/phases/01-foundation/01-01-PLAN.md
Normal file
202
.planning/phases/01-foundation/01-01-PLAN.md
Normal file
@@ -0,0 +1,202 @@
|
||||
---
|
||||
phase: 01-foundation
|
||||
plan: 01
|
||||
type: execute
|
||||
wave: 1
|
||||
depends_on: []
|
||||
files_modified:
|
||||
- go.mod
|
||||
- go.sum
|
||||
- cmd/server/main.go
|
||||
- internal/health/handler.go
|
||||
- docker/Dockerfile
|
||||
- .dockerignore
|
||||
autonomous: true
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "Go module initializes without errors"
|
||||
- "Go server compiles to a single binary"
|
||||
- "Docker image builds successfully for linux/amd64"
|
||||
- "Built image is less than 150MB (debian slim + static binary)"
|
||||
artifacts:
|
||||
- path: "go.mod"
|
||||
provides: "Go module definition"
|
||||
contains: "module"
|
||||
- path: "cmd/server/main.go"
|
||||
provides: "Application entry point"
|
||||
contains: "func main()"
|
||||
- path: "internal/health/handler.go"
|
||||
provides: "Health check endpoint handler"
|
||||
contains: "func Handler"
|
||||
- path: "docker/Dockerfile"
|
||||
provides: "Multi-stage build definition"
|
||||
contains: "FROM golang"
|
||||
- path: ".dockerignore"
|
||||
provides: "Build context exclusions"
|
||||
contains: ".git"
|
||||
key_links:
|
||||
- from: "cmd/server/main.go"
|
||||
to: "internal/health"
|
||||
via: "import statement"
|
||||
pattern: "internal/health"
|
||||
- from: "docker/Dockerfile"
|
||||
to: "cmd/server"
|
||||
via: "go build command"
|
||||
pattern: "go build.*cmd/server"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Create Go project structure and multi-stage Dockerfile for isolated container builds.
|
||||
|
||||
Purpose: Establishes the foundational artifacts needed to build and run the Pirate Station backend. This plan creates the Go module with a minimal HTTP server and the multi-stage Dockerfile that produces a portable ARM64/x86_64 binary.
|
||||
|
||||
Output: Buildable Go project with Dockerfile that produces a slim container image.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@/home/acty/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@/home/acty/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/phases/01-foundation/01-CONTEXT.md
|
||||
@.planning/phases/01-foundation/01-RESEARCH.md
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Initialize Go project with HTTP server</name>
|
||||
<files>
|
||||
go.mod
|
||||
go.sum
|
||||
cmd/server/main.go
|
||||
internal/health/handler.go
|
||||
</files>
|
||||
<action>
|
||||
1. Initialize Go module:
|
||||
```bash
|
||||
go mod init github.com/acty/pirate-station
|
||||
```
|
||||
(Use github.com path even though pushing to Gitea - conventional Go module naming)
|
||||
|
||||
2. Create cmd/server/main.go with:
|
||||
- Import net/http and internal/health
|
||||
- http.HandleFunc for "/" returning "Pirate Station API"
|
||||
- http.HandleFunc for "/health" using health.Handler
|
||||
- ListenAndServe on :32768
|
||||
- log.Fatal on server error
|
||||
- Log startup message with port number
|
||||
|
||||
3. Create internal/health/handler.go with:
|
||||
- package health
|
||||
- Handler(w http.ResponseWriter, r *http.Request) function
|
||||
- Check os.Stat("/data") - return 503 if not exists
|
||||
- Return 200 with {"status":"healthy"} JSON if /data exists
|
||||
- Return 503 with {"status":"unhealthy","reason":"data volume not mounted"} if not
|
||||
|
||||
4. Run `go mod tidy` to create go.sum
|
||||
|
||||
Keep it minimal - no frameworks, no external dependencies, pure stdlib.
|
||||
</action>
|
||||
<verify>
|
||||
```bash
|
||||
go build -o /tmp/server ./cmd/server && echo "Build successful"
|
||||
```
|
||||
</verify>
|
||||
<done>
|
||||
- go.mod exists with module path
|
||||
- cmd/server/main.go compiles
|
||||
- internal/health/handler.go provides health check
|
||||
- No external dependencies (only stdlib)
|
||||
</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Create multi-stage Dockerfile</name>
|
||||
<files>
|
||||
docker/Dockerfile
|
||||
.dockerignore
|
||||
</files>
|
||||
<action>
|
||||
1. Create docker/Dockerfile with multi-stage build:
|
||||
|
||||
Build stage:
|
||||
- FROM --platform=$BUILDPLATFORM golang:1.25-bookworm AS builder
|
||||
- WORKDIR /build
|
||||
- COPY go.mod go.sum ./ (cache dependencies separately)
|
||||
- RUN go mod download
|
||||
- COPY . .
|
||||
- ARG TARGETOS TARGETARCH
|
||||
- RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -ldflags="-w -s" -o /server ./cmd/server
|
||||
|
||||
Runtime stage:
|
||||
- FROM debian:bookworm-slim
|
||||
- RUN useradd -u 10001 -m appuser
|
||||
- USER appuser
|
||||
- COPY --from=builder /server /usr/local/bin/server
|
||||
- VOLUME /data
|
||||
- EXPOSE 32768
|
||||
- CMD ["server"]
|
||||
|
||||
2. Create .dockerignore at project root:
|
||||
```
|
||||
.git
|
||||
.gitignore
|
||||
README.md
|
||||
*.md
|
||||
.env
|
||||
.env.local
|
||||
.DS_Store
|
||||
.air.toml
|
||||
docker-compose.yml
|
||||
.planning/
|
||||
tmp/
|
||||
```
|
||||
|
||||
Key points:
|
||||
- Use --platform=$BUILDPLATFORM for native build speed
|
||||
- CGO_ENABLED=0 for static binary (no libc dependency)
|
||||
- -ldflags="-w -s" strips debug symbols (smaller binary)
|
||||
- Non-root user (appuser) for security
|
||||
- VOLUME /data declares mount point
|
||||
- Port 32768 as per user decision
|
||||
</action>
|
||||
<verify>
|
||||
```bash
|
||||
docker build -f docker/Dockerfile -t pirate-station:test . && docker images pirate-station:test --format "{{.Size}}"
|
||||
```
|
||||
Image should build and be under 150MB.
|
||||
</verify>
|
||||
<done>
|
||||
- docker/Dockerfile exists with multi-stage build
|
||||
- .dockerignore excludes non-essential files
|
||||
- Image builds successfully
|
||||
- Image size under 150MB (debian slim + Go binary)
|
||||
</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
1. Go project compiles: `go build ./...`
|
||||
2. Docker image builds: `docker build -f docker/Dockerfile -t pirate-station:test .`
|
||||
3. Container starts: `docker run --rm -v /tmp/test-data:/data pirate-station:test &` then `curl localhost:32768/health`
|
||||
4. Container cannot access host filesystem outside /data mount
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- Go module initialized with github.com/acty/pirate-station
|
||||
- HTTP server listens on :32768
|
||||
- /health endpoint returns JSON status
|
||||
- Dockerfile produces working image under 150MB
|
||||
- Image runs as non-root user
|
||||
- No external Go dependencies (stdlib only)
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/01-foundation/01-01-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user