|
1 | 1 | # Taskdeck Implementation Masterplan |
2 | 2 |
|
3 | | -Last Updated: 2026-04-15 |
| 3 | +Last Updated: 2026-04-16 |
4 | 4 | <br> |
5 | 5 | Planning Horizon: Next 8 to 12 weeks |
6 | 6 | Companion Active Docs: |
@@ -666,6 +666,18 @@ Delivered in the latest cycle: |
666 | 666 | - resilience/degraded-mode tests (`#720`/`#823`): 30 tests across 3 files — LLM provider resilience, queue accumulation, frontend slow-API/storage |
667 | 667 | - estimated combined total after merge: backend ~4,479+, frontend ~2,454+, combined ~6,950+ |
668 | 668 |
|
| 669 | +135. PROD-00 production-readiness round-2 hardening wave (2026-04-16, PRs `#884`–`#891`, 8 PROD-00 tracker `#881` items): |
| 670 | + - 8 focused PRs covering disclosure policy, contributor onramp, config reference, response compression, DB indexes, container hardening, frontend crash prevention, and HTTP retry; each PR received two rounds of adversarial review (self-review + independent cold review with bot-findings triage) |
| 671 | + - **SEC-28** SECURITY.md vulnerability disclosure policy (`#853`/`#884`): repo-root `SECURITY.md` with GitHub private advisory + fallback email, 48h acknowledgement target, supported-versions scope (`main` guaranteed; latest pre-1.0 tag best-effort), safe-harbor language; README cross-link; round-2 enabled the private vulnerability reporting feature (was disabled, would have 404'd) and reconciled prose with the supported-versions table |
| 672 | + - **DOC-06** CONTRIBUTING.md onramp (`#873`/`#885`): repo-root `CONTRIBUTING.md` covering prerequisites (.NET 8 SDK, Node.js 24.x, Git), cross-platform local setup, Windows-specific notes (`check-git-env.sh`, Cygwin-git pitfall, PowerShell chaining), default URLs, test commands, commit conventions, PR process; README cross-link; AGENTS.md remains authoritative |
| 673 | + - **DOC-07** CONFIGURATION_REFERENCE.md appsettings schema (`#874`/`#887`): `docs/platform/CONFIGURATION_REFERENCE.md` documents every `appsettings.json` section and every typed `*Settings.cs` binding with key/type/default/description/required flags and env-var override conventions; cross-linked from `CLAUDE.md` and `docs/platform/README.md`; `deploy/.env.example` aligned |
| 674 | + - **PERF-09** response compression (`#845`/`#886`): `AddTaskdeckResponseCompression()` registers Brotli + Gzip, `UseResponseCompression()` wired in `PipelineConfiguration` after forwarded headers and before CORS/static/routing; includes `application/problem+json` in compressible MIME set; 3 integration tests (`ResponseCompressionApiTests`); **round-2 BREACH correction**: threat-model analysis caught that JWTs ARE returned in `/api/auth/login` and `/api/auth/register` response bodies (contradicting inline comment assuming they only live in `Authorization` headers) — compression level downgraded from `CompressionLevel.Optimal` to `CompressionLevel.Fastest` to reduce BREACH/CRIME oracle surface while preserving bandwidth wins |
| 675 | + - **PERF-10** composite DB indexes for AuditLog and Card (`#846`/`#888`): EF Core migration `20260416161303_AddPerfIndexes` adds `IX_Cards_BoardId_ColumnId` (replaces single-column `IX_Cards_BoardId`; SQLite satisfies leftmost-prefix; FK constraint preserved by schema), `IX_AuditLogs_UserId_Timestamp`, and `IX_AuditLogs_EntityId_Timestamp`; **explicit issue-AC deviations documented**: uses `AuditLog.EntityId` instead of the aspirational `BoardId` (AuditLog uses polymorphic `EntityId` targeting), and `IX_LlmRequests_UserId_Status` was confirmed pre-existing so no new index created; no new tests (migration-only) |
| 676 | + - **OPS-29** Docker container hardening (`#866`/`#889`): non-root end-to-end; backend uses `setpriv` entrypoint to chown `/app/data` and drop to `appuser` (UID 10001) — **upgrade-safe** for existing root-owned `taskdeck-db` volumes; backend HEALTHCHECK on `/health/ready`; frontend runs `nginxinc/nginx-unprivileged` with HEALTHCHECK on `/healthz`; **round-2 shipbreaker caught**: initial frontend HEALTHCHECK used `localhost`, BusyBox resolver preferred `::1` (IPv6) but nginx bound IPv4 only — probe never transitioned to healthy; fixed by pinning to `127.0.0.1`; docker-compose gains `mem_limit`/`cpus`, `logging` rotation (`max-size: 10m`/`max-file: 3`), `init: true`, `no-new-privileges`, unprivileged proxy |
| 677 | + - **FE-15** HTTP retry with exponential backoff (`#854`/`#890`): Axios retry interceptor in `httpRetry.ts` — max 3 attempts, exponential backoff (1s/2s/4s ± 25% jitter), idempotent methods only (GET/HEAD/OPTIONS/PUT/DELETE), 5xx + network + 408/429/503 retryable (501/505 excluded), 429 honours `Retry-After` (seconds + HTTP-date, case-insensitive via `AxiosHeaders`), no retry on 401/403/404/409/422, respects `axios.isCancel`, backoff races `AbortSignal`; **round-2 fixes**: `parseRetryAfter('-5')` returned 0 because HTTP-date branch lacked a proper letter-guard — fixed to return `null`; `skipRetry` opt-out on `RetryableRequestConfig` so pre-existing PR `#725` baseline tests (asserting retry-less 5xx) and 2 Playwright specs with first-request-fails mocks can opt out; new retry tests + E2E updates |
| 678 | + - **FE-14** Vue error boundary for crash prevention (`#852`/`#891`): `ErrorBoundary.vue` uses `onErrorCaptured` to render a recoverable fallback (Reload + Go-to-Home); `App.vue` wraps `<RouterView />` as outer backstop and `AppShell.vue` wraps its inner `<router-view />` for per-view crash containment; `main.ts` installs `app.config.errorHandler` plus `window` listeners for `error`/`unhandledrejection`; optional Sentry passthrough via `window.Sentry?.captureException`; **round-2 fix**: `crashedError === null` sentinel would collide if a descendant threw literal `null` — replaced with explicit `hasCrashed: boolean`; null-throw and Sentry info-context tests added (`ErrorBoundary.spec.ts` + `errorReporting.spec.ts`) |
| 679 | + - Closes `#853`, `#873`, `#874`, `#845`, `#846`, `#866`, `#854`, `#852` — all part of PROD-00 wave tracker `#881` |
| 680 | + |
669 | 681 | ## Current Planning Pivot (2026-03-07) |
670 | 682 |
|
671 | 683 | The 2026-03-06 MVP expansion review packages change the next-cycle emphasis without invalidating the current architecture. |
|
0 commit comments