# Phase 14: Volumes & Environment **Status:** ⬜ Not Started **Parent plan:** [PLAN.md](./PLAN.md) **Domain:** fullstack ## Objective Implement per-project environment variables with per-stage overrides, volume mounts with shared/isolated modes, sensitive env value encryption, and UI for managing both. ## Tasks - [ ] Task 1: Extend store schema — add `stage_env` table for per-stage env overrides (stage_id, key, value, encrypted bool) - [ ] Task 2: Extend store schema — add `volumes` table for volume config (project_id, source, target, mode: shared|isolated) - [ ] Task 3: Implement store CRUD for stage env overrides (Create, GetByStageID, Update, Delete) - [ ] Task 4: Implement store CRUD for volumes (Create, GetByProjectID, Update, Delete) - [ ] Task 5: Encrypt sensitive env values (values marked as secret) using crypto.Encrypt before storage - [ ] Task 6: Merge env vars during deploy — project-level env + stage-level overrides, decrypt secrets - [ ] Task 7: Compute volume mounts during deploy — shared mode uses path as-is, isolated mode appends `/{stage}-{tag}/` to source - [ ] Task 8: Pass merged env vars and volume mounts to Docker container creation - [ ] Task 9: API endpoints — CRUD for stage env vars and project volumes - [ ] Task 10: Frontend — env var editor in project/stage settings (key/value pairs, secret toggle) - [ ] Task 11: Frontend — volume editor in project settings (source/target/mode) - [ ] Task 12: Frontend — per-stage env override UI showing inherited vs overridden values ## Files to Modify/Create - `internal/store/stage_env.go` — stage env CRUD - `internal/store/volumes.go` — volume CRUD - `internal/store/store.go` — add new tables to schema - `internal/deployer/deployer.go` — merge env vars and compute volume mounts during deploy - `internal/docker/container.go` — accept volume mounts in ContainerConfig - `internal/api/stages.go` — add env var endpoints - `internal/api/projects.go` — add volume endpoints - `web/src/routes/projects/[id]/env/+page.svelte` — env var editor - `web/src/routes/projects/[id]/volumes/+page.svelte` — volume editor ## Acceptance Criteria - Project-level env vars applied to all containers - Stage-level overrides replace project-level values for matching keys - Sensitive env values encrypted at rest, decrypted only during deploy - Shared volumes: all instances mount same host path - Isolated volumes: each instance gets `{source}/{stage}-{tag}/` subdirectory - UI allows managing env vars and volumes per project and per stage ## Notes - Project `env` field already exists as JSON blob in the store — this phase may migrate to a proper table or keep JSON and add stage overrides separately - Volume `mode` is either "shared" or "isolated" - Isolated volume subdirectory is created automatically by Docker (bind mount creates parent dirs) - Sensitive env display: masked in UI, "Change" button pattern (same as credentials page) ## Review Checklist - [ ] All tasks completed - [ ] Env merge logic is correct (stage overrides project) - [ ] Secret values never appear in plaintext in API responses - [ ] Volume paths are validated (no path traversal) - [ ] Isolated volume subdirectory naming is deterministic ## Handoff to Next Phase