Commit Graph

334 Commits

Author SHA1 Message Date
Hartmut a9ad1ed8b6 feat(G-08): chapter field uses live datalist from resource.chapters
All chapter text inputs now show autocomplete suggestions from the
database (distinct chapter values from active resources) via HTML
<datalist> wired to trpc.resource.chapters:

- ResourceModal: chapter input
- RateCardsClient: rate card line chapter input
- EffortRulesClient: effort rule chapter input
- ExperienceMultipliersClient: replaces hardcoded CHAPTER_PRESETS
  with live data, falls back to presets when no data available

Also revert blueprintRolePresetsInputSchema to z.array(z.unknown())
to restore compatibility with StaffingRequirement[] call sites.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 08:10:36 +02:00
Hartmut 4a49ec4f05 fix(sanity): resolve 15 gaps from sanity check audit (G-01 through G-15)
- G-01: ProjectWizard renders blueprint fieldDefs with DynamicFieldInput component
- G-02: Blueprint rolePresets validated via RolePresetsSchema in wizard; API keeps loose schema
- G-03: ProjectWizard step 2/3 validation (role, hoursPerDay, headcount required)
- G-04: EstimateWizard validates baseCurrency and demand line cost rates
- G-05: Project lifecycle transition guards with ALLOWED_TRANSITIONS map
- G-06: Blueprint validator extended for minLength/maxLength/pattern and DATE range checks
- G-07: assertBlueprintDynamicFields merges global blueprint fieldDefs into validation
- G-08: (tracked — chapter managed dropdown; deferred to backend ticket)
- G-09: JSDoc added to lcrCents/ucrCents clarifying LCR/UCR terminology
- G-10: Dispo route redirect already in place — closed as done
- G-11: packages/ui empty by design — closed as documented
- G-12: @deprecated JSDoc added to CreateAllocationSchema and UpdateAllocationSchema
- G-13: ProjectWizard review step enhanced with blueprint name, field values, skills, assignments
- G-14: ProjectWizard handleSubmit collects per-item warnings instead of silent swallowing
- G-15: Vacation cancel reverses usedDays entitlement for APPROVED ANNUAL/OTHER vacations

Tests: all 1575 passing (1 pre-existing failure in insights-summary unrelated to these changes)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 00:11:12 +02:00
Hartmut fba65387fe feat(resources): add hard-delete action to resource list (per-row and batch)
- Add batchHardDelete adminProcedure to resource-mutations router
- Per-row Delete button visible to ADMIN role only
- Delete Selected button in BatchActionBar for ADMIN role only
- Two-step confirmation dialogs with permanent-action warnings
- Audit log written for each deleted resource

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-03 23:18:30 +02:00
Hartmut 0d0707264d feat(admin): hard-delete resources (admin-only)
Adds a transactional hard-delete procedure behind adminProcedure that
removes a resource's assignments and vacations first, then the record
itself, and writes an audit log entry.  The ResourceModal exposes a
"Delete Resource" button (edit mode, ADMIN role only) with an inline
confirm step before the mutation fires.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-03 15:23:30 +02:00
Hartmut 41eb722369 feat: user invite flow, deactivate/delete, favicon, dashboard loading fix, admin full-width
- Invite flow: admin can invite users by email with role selection; accept-invite page
  sets password and creates the account; 72-hour token expiry; E2E tests
- User deactivate/reactivate/delete: new tRPC procedures + UI buttons; deactivation
  revokes all active sessions immediately; delete cascades vacation/broadcast records;
  isActive field added via migration 20260402000000_user_isactive
- Auth: block login for inactive users with audit entry
- Favicon: SVG favicon + ICO/PNG fallbacks (16, 32, 180, 192, 512px); manifest updated
- Dashboard: GridLayout dynamic-import loading skeleton prevents blank dark area
  on first login before react-grid-layout chunk is cached
- Admin users: remove max-w-5xl constraint so table uses full page width
- Dev: docker container restart workflow documented in LEARNINGS.md; Prisma generate
  must run inside the container after schema changes (named node_modules volume)

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-02 20:19:26 +02:00
Hartmut dc5bbdc47d feat: centralize app base URL — no localhost fallback in production
Introduce getAppBaseUrl() in packages/api/src/lib/app-base-url.ts:
- Reads NEXTAUTH_URL (trimmed, trailing slash stripped)
- production: throws if NEXTAUTH_URL is missing/empty so broken
  localhost links in emails are caught at runtime, not silently sent
- development/test: falls back to http://localhost:3100 with a
  one-time console.warn

Replace the duplicated inline fallback in:
- packages/api/src/router/invite.ts (invite email link)
- packages/api/src/router/auth.ts (password reset email link)

Extend GET /api/health to report:
  "baseUrl": { "configured": bool, "isLocalhost": bool }
so deployment checks can detect a misconfigured NEXTAUTH_URL.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-02 14:19:19 +02:00
Hartmut fceceeee4b feat: SMTP full ENV override, password reset flow, and E2E email testing
- SMTP: SMTP_HOST/PORT/USER/FROM/TLS now all have ENV override support
  (previously only SMTP_PASSWORD was env-aware). ENV takes priority over DB.
- docker-compose.yml: forward all SMTP_* env vars to app container + add
  Mailhog service (ports 1025 SMTP / 8025 HTTP, always available in dev)
- Password reset: PasswordResetToken Prisma model + authRouter with
  requestPasswordReset (timing-safe, no email enumeration) + resetPassword
- UI: /auth/forgot-password, /auth/reset-password/[token] pages +
  "Forgot password?" link on sign-in page
- E2E: Mailhog helpers (getLatestEmailTo, clearMailhog, extractUrlFromEmail)
  + invite-flow.spec.ts + password-reset.spec.ts

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-02 08:55:39 +02:00
Hartmut 435c871e1f security: implement tickets #28-#35 + architecture decision #30
#28 - TOTP rate limiting (verifyTotp): added totpRateLimiter (10 req/30s),
  throws TOO_MANY_REQUESTS before DB hit; 16 unit tests including rate-limit
  exceeded + userId key isolation.

#29 - /api/reports/allocations role check: only ADMIN/MANAGER/CONTROLLER may
  access; returns 403 otherwise; 9 unit tests (401 unauthenticated, 403 for
  USER/VIEWER, 200 for allowed roles + xlsx format).

#31 - pgAdmin credentials moved out of docker-compose.yml into env vars;
  PGADMIN_PASSWORD is now required (:?) to prevent accidental plaintext
  exposure in committed files.

#34 - Server-side HTML sanitization for comment bodies via stripHtml():
  strips all tags + decodes safe entities before persistence; 16 unit tests
  covering passthrough, injection patterns, entity decoding.

#35 - MFA setup prompt banner (MfaPromptBanner): shown to ADMIN/MANAGER users
  without TOTP enabled; user-scoped localStorage snooze (7 days); links to
  /account/security; accessibility role=alert; 7 structural unit tests.

#33 - Auth anomaly alerting cron (/api/cron/auth-anomaly-check): detects
  HIGH_GLOBAL_FAILURE_RATE and CONCENTRATED_FAILURES in 30-minute window;
  CRITICAL notification to ADMINs; fail-closed via verifyCronSecret;
  10 unit tests.

#32 - MFA enforcement policy: added requireMfaForRoles field to SystemSettings
  schema + Prisma migration; auth.ts blocks login with MFA_REQUIRED_SETUP
  signal if role is enforced but TOTP not set up; signin page redirects to
  /account/security?mfa_required=1; settings schema + view model updated;
  11 unit tests.

#30 - API keys architecture decision documented in LEARNINGS.md; no code
  written — product decision required before implementation.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-01 23:25:06 +02:00
Hartmut 0e119cfe73 security: close audit findings #19–#23 and harden Docker setup (#24)
#19 MFA QR code: render locally via qrcode package, remove external qrserver.com request
#20 Webhook SSRF: add ssrf-guard.ts with DNS-verified IP blocklist; enforce on create/update/test/dispatch
#21 /api/perf: fail-closed when CRON_SECRET missing; remove query-string token auth
#22 CSP: remove unsafe-eval and unsafe-inline from script-src in production builds
#23 Active session registry: forward jti into session object; validate against ActiveSession on every tRPC request

#24 Docker: add missing packages/application to Dockerfile.dev; fix pnpm-lock.yaml glob;
    run db:migrate:deploy on container start so a fresh checkout boots without manual steps

Also: fix pre-existing TS error in e2e/allocations.spec.ts (args.length literal type overlap)

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-01 18:19:21 +02:00
Hartmut 8c5be51251 feat(platform): checkpoint current implementation state 2026-04-01 07:42:03 +02:00
Hartmut 3e53471f05 refactor(api): split resource read models 2026-04-01 07:38:03 +02:00
Hartmut 41916a4e46 refactor(api): share owned resource read access 2026-04-01 07:35:34 +02:00
Hartmut a0c98cf24d test(api): close assistant split regression gaps 2026-04-01 07:33:00 +02:00
Hartmut 9553aa0544 feat(api): add timeline allocation fragment support 2026-03-31 23:46:23 +02:00
Hartmut f2d511ebc8 feat(api): include skill gaps in dashboard detail 2026-03-31 23:46:07 +02:00
Hartmut 2de5a0eede feat(api): include project health in dashboard detail 2026-03-31 23:36:29 +02:00
Hartmut 703406a76b feat(api): explain dashboard chargeability by chapter 2026-03-31 23:34:03 +02:00
Hartmut a8fcc4dacb feat(api): expose peak times explainability 2026-03-31 23:25:36 +02:00
Hartmut fc12a5739e feat(api): expose demand pipeline explainability 2026-03-31 23:24:14 +02:00
Hartmut 79e0fd82f5 fix(api): reuse cached dashboard detail reads 2026-03-31 23:11:49 +02:00
Hartmut a76b173f4b refactor(api): narrow import-export procedure contexts 2026-03-31 22:55:26 +02:00
Hartmut 8bc764a35e fix(api): harden optional audit and session fields 2026-03-31 22:54:33 +02:00
Hartmut 160ba99b5c refactor(insights): share workbook export and ai defaults 2026-03-31 22:53:53 +02:00
Hartmut 05eeaab3f7 chore(settings): align default ai model handling 2026-03-31 22:52:29 +02:00
Hartmut 6e84b022c3 fix(api): harden notification assignee persistence 2026-03-31 22:52:09 +02:00
Hartmut 7ace137d16 feat(dashboard): tighten explainability detail views 2026-03-31 22:50:47 +02:00
Hartmut ba2bf00712 refactor(api): extract estimate procedure support 2026-03-31 22:45:05 +02:00
Hartmut 3f9ae29e01 refactor(api): share staffing capacity summaries 2026-03-31 22:45:00 +02:00
Hartmut 64111a9013 refactor(api): extract assistant chat orchestration 2026-03-31 22:44:54 +02:00
Hartmut 1b5f19c72c feat(api): explain chargeability derivation inputs 2026-03-31 22:43:33 +02:00
Hartmut cb363ca5b3 feat(api): explain holiday-aware vacation deductions 2026-03-31 22:42:00 +02:00
Hartmut cb8669c489 refactor(api): strengthen report template persistence 2026-03-31 22:35:15 +02:00
Hartmut 78d19c59b6 fix(api): harden notification task status updates 2026-03-31 22:35:02 +02:00
Hartmut d9c1e70620 refactor(api): split allocation assignment mutations 2026-03-31 22:30:03 +02:00
Hartmut 46d00c2635 refactor(api): split dashboard detail shaping 2026-03-31 22:26:52 +02:00
Hartmut a9028290f2 refactor(api): clarify affected allocation resource ids 2026-03-31 22:22:22 +02:00
Hartmut dbf5401910 refactor(api): extract allocation assignment mutation effects 2026-03-31 22:21:30 +02:00
Hartmut 59690b86ac refactor(api): split computation graph detail formatting 2026-03-31 22:19:09 +02:00
Hartmut a539e748a5 refactor(api): split resource graph snapshot loading 2026-03-31 22:16:31 +02:00
Hartmut 7411aaa77b refactor(api): split resource graph allocation assembly 2026-03-31 22:14:53 +02:00
Hartmut 831a44973c refactor(api): split project graph estimate assembly 2026-03-31 22:12:02 +02:00
Hartmut 1a90f4b930 fix(dashboard): stabilize budget forecast derivation typing 2026-03-31 22:11:39 +02:00
Hartmut 459ab6911b refactor(api): split resource graph availability 2026-03-31 22:01:29 +02:00
Hartmut e0de41488c refactor(api): split report query execution 2026-03-31 21:59:10 +02:00
Hartmut 4111b7b661 refactor(api): split notification procedure support 2026-03-31 21:56:15 +02:00
Hartmut 9fccd4c29e refactor(api): extract user procedures 2026-03-31 21:40:50 +02:00
Hartmut e34c22f3b0 refactor(api): extract project procedures 2026-03-31 21:28:56 +02:00
Hartmut b1799e4f54 refactor(api): extract computation graph procedures 2026-03-31 21:24:28 +02:00
Hartmut 884f1012c9 refactor(api): extract role read procedures 2026-03-31 21:22:44 +02:00
Hartmut cba4d44f16 refactor(api): extract webhook procedures 2026-03-31 21:18:29 +02:00