--- phase: 01-foundation plan: 01 type: execute wave: 1 depends_on: [] files_modified: - Dockerfile - docker-compose.yml - requirements.txt - requirements-dev.txt - imptune/main.py - imptune/config.py - imptune/api/__init__.py - imptune/api/pages.py - imptune/api/health.py - imptune/templates/base.html - imptune/templates/dashboard.html - imptune/static/app.css - tests/__init__.py - tests/conftest.py - tests/test_health.py - tests/test_static.py autonomous: true requirements: - INFRA-01 - INFRA-02 must_haves: truths: - "Running docker compose up starts the app and serves HTTP 200 on GET /health" - "The container has no Node.js dependency and starts from a single python:3.12-slim-bookworm image" - "All static assets (Pico CSS, HTMX, Alpine.js) are served from /static/ with zero CDN references in templates" - "The app shell displays a sidebar with Dashboard, Drivers, Printers, Clients, Packages sections" - "The app follows OS dark/light theme preference automatically" artifacts: - path: "Dockerfile" provides: "Single-container build with baked-in static assets" contains: "python:3.12-slim-bookworm" - path: "docker-compose.yml" provides: "Container orchestration with named volume" contains: "imptune_data:/data" - path: "imptune/main.py" provides: "FastAPI app entrypoint with static files mount and router registration" exports: ["app"] - path: "imptune/api/health.py" provides: "GET /health endpoint for Docker healthcheck" exports: ["router"] - path: "imptune/templates/base.html" provides: "Layout template with sidebar navigation and static asset includes" contains: "data-theme=\"auto\"" key_links: - from: "Dockerfile" to: "imptune/static/" via: "curl downloads during build" pattern: "curl.*pico\\.min\\.css" - from: "imptune/main.py" to: "imptune/api/health.py" via: "include_router" pattern: "include_router.*health" - from: "imptune/templates/base.html" to: "/static/" via: "link and script tags" pattern: "/static/.*\\.css|/static/.*\\.js" --- Create the Docker container scaffold, FastAPI app shell with sidebar navigation, health endpoint, and all baked-in static assets (Pico CSS, HTMX, Alpine.js). This is the foundation every subsequent plan builds on. Purpose: Establish the running container and app shell that satisfies INFRA-01 (single Docker container) and INFRA-02 (no Node.js, no external DB). All subsequent phases add features to this scaffold. Output: A buildable Docker image that starts, serves the app shell on localhost:8000, and passes healthcheck. @C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md @C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/01-foundation/01-CONTEXT.md @.planning/phases/01-foundation/01-RESEARCH.md Task 1: Create Docker scaffold, FastAPI app, and app shell templates Dockerfile, docker-compose.yml, requirements.txt, imptune/__init__.py, imptune/main.py, imptune/config.py, imptune/api/__init__.py, imptune/api/pages.py, imptune/api/health.py, imptune/templates/base.html, imptune/templates/dashboard.html, imptune/static/app.css Create the full project scaffold following the architecture from RESEARCH.md. The app package is `imptune/` (not top-level modules). **Dockerfile** (python:3.12-slim-bookworm base): - WORKDIR /app - Single RUN layer: apt-get install curl, mkdir -p /app/imptune/static, download Pico CSS v2 (pico.min.css), HTMX 2.x (htmx.min.js), Alpine.js 3.x (alpine.min.js) into /app/imptune/static/ using curl with --fail flag, then purge curl and clean apt cache - COPY requirements.txt and pip install --no-cache-dir - COPY imptune/ into /app/imptune/ and other root files - VOLUME ["/data"] - HEALTHCHECK using python stdlib urllib (not curl): `python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"` - EXPOSE 8000 - CMD ["uvicorn", "imptune.main:app", "--host", "0.0.0.0", "--port", "8000"] **docker-compose.yml**: - Service `imptune`, build context `.`, ports 8000:8000, volume `imptune_data:/data`, restart unless-stopped, env DATA_DIR=/data **requirements.txt** (all dependencies for phases 1-5): - fastapi==0.115.*, uvicorn[standard]==0.30.*, jinja2==3.1.*, python-multipart==0.0.9, pycryptodome==3.20.*, python-dotenv==1.0.*, peewee==3.17.* **imptune/config.py**: - Load DATA_DIR from env (default "/data"), PORT from env (default 8000) - Derive DB_PATH as DATA_DIR/imptune.db, DRIVERS_DIR as DATA_DIR/drivers **imptune/main.py**: - Create FastAPI app (title="ImpTune") - Mount StaticFiles from pathlib.Path(__file__).parent / "static" at "/static" - Set up Jinja2Templates pointing to imptune/templates/ - Include health router and pages router - Add startup event that creates DATA_DIR and DRIVERS_DIR directories if they don't exist **imptune/api/health.py**: - GET /health returning {"status": "ok"} **imptune/api/pages.py**: - GET / returning dashboard.html template (sync def, not async) - Pass empty recent_printers=[] and recent_packages=[] context for now **imptune/templates/base.html**: - html lang="en" data-theme="auto" (Pico CSS auto dark/light) - Head: meta charset, viewport, title "ImpTune", link to /static/pico.min.css, link to /static/app.css, script defer for alpine.min.js, script for htmx.min.js - Body: flex container with persistent left sidebar nav and main content area - Sidebar: flat equal-weight nav links for Dashboard (/), Drivers (/drivers), Printers (/printers), Clients (/clients), Packages (/packages). Use semantic nav element. Active link highlighted. - Main: container class wrapping {% block content %}{% endblock %} **imptune/templates/dashboard.html**: - Extends base.html - Quick action buttons at top: "New Printer", "Upload Driver", "Export Package" (links, non-functional in Phase 1 — link to # with disabled state) - Recent activity section below: empty state message "No printers configured yet" and "No packages exported yet" **imptune/static/app.css** (under 50 lines): - Sidebar layout: flex, sidebar fixed width ~220px, main flex-grow - Sidebar nav styling: vertical link list, active state highlight - Quick action button row styling - Keep minimal — Pico CSS handles most styling All __init__.py files: empty or minimal. cd C:/Users/SebastienQUEROL/Documents/projets/ImpTune && python -c "from imptune.main import app; print('App created:', app.title)" - All files exist with correct content - FastAPI app imports without errors - Dockerfile builds (docker build .) - docker-compose.yml is valid YAML - Templates reference /static/ paths only (no CDN URLs) - Sidebar has all 5 sections with equal weight - data-theme="auto" is set on html element Task 2: Create test scaffold and write health + static asset tests requirements-dev.txt, tests/__init__.py, tests/conftest.py, tests/test_health.py, tests/test_static.py - test_health_returns_200: GET /health returns 200 with {"status": "ok"} - test_static_mount_exists: app has /static mount - test_no_cdn_urls_in_templates: scanning all .html files in imptune/templates/ finds zero references to cdn.jsdelivr.net, unpkg.com, cdnjs.com, or any https:// URL in link/script tags - test_dashboard_returns_200: GET / returns 200 **requirements-dev.txt**: pytest, httpx (for FastAPI TestClient alternative — use fastapi.testclient which uses httpx internally) **tests/conftest.py**: - Import TestClient from fastapi.testclient (uses httpx under the hood) - Fixture `client` that creates TestClient(app) from imptune.main - Fixture `tmp_data_dir` using tmp_path that sets DATA_DIR env var to a temp directory before importing app, and creates the temp SQLite path **tests/test_health.py**: - test_health_returns_200: client.get("/health") returns 200 and JSON body {"status": "ok"} **tests/test_static.py**: - test_no_cdn_urls_in_templates: glob all .html files in imptune/templates/, read each, assert no matches for CDN domains (cdn.jsdelivr.net, unpkg.com, cdnjs.com) or https:// in href/src attributes - test_dashboard_returns_200: client.get("/") returns 200 Run tests to confirm they pass (GREEN). The no-CDN test validates INFRA-02 at the template level. cd C:/Users/SebastienQUEROL/Documents/projets/ImpTune && pip install -r requirements-dev.txt -q && python -m pytest tests/test_health.py tests/test_static.py -x -v - All 4 tests pass - Health endpoint verified via TestClient - No CDN URLs found in any template - Dashboard page loads successfully - `python -m pytest tests/ -x -v` — all tests pass - `python -c "from imptune.main import app; print(app.title)"` — prints "ImpTune" - Visually inspect templates for /static/ references only (automated by test_no_cdn_urls) - `docker compose build` succeeds (if Docker available) - FastAPI app starts and serves GET /health with 200 - Dashboard page renders with sidebar navigation (5 sections) - All static assets referenced via /static/ paths, zero CDN URLs - Docker image builds from python:3.12-slim-bookworm with no Node.js - Test suite passes with 4+ green tests After completion, create `.planning/phases/01-foundation/01-01-SUMMARY.md`