Skip to content

feat: multi-stage Docker build + e2e test suite#2

Merged
bupao merged 3 commits intomainfrom
feat/docker-multistage-build
Mar 10, 2026
Merged

feat: multi-stage Docker build + e2e test suite#2
bupao merged 3 commits intomainfrom
feat/docker-multistage-build

Conversation

@bupao
Copy link
Contributor

@bupao bupao commented Mar 10, 2026

Summary

  • Multi-stage Dockerfile: TypeScript compiles inside Docker (builder stage), eliminating local Node.js requirement for image builds
  • Native addon fix: Explicit npm rebuild better-sqlite3 after --ignore-scripts install to compile the .node binding for the target platform
  • E2e test suite: scripts/e2e-test.sh — 26 automated test cases covering the full Docker workflow
  • Build tooling: .dockerignore for faster context, Makefile/picoclaw.sh updated to remove local build dependencies

Changes

Dockerfile (multi-stage build)

  • Stage 1 (builder): npm ci + npm run build — compiles TypeScript
  • Stage 2 (runtime): npm ci --omit=dev --ignore-scripts + npm rebuild better-sqlite3 — production deps with native addon
  • COPY --from=builder /build/dist/ ./dist/ — only compiled output enters runtime image

Build tooling

  • Makefile: docker-build and docker-build-lambda no longer depend on build-ts
  • picoclaw.sh: build_image() removed npm run build step
  • .dockerignore: excludes node_modules, dist, dev-data, docs, .git

E2e test suite (scripts/e2e-test.sh)

26 test cases in 9 sections:

Section Tests
Health check GET /health returns status=ok
Authentication No token → 401, wrong token → 401
Multi-turn conversation 4 rounds: establish identity → recall name → recall 3 facts → summarize
Conversation isolation New conversation has no knowledge of previous
Task CRUD Create → list → update → check → delete
Skills & memory Skill sync verified, persona CLAUDE.md accessible
Container restart Graceful stop → DB sync → restart → session resume with full context
Error handling Non-existent conversation → 404
Graceful shutdown POST /control/stop → container exits cleanly

Usage:

make test-e2e              # full: build + all tests (requires .env with API credentials)
make test-e2e-quick        # skip build and Claude API calls
./scripts/e2e-test.sh --no-build   # use existing image
./scripts/e2e-test.sh --no-chat    # skip tests that call Claude API

Documentation

  • CLAUDE.md: Docker workflow section updated
  • CHANGELOG.md: unreleased changes documented
  • docs/SERVERLESS_API_DEPLOYMENT_GUIDE.md: multi-stage build docs, troubleshooting updated

Test results

── 1. Health Check ──
  PASS GET /health returns status=ok
── 2. Authentication ──
  PASS No token → 401
  PASS Wrong token → 401
── 3. Multi-Turn Conversation ──
  PASS Round 1: conversation created
  PASS Persona: agent identifies as TestBot
  PASS Round 2: agent recalls name 'Kevin'
  PASS Round 3: agent recalls all 3 facts (Kevin, Rust, Mochi)
  PASS Round 4: 4-turn conversation completed
  PASS Metadata: 8 messages, status=idle
── 4. Conversation Isolation ──
  PASS Isolation: new conversation_id
  PASS Isolation: agent reports no knowledge of Kevin
── 5. Task CRUD ──
  PASS Create/List/Update/Check/Delete
── 6. Skills & Memory ──
  PASS Skills synced, Persona accessible
── 7. Container Restart Persistence ──
  PASS Graceful stop → DB sync → restart → session resume (Mochi + Rust)
── 8. Error Handling ──
  PASS Non-existent conversation → 404
── 9. Graceful Shutdown ──
  PASS Container exited cleanly

Total: 26  Pass: 26  Fail: 0  Skip: 0

Test plan

  • npm run build — TypeScript compiles cleanly
  • npm test — 16 unit tests pass
  • npm run format:check — Prettier formatting verified
  • docker build --platform linux/amd64 — image builds successfully
  • ./scripts/e2e-test.sh — 26/26 e2e tests pass in Docker container
  • Documentation consistency across CLAUDE.md, CHANGELOG.md, deployment guide

🤖 Generated with Claude Code

bupao and others added 3 commits March 10, 2026 19:24
Eliminates the local Node.js requirement for Docker image builds.
TypeScript now compiles inside the builder stage, and the runtime
stage copies only the compiled output. Also removes the build-ts
dependency from Makefile docker targets and the npm-run-build step
from picoclaw.sh.

- Add .dockerignore for faster build context transfer
- Use --ignore-scripts in runtime npm ci to avoid husky errors
- Update docs (CLAUDE.md, deployment guide, changelog) for consistency

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
--ignore-scripts skips all lifecycle scripts including better-sqlite3's
postinstall which compiles the native .node binding. Add an explicit
npm rebuild step so the addon is compiled for the target platform.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Automated test script (scripts/e2e-test.sh) covering 26 test cases:
- Health check and auth rejection
- 4-round multi-turn conversation with context recall
- Conversation isolation between users
- Task CRUD (create, list, update, check, delete)
- Skills sync and persona verification
- Container restart persistence with session resume
- Graceful shutdown and clean exit

Usage: make test-e2e (full) or make test-e2e-quick (no build/API)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@bupao bupao changed the title feat: convert Dockerfile to multi-stage build feat: multi-stage Docker build + e2e test suite Mar 10, 2026
@bupao bupao merged commit 213076d into main Mar 10, 2026
1 check passed
@bupao bupao deleted the feat/docker-multistage-build branch March 10, 2026 13:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant