Commit initial
This commit is contained in:
@@ -0,0 +1,238 @@
|
||||
---
|
||||
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"
|
||||
---
|
||||
|
||||
<objective>
|
||||
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.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/01-foundation/01-CONTEXT.md
|
||||
@.planning/phases/01-foundation/01-RESEARCH.md
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Create Docker scaffold, FastAPI app, and app shell templates</name>
|
||||
<files>
|
||||
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
|
||||
</files>
|
||||
<action>
|
||||
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.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd C:/Users/SebastienQUEROL/Documents/projets/ImpTune && python -c "from imptune.main import app; print('App created:', app.title)"</automated>
|
||||
</verify>
|
||||
<done>
|
||||
- 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
|
||||
</done>
|
||||
</task>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 2: Create test scaffold and write health + static asset tests</name>
|
||||
<files>
|
||||
requirements-dev.txt,
|
||||
tests/__init__.py,
|
||||
tests/conftest.py,
|
||||
tests/test_health.py,
|
||||
tests/test_static.py
|
||||
</files>
|
||||
<behavior>
|
||||
- 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
|
||||
</behavior>
|
||||
<action>
|
||||
**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.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>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</automated>
|
||||
</verify>
|
||||
<done>
|
||||
- All 4 tests pass
|
||||
- Health endpoint verified via TestClient
|
||||
- No CDN URLs found in any template
|
||||
- Dashboard page loads successfully
|
||||
</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
- `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)
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- 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
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/01-foundation/01-01-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user