# Sprint Planner Web replacement for an Excel-based sprint planning workbook used by a ~15-person ops/dev team. One sprint per page: an Arbeitstage matrix (working-days availability per worker per week) on top, a task list with per-worker day allocations on the bottom. Proper auth, database, and a per-cell audit trail. ## Stack - PHP 8.3 + Apache (Docker, multi-stage build) - SQLite via PDO (file on a mounted volume) - Server-rendered PHP templates + Tailwind CSS (vendored, compiled by a Node build stage) + jQuery / jQuery UI (CDN) - Microsoft Entra ID (OpenID Connect, Authorization Code + PKCE), with an optional local-admin fallback for dev / on-prem deployments - Dark mode (manual toggle, no FOUC), strict CSP ## Quick setup For a development or pilot install on a single host: ```bash # 1. Clone and enter the repo git clone sprint_planer_web cd sprint_planer_web # 2. Create the .env file from the template cp .env.example .env # 3. Generate a hash for the local-admin password. The app verifies sign-ins # with password_verify() against LOCAL_ADMIN_PASSWORD_HASH, so the # plaintext password never lands on disk. Pick the snippet that matches # what you have installed: # # a) Host PHP 8 (any minor): # php -r 'echo password_hash(readline("Password: "), PASSWORD_DEFAULT), PHP_EOL;' # # b) No host PHP — use the Docker image you already build with: # docker run --rm -it php:8.3-cli php -r \ # 'echo password_hash(readline("Password: "), PASSWORD_DEFAULT), PHP_EOL;' # # Both prompt for the password (no echo on most TTYs) and print a # bcrypt string starting with `$2y$`. Paste it into .env as: # LOCAL_ADMIN_EMAIL='you@example.com' # LOCAL_ADMIN_PASSWORD_HASH='$2y$...' # Use single quotes — the `$` in the hash will otherwise be eaten by the # shell on `docker compose up`. # # For Entra-based sign-in, fill ENTRA_TENANT_ID / ENTRA_CLIENT_ID / # ENTRA_CLIENT_SECRET instead (or in addition). chmod 600 .env # 4. Build and start the container (compose maps host port 8088 → container 80) docker compose up -d --build # 5. Open the app xdg-open http://localhost:8088 # or just visit it in a browser ``` If you signed in via the local-admin fallback you are immediately the administrator (audit-logged as `BOOTSTRAP_ADMIN` with `via=local`). For an OIDC-only deploy, nominate the first admin up front via `BOOTSTRAP_ADMIN_OID` or `BOOTSTRAP_ADMIN_EMAIL` in `.env` — without one of them set the OIDC path will not auto-promote anyone (this closes finding R01-N03 in `doc/REVIEW_01.md`). Subsequent admin promotions happen through the **Users** page in the hamburger menu. The SQLite database is created on first request at `./data/app.sqlite` on the host (mounted into the container at `/var/www/data/app.sqlite`). Migrations run automatically on container start. Wiping `./data/` resets the application to a blank slate. For everything else — Entra app registration, backups, troubleshooting, upgrades — see [`doc/admin-manual.md`](doc/admin-manual.md). ## Layout ``` public/ front controller (index.php) + web root src/ application code (App\ namespace, PSR-4) views/ PHP templates migrations/ numbered .sql files applied by Migrator assets/ Tailwind source (compiled into public/assets/css/app.css) data/ SQLite + sessions (volume-mounted; gitignored) doc/ operator-facing documentation (admin manual) ``` ## Documentation - [`doc/admin-manual.md`](doc/admin-manual.md) — administrator setup, configuration, and operations guide. - [`SPEC.md`](SPEC.md) — full specification: schema, routes, capacity math, build phase history. Read this if you intend to modify the code. - [`ACCEPTANCE.md`](ACCEPTANCE.md) — manual acceptance checklist used to validate releases. ## Tests ```bash vendor/bin/phpunit # → OK (88 tests, 208 assertions) ```