|
@@ -72,27 +72,38 @@ per-cell audit trail.
|
|
|
│ │ SprintWorkerDayRepository, TaskRepository,
|
|
│ │ SprintWorkerDayRepository, TaskRepository,
|
|
|
│ │ TaskAssignmentRepository, AuditRepository
|
|
│ │ TaskAssignmentRepository, AuditRepository
|
|
|
│ └── Services/ AuditLogger, CapacityCalculator
|
|
│ └── Services/ AuditLogger, CapacityCalculator
|
|
|
-├── migrations/ 001_init.sql (full schema per spec §3)
|
|
|
|
|
|
|
+├── migrations/ 001_init.sql (full schema per spec §3)
|
|
|
|
|
+│ 002_sprint_week_active_days.sql (Phase 12 — mask column)
|
|
|
├── views/ layout.php, home.php, auth/local.php,
|
|
├── views/ layout.php, home.php, auth/local.php,
|
|
|
│ workers/index.php, users/index.php,
|
|
│ workers/index.php, users/index.php,
|
|
|
│ sprints/{new,show,settings}.php,
|
|
│ sprints/{new,show,settings}.php,
|
|
|
│ audit/index.php
|
|
│ audit/index.php
|
|
|
├── tests/ TestCase + Services/ + Repositories/ + Controllers/ + Cascade/
|
|
├── tests/ TestCase + Services/ + Repositories/ + Controllers/ + Cascade/
|
|
|
|
|
+│ + Domain/ + Db/
|
|
|
└── data/ SQLite + sessions directory (volume-mounted, gitignored)
|
|
└── data/ SQLite + sessions directory (volume-mounted, gitignored)
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-## 4. Schema (migrations/001_init.sql)
|
|
|
|
|
|
|
+## 4. Schema (migrations/001_init.sql + 002_sprint_week_active_days.sql)
|
|
|
|
|
|
|
|
Tables (already applied): `users`, `workers`, `sprints`, `sprint_weeks`,
|
|
Tables (already applied): `users`, `workers`, `sprints`, `sprint_weeks`,
|
|
|
`sprint_workers`, `sprint_worker_days`, `tasks`, `task_assignments`,
|
|
`sprint_workers`, `sprint_worker_days`, `tasks`, `task_assignments`,
|
|
|
`audit_log`, plus the `schema_version` tracking table.
|
|
`audit_log`, plus the `schema_version` tracking table.
|
|
|
|
|
|
|
|
|
|
+`sprint_weeks.active_days_mask INTEGER NOT NULL DEFAULT 31` (Phase 12) is
|
|
|
|
|
+a 5-bit mask — bit0=Mo, bit1=Di, bit2=Mi, bit3=Do, bit4=Fr — and is the
|
|
|
|
|
+source of truth for "is this a workday this week." `max_working_days`
|
|
|
|
|
+lives on as a cached `popcount(mask)` projection, so the two columns
|
|
|
|
|
+are always in sync.
|
|
|
|
|
+
|
|
|
Indexes: `idx_audit_occurred_at`, `idx_audit_entity`, `idx_tasks_sprint`,
|
|
Indexes: `idx_audit_occurred_at`, `idx_audit_entity`, `idx_tasks_sprint`,
|
|
|
`idx_sw_sprint`.
|
|
`idx_sw_sprint`.
|
|
|
|
|
|
|
|
Value constraints enforced in PHP (not SQL):
|
|
Value constraints enforced in PHP (not SQL):
|
|
|
- All `days` fields: non-negative multiple of 0.5.
|
|
- All `days` fields: non-negative multiple of 0.5.
|
|
|
-- `max_working_days`, `sprint_worker_days.days` ∈ {0, 0.5, …, 5}.
|
|
|
|
|
|
|
+- `sprint_weeks.max_working_days` ∈ {0, 1, 2, 3, 4, 5} — derived from the
|
|
|
|
|
+ weekday mask, so half-days are gone at the week level (Phase 12).
|
|
|
|
|
+- `sprint_weeks.active_days_mask` ∈ 0..31 (bits Mo..Fr).
|
|
|
|
|
+- `sprint_worker_days.days` ∈ {0, 0.5, …, 5}.
|
|
|
- `task_assignments.days` ≥ 0, no hard upper bound.
|
|
- `task_assignments.days` ≥ 0, no hard upper bound.
|
|
|
- `reserve_fraction`, `rtb` ∈ [0, 1].
|
|
- `reserve_fraction`, `rtb` ∈ [0, 1].
|
|
|
|
|
|
|
@@ -157,7 +168,7 @@ JSON (admin-only, CSRF via `X-CSRF-Token` header; envelope per spec §7):
|
|
|
| POST | `/sprints/{id}/workers/reorder` | reorder sprint workers |
|
|
| POST | `/sprints/{id}/workers/reorder` | reorder sprint workers |
|
|
|
| PATCH | `/sprints/{id}/workers/{sw_id}` | set rtb |
|
|
| PATCH | `/sprints/{id}/workers/{sw_id}` | set rtb |
|
|
|
| PATCH | `/sprints/{id}/week-cells` | batch day cells |
|
|
| PATCH | `/sprints/{id}/week-cells` | batch day cells |
|
|
|
-| PATCH | `/sprints/{id}/week/{week_id}` | set max_working_days |
|
|
|
|
|
|
|
+| PATCH | `/sprints/{id}/week/{week_id}` | set active_days_mask or active_days (derives max_working_days) |
|
|
|
| POST | `/sprints/{id}/tasks` | create task |
|
|
| POST | `/sprints/{id}/tasks` | create task |
|
|
|
| POST | `/sprints/{id}/tasks/reorder` | reorder tasks |
|
|
| POST | `/sprints/{id}/tasks/reorder` | reorder tasks |
|
|
|
| PATCH | `/tasks/{id}` | title/owner/priority |
|
|
| PATCH | `/tasks/{id}` | title/owner/priority |
|
|
@@ -247,6 +258,15 @@ with a `BOOTSTRAP_ADMIN` audit row.
|
|
|
a Node css-builder Docker stage; inline onclick replaced by
|
|
a Node css-builder Docker stage; inline onclick replaced by
|
|
|
`data-href` + `app.js`; CSP dropped `'unsafe-inline'` and the
|
|
`data-href` + `app.js`; CSP dropped `'unsafe-inline'` and the
|
|
|
Tailwind CDN host. Strict CSP now in effect.
|
|
Tailwind CDN host. Strict CSP now in effect.
|
|
|
|
|
+- [x] **Phase 12 — Per-week weekday selection (Mo–Fr) drives Arbeitstage**
|
|
|
|
|
+ (`a634582`): `sprint_weeks.active_days_mask` is the new source of
|
|
|
|
|
+ truth; `max_working_days` is a cached `popcount(mask)` projection.
|
|
|
|
|
+ Sprint Settings exposes five checkboxes (Mo Di Mi Do Fr) per week;
|
|
|
|
|
+ the sprint view's Arbeitstage header reads the derived count
|
|
|
|
|
+ read-only. `PATCH /sprints/{id}/week/{week_id}` now accepts
|
|
|
|
|
+ `active_days_mask` or `active_days`; `max_working_days` in the body
|
|
|
|
|
+ is rejected. Migration 002 backfills legacy rows (half-days round
|
|
|
|
|
+ up, clamped to 0..5). +14 tests, 88 total (was 74).
|
|
|
|
|
|
|
|
### Upcoming
|
|
### Upcoming
|
|
|
|
|
|
|
@@ -300,7 +320,7 @@ for f in $(git ls-files '*.php'); do php -l "$f" | tail -1 | sed "s|^|$f: |"; do
|
|
|
Run the test suite:
|
|
Run the test suite:
|
|
|
```bash
|
|
```bash
|
|
|
vendor/bin/phpunit
|
|
vendor/bin/phpunit
|
|
|
-# → OK (74 tests, 138 assertions)
|
|
|
|
|
|
|
+# → OK (88 tests, 208 assertions)
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
## 12. How to resume in a fresh Claude session
|
|
## 12. How to resume in a fresh Claude session
|
|
@@ -308,7 +328,7 @@ vendor/bin/phpunit
|
|
|
Tell Claude:
|
|
Tell Claude:
|
|
|
|
|
|
|
|
> Working on `/Users/achiappa/Development/claude_code_private/sprint_planer_web`.
|
|
> Working on `/Users/achiappa/Development/claude_code_private/sprint_planer_web`.
|
|
|
-> Read `HANDOFF.md`, the git log, and `ACCEPTANCE.md`. All 11 phases are
|
|
|
|
|
|
|
+> Read `HANDOFF.md`, the git log, and `ACCEPTANCE.md`. All 12 phases are
|
|
|
> shipped (see §9). There is no scheduled coding work. The only
|
|
> shipped (see §9). There is no scheduled coding work. The only
|
|
|
> outstanding items are in §10 (mostly a manual acceptance walkthrough
|
|
> outstanding items are in §10 (mostly a manual acceptance walkthrough
|
|
|
> in the running container). If I ask for new work, follow the
|
|
> in the running container). If I ask for new work, follow the
|
|
@@ -321,6 +341,8 @@ before acting — nothing here is load-bearing once it grows stale.
|
|
|
## 13. Git history (as of this handoff)
|
|
## 13. Git history (as of this handoff)
|
|
|
|
|
|
|
|
```
|
|
```
|
|
|
|
|
+a634582 Phase 12: per-week weekday selection (Mo–Fr) drives Arbeitstage
|
|
|
|
|
+a1a1266 HANDOFF.md: mark Phases 8–11 shipped + codify the maintenance rule
|
|
|
ab9430b Phase 11: vendor Tailwind + drop inline onclick + tighten CSP
|
|
ab9430b Phase 11: vendor Tailwind + drop inline onclick + tighten CSP
|
|
|
c35a934 Phase 10: multi-select owner filter + column visibility toggle
|
|
c35a934 Phase 10: multi-select owner filter + column visibility toggle
|
|
|
f7f5db5 Phase 9: users management page (promote / demote admin)
|
|
f7f5db5 Phase 9: users management page (promote / demote admin)
|