# Acceptance checklist (spec §10) — walkthrough This is the checklist from the spec. Run it against a fresh container after Phase 7 lands. Expected outcome is noted next to each step; edit this file (and open a bug) if any step deviates. ## Setup ```bash docker compose down && rm -rf data/app.sqlite docker compose up --build ``` `.env` should have EITHER valid `ENTRA_*` values OR `LOCAL_ADMIN_EMAIL` + `LOCAL_ADMIN_PASSWORD` set. Below, "sign in" means whichever flow you configured. ## Steps 1. **Fresh container, empty DB → sign in → you're the admin.** - Open http://localhost:8080. - If OIDC configured, click **Sign in with Microsoft** → complete Entra round-trip. If local admin configured, click **Sign in as local admin** and enter the env credentials. - Expected: header shows your display name + `admin` badge. `SELECT is_admin FROM users LIMIT 1` in `data/app.sqlite` returns 1. `audit_log` has rows: `CREATE user / BOOTSTRAP_ADMIN user / LOGIN user`. 2. **Create a sprint with 4 weeks.** - Header → **New sprint** → name "Sprint 1", reasonable dates, reserve 20%, weeks = 4 → Create sprint. - Expected: redirect to `/sprints/1`; empty-state banner says "No workers". Clicking **Settings** opens the settings page. The weeks table shows 4 rows with max_working_days 5.0 each and ISO week numbers computed from the start date. 3. **Add 6 workers, reorder by dragging — reload persists order.** - Header → **Workers** → add Alice, Bob, Carol, Dan, Eve, Frank. - Back to `/sprints/1/settings` → add all 6 to the sprint via **Add →** buttons. - Drag the "≡" handles to reorder (e.g. reverse order). - Reload the page. - Expected: the reordered sequence persists. `audit_log` shows `UPDATE sprint_worker` rows for every moved row (unchanged rows emit nothing thanks to the no-op rule). 4. **Fill Arbeitstage; Ressourcen / Reserven / Available update live.** - Open `/sprints/1` → edit a day cell (0.5-step input). - Blur the input. - Expected: Σ column updates immediately, the capacity strip updates (`Ressourcen`, `− Reserven`, `Available`). Status pill flashes "Saved N cell(s)". `audit_log` has one `CREATE sprint_worker_days` row per edited cell. 5. **Add tasks, assign days — Tot updates; over-commit turns Available red but still saves.** - In Section B: click **+ Add task** → focus jumps to the title input → type "Report for Q1", set priority 1, assign 10 days to one worker whose capacity is 8. - Expected: `Tot` cell shows 10; that worker's `Available` in the capacity strip goes negative and turns red. The assignment is persisted (reload still shows 10); `audit_log` has `CREATE task` + `CREATE task_assignment`. 6. **Sort task table by Owner, then by a worker column; clear → original drag order returns.** - Click the `Owner` header — rows sort asc, header shows "↑". - Click again — desc, "↓". - Click any worker column header — sorts by that cell's days. - Click the same header a third time (or any other until cleared) — the rows return to `data-sort-order` (the drag-persisted order). - Expected: no 500s, no layout shift, drag is disabled while a sort is active. 7. **Filter tasks: Prio=1, Owner=X, free-text "report".** - Set prio filter to "Prio 1 only", owner to a specific worker, type "report" into the search box. - Expected: only matching rows stay visible. The "No tasks match the current filters" banner appears when every row is hidden. 8. **Rename a worker in `/workers` — reflected everywhere.** - Header → **Workers** → change "Alice" to "Alice Cooper" → Save. - Open `/sprints/1` in another tab. - Expected: Arbeitstage row label, task list column header, and the Owner dropdowns all show the new name. `audit_log` has an `UPDATE worker` row. 9. **/audit shows one row per change with diffs visible.** - Header → **Audit log**. - Expected: reverse-chronological table with 50/page pagination. Every change you made is there. Each row's "before / after" `
` opens to show pretty-printed JSON snapshots. - Filter by user / action / entity type / date range / entity_id substring — narrow the list. 10. **Sign out; unauthenticated → redirect to /auth/login.** - Click **Sign out**. - Expected: session cleared, `audit_log` has a `LOGOUT user` row. - Try visiting `/workers` or `/sprints/1/settings` while anonymous → redirected to `/auth/login` (and then Entra, or the local form). ## Spot-check (spec §12) If you have `Tool_Sprint_PlanningSample.xlsx` handy: - Pick a worker with known weekly availability (e.g. 4-4-5-5-2). `Ressourcen` should match Excel: sum across weeks. - `− Reserven` should match: `round_to_0.5(Ressourcen * 0.8)` with reserve = 20 %. - For a prio-1 task totalling N days on that worker, `Available` should be `(Ressourcen − Reserven) − N`, and turn red when negative. ## Security headers (spec §9) With the app running, `curl -I http://localhost:8080/` should report: ``` X-Content-Type-Options: nosniff X-Frame-Options: DENY Referrer-Policy: strict-origin-when-cross-origin Content-Security-Policy: default-src 'self'; script-src 'self' …; … ``` `Strict-Transport-Security` appears only when `APP_BASE_URL` uses `https://`.