Commit Graph

216 Commits

Author SHA1 Message Date
Hartmut 81a46c81bd feat(blueprint): scope summary reads to planning audience 2026-03-30 10:55:28 +02:00
Hartmut 9b764008c3 feat(management-level): scope reads to planning audience 2026-03-30 10:45:44 +02:00
Hartmut c2ca6a6d0d feat(holiday-calendar): restrict catalog reads to admins 2026-03-30 10:36:05 +02:00
Hartmut 54769ca0f5 feat(utilization-category): scope reads to planning audience 2026-03-30 10:29:40 +02:00
Hartmut ae74700f7c feat(client): scope planning reads to explicit audience 2026-03-30 10:24:52 +02:00
Hartmut 2b514ea962 feat(org-unit): scope structural reads to resource overview 2026-03-30 10:17:57 +02:00
Hartmut 65fe7ce04f feat(assistant): align resource tool visibility with read audiences 2026-03-30 10:11:55 +02:00
Hartmut bd654251f7 feat(master-data): scope detail reads to resource overview 2026-03-30 10:08:44 +02:00
Hartmut 3a30fecc13 feat(role): scope planning-linked role reads to planning audience 2026-03-30 09:58:39 +02:00
Hartmut 16cf1bcb50 feat(assistant): align system role config visibility with admin reads 2026-03-30 09:56:45 +02:00
Hartmut a25635ee66 feat(auth): restrict system role config reads to admins 2026-03-30 09:46:32 +02:00
Hartmut 98502e6cf8 feat(estimate): scope estimate search to controller audience 2026-03-30 09:44:50 +02:00
Hartmut 806c028974 feat(scenario): scope baseline reads to planning and cost audiences 2026-03-30 09:40:07 +02:00
Hartmut 3aac946443 feat(staffing): enforce planning and cost audiences 2026-03-30 09:36:38 +02:00
Hartmut a960d43ed1 feat(assistant): align tool visibility with route audiences 2026-03-30 09:22:26 +02:00
Hartmut 93c4374973 feat(auth): introduce explicit planning read permission 2026-03-30 09:15:07 +02:00
Hartmut a50ca09333 feat(auth): tighten allocation read audiences 2026-03-30 09:03:44 +02:00
Hartmut db45829eca feat(auth): classify planning and resource read audiences 2026-03-30 08:51:07 +02:00
Hartmut f6daf21983 feat(import): harden untrusted spreadsheet boundaries 2026-03-30 08:02:52 +02:00
Hartmut fac8c1c3a5 feat(sse): scope timeline events to affected audiences 2026-03-30 00:40:24 +02:00
Hartmut 819345acfa feat(platform): harden access scoping and delivery baseline 2026-03-30 00:27:31 +02:00
Hartmut 00b936fa1f feat(assistant): extend audit and import parity 2026-03-29 12:56:29 +02:00
Hartmut 47e4d701ff chore(repo): checkpoint current capakraken implementation state 2026-03-29 12:47:12 +02:00
Hartmut beae1a5d6e feat(assistant): add approval inbox and e2e hardening 2026-03-29 10:10:59 +02:00
Hartmut 4f48afe7b4 feat(planning): ship holiday-aware planning and assistant upgrades 2026-03-28 22:49:28 +01:00
Hartmut 2a005794e7 feat: additive security improvements — prompt guard, content filter, data classification
Prompt Injection Detection (EGAI 4.6.3.2):
- 12-pattern regex scanner on user messages before AI processing
- Logs warning + creates SecurityAlert audit entry on detection
- Reinforces system prompt instead of blocking (non-breaking)

AI Output Content Filter (EGAI 4.3.2.1):
- Scans AI responses for leaked credentials/secrets
- Auto-redacts passwords, API keys, bearer tokens, private keys
- Logs warning + SecurityAlert audit when redaction occurs

AI Tool Execution Audit Trail (IAAI 3.6.35):
- Every AI tool call creates AiToolExecution audit entry
- Logs tool name, parameters, userId, source: "ai"

Data Classification Labels (EGAI 4.2):
- DATA_CLASSIFICATION constant mapping all fields to HC/C/IR/U
- Exported from @capakraken/shared

All changes strictly additive — no existing logic modified.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-27 16:23:33 +01:00
Hartmut 1fc1e9f24c feat: AI security controls + PostgreSQL hardening (Week 1 Quick Wins)
AI Security (EGAI 4.3.1.3, 4.3.1.4, 4.1.3.1, IAAI 3.6.26):
- AI Disclaimer banner in ChatPanel: "AI responses may be inaccurate"
- "AI Generated" violet badge on: chat messages, AI summaries,
  project narratives, AI-generated cover images
- HITL: system prompt now requires explicit user confirmation
  before any data mutation (strongly worded instruction)
- Mutation tool audit logging: all 31 write tools logged with
  tool name, params, userId, userRole via Pino

PostgreSQL Hardening (PG Standard V1.6):
- Audit logging: log_connections, log_disconnections, log_statement=ddl,
  log_min_duration_statement=1000 in docker-compose
- SUPERUSER removal script: scripts/harden-postgres.sh
  (NOSUPERUSER + minimal GRANT for app user)
- Health check: pg_isready -U capakraken -d capakraken
- Documentation: security-architecture.md Section 12 updated

Controls closed: EGAI 4.1.3.1, 4.3.1.3, 4.3.1.4, PG 3.3, 3.5

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-27 16:18:35 +01:00
Hartmut 9d43e4b113 feat: ACN Application Security Standard V7.30 compliance (19/23 items)
CRITICAL — Authentication & Access:
- TOTP MFA: otpauth-based, QR setup UI, sign-in flow integration,
  admin disable override, /account/security self-service page
- Session Timeouts: 8h absolute (maxAge), 30min idle (updateAge)
- Failed Auth Logging: Pino warn for invalid password/user/totp,
  info for successful login, audit entries for all auth events
- Concurrent Session Limit: ActiveSession model, oldest-kick strategy,
  max 3 per user (configurable in SystemSettings)

CRITICAL — HTTP Security:
- HSTS: max-age=31536000; includeSubDomains
- CSP: script/style/img/font/connect-src with Gemini/OpenAI whitelist
- X-XSS-Protection: 0 (CSP replaces legacy)
- Auth page cache: no-store, no-cache, must-revalidate
- Rate Limiting: 100/15min general API, 5/15min auth (Map-based)

Data Protection:
- XSS Sanitization: DOMPurify on comment bodies
- autocomplete="new-password" on all password/secret fields
- SameSite=Strict on all cookies (Credentials-only, no OAuth)
- File Upload Magic Bytes validation (PNG/JPEG/WebP/GIF/BMP/TIFF)

Logging & Monitoring:
- Login/Logout audit entries (Auth entityType)
- External API call logging with timing (OpenAI, Gemini)
- Input validation failure logging at warn level
- Concurrent session tracking in ActiveSession table

Documentation:
- docs/security-architecture.md (11 sections)
- docs/sdlc.md (CI pipeline, security gates, incident response)
- .gitea/PULL_REQUEST_TEMPLATE.md (security checklist)

Schema: User.totpSecret/totpEnabled, SystemSettings.sessionMaxAge/
sessionIdleTimeout/maxConcurrentSessions, ActiveSession model

Tests: 310 engine + 37 staffing pass. TypeScript clean.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-27 14:16:39 +01:00
Hartmut cd78f72f33 chore: full technical rename planarchy → capakraken
Complete rename of all technical identifiers across the codebase:

Package names (11 packages):
- @planarchy/* → @capakraken/* in all package.json, tsconfig, imports

Import statements: 277 files, 548 occurrences replaced

Database & Docker:
- PostgreSQL user/db: planarchy → capakraken
- Docker volumes: planarchy_pgdata → capakraken_pgdata
- Connection strings updated in docker-compose, .env, CI

CI/CD:
- GitHub Actions workflow: all filter commands updated
- Test database credentials updated

Infrastructure:
- Redis channel: planarchy:sse → capakraken:sse
- Logger service name: planarchy-api → capakraken-api
- Anonymization seed updated
- Start/stop/restart scripts updated

Test data:
- Seed emails: @planarchy.dev → @capakraken.dev
- E2E test credentials: all 11 spec files updated
- Email defaults: @planarchy.app → @capakraken.app
- localStorage keys: planarchy_* → capakraken_*

Documentation: 30+ .md files updated

Verification:
- pnpm install: workspace resolution works
- TypeScript: only pre-existing TS2589 (no new errors)
- Engine: 310/310 tests pass
- Staffing: 37/37 tests pass

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-27 13:18:09 +01:00
Hartmut bf3751f667 fix: invert shoring ratio logic — higher offshore = better
The shoring indicator logic was backwards. In the business context,
higher offshore = more cost-efficient = GOOD.

Inverted logic:
- Green: offshore >= threshold (target met, e.g. >= 55%)
- Yellow: offshore close to threshold (threshold-10 to threshold)
- Red: offshore below threshold (too little offshore, too expensive)

Updated:
- ShoringIndicator: getSeverity() inverted, badge text updated
- ProjectModal: "Max Offshore" renamed to "Min Offshore" with new tooltip
- AI Tool: status text reflects "target met" vs "below target"
- Tool description: "higher offshore is better, threshold is minimum"

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-26 13:07:36 +01:00
Hartmut 92a982b151 feat: Nearshore-Ratio indicator per project
Engine (packages/engine):
- calculateShoringRatio() pure function: onshore/offshore hours,
  country breakdown, threshold check, weighted by hours not headcount
- 12 unit tests: empty, 100% onshore/offshore, mixed ratios,
  custom threshold, case-insensitive, unknown country, FTE weighting

Schema:
- Project.shoringThreshold (default 55%) — per-project configurable
- Project.onshoreCountryCode (default "DE") — configurable onshore country

API (project router):
- getShoringRatio query: loads assignments with resource.country,
  computes ratio, returns full breakdown
- update mutation: accepts shoringThreshold + onshoreCountryCode

UI:
- ShoringIndicator: stacked horizontal bar with country segments,
  severity badge (green/yellow/red), hover tooltip, dark theme
- ShoringBadge: mini colored dot + % for project list column
- ProjectModal: "Max Offshore %" number input
- Project detail: indicator after budget status card
- Project list: "Shoring" column (default hidden, toggleable)

AI Assistant:
- get_shoring_ratio tool: human-readable breakdown with threshold alert

Colors: green (<threshold-10), yellow (threshold-10 to threshold), red (>=threshold)
Default: 55% offshore threshold, "DE" as onshore country

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-26 11:45:50 +01:00
Hartmut e5d7ca1293 refactor: rename Planarchy to CapaKraken (branding only)
User-facing rename across 20 files:
- Layout title/meta: "CapaKraken — Resource & Capacity Planning"
- Sidebar logo: "CapaKraken" with "RESOURCE & CAPACITY PLANNING"
- Sign-in page: "CapaKraken Control Center", "Sign in to CapaKraken"
- PWA manifest: name + short_name
- PDF reports: footer text
- Install prompt: "Install CapaKraken"
- AI assistant system prompt
- Webhooks test payload
- Email subject lines
- Tooltips, descriptions, empty states

NOT changed (technical identifiers):
- Package names (@planarchy/*)
- Import paths
- Database names
- Docker container names
- localStorage keys
- Domain URLs
- CLAUDE.md

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-25 21:46:15 +01:00
Hartmut cb46bfbd85 fix: cap AI tool result size to prevent JSON parse errors
When generating multiple cover images in one conversation, the
accumulated tool results (each ~400KB base64) caused the OpenAI
conversation payload to exceed JSON parsing limits in the browser.

Fix:
- Strip coverImageUrl from invalidate action results (not needed by AI)
- Cap invalidate results to 4KB
- Cap all tool results to 8KB
- Prevents "JSON.parse: unexpected character" errors during batch ops

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-23 18:35:57 +01:00
Hartmut e766309c6c fix: AI assistant generate_project_cover now uses configured provider
The tool was hardcoded to only check isDalleConfigured(), ignoring
Gemini even when it was the configured image provider. This caused
"DALL-E is not configured" errors for all 13 projects.

Fix: reads imageProvider from SystemSettings and routes to Gemini
or DALL-E accordingly (same logic as the generateCover mutation).

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-23 18:01:16 +01:00
Hartmut 835ed6ef27 fix: correct Gemini model names + add model dropdown
Corrected model names (per Google AI docs):
- gemini-2.5-flash-image (was gemini-2.0-flash-preview-image-generation)
- gemini-3-pro-image-preview (Nano Banana Pro)
- gemini-3.1-flash-image-preview (Nano Banana 2)

UI: replaced text input with dropdown selector showing all 3 models
with human-readable descriptions.

Default changed to gemini-2.5-flash-image (fast, high-volume).

AI Assistant: generate_project_cover tool description updated to be
provider-agnostic (works with both DALL-E and Gemini).

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-23 17:46:41 +01:00
Hartmut 3ceba38ac8 feat: Gemini image generation test button in admin settings
API: new testGeminiConnection adminProcedure
- Generates a simple test image via Gemini API
- Returns { ok, model } on success, { ok: false, error } on failure
- Audit logged: "Gemini test succeeded/failed"

UI: "Test Gemini" button next to "Save Image Settings"
- Only visible when Gemini provider is selected
- Shows green success or red error result below the buttons
- Displays the model name on success

Model: gemini-2.0-flash-preview-image-generation (correct name)

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-23 15:11:28 +01:00
Hartmut 502ecba9e9 feat: Google Gemini image generation for project covers
Schema:
- SystemSettings: geminiApiKey, geminiModel, imageProvider fields
- imageProvider: "dalle" (default) or "gemini"

Gemini Client (packages/api/src/gemini-client.ts):
- Direct HTTP call to Gemini REST API with responseModalities: [TEXT, IMAGE]
- Returns base64 data URL
- Error parsing with user-friendly messages

Router (project.ts):
- generateCover: routes to DALL-E or Gemini based on imageProvider setting
- New isImageGenConfigured query returning { configured, provider }

Admin UI (SystemSettingsClient.tsx):
- "Image Generation" section with provider radio buttons (DALL-E / Gemini)
- Conditional fields: DALL-E config or Gemini API key + model
- Separate save button for image settings

Security:
- geminiApiKey sanitized in audit logs (SENSITIVE_FIELDS)
- API key stored server-side only, never sent to client

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-23 15:02:35 +01:00
Hartmut 840f355f4f feat: admin can change user display name
API: new updateName adminProcedure in user router
- Input: userId + name (min 1, max 200 chars)
- Argon2 not involved (name only, not password)
- Audit log: "Changed name from X to Y"

UI: "Display Name" editable section in user edit modal
- Shows current name with "Edit" link
- Click Edit: inline input with Save/Cancel + Enter/Escape
- Auto-focuses input, saves on Enter
- Invalidates user list on success

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-23 09:41:56 +01:00
Hartmut bc6afefeae feat: admin set password for users + fix dashboard cache error
Admin Set Password:
- New setPassword adminProcedure in user router (Argon2 hashing)
- Audit log: "Password reset by admin" (no password value logged)
- UI: per-user "Password" button with key icon in User Management
- Modal: new password + confirm, min 8 chars, mismatch validation
- Success toast + auto-close on completion

Dashboard fix:
- Corrupted .next cache causing "Cannot find module worker.js"
- Fixed by clearing .next cache and restarting dev server

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-23 09:32:38 +01:00
Hartmut 47b2aeec72 feat: prevent duplicate resource-project assignments
Engine (packages/engine):
- New checkDuplicateAssignment() pure function: detects same resource
  assigned to same project with overlapping dates
- 15 unit tests covering: overlap, no-overlap, cancelled, self-exclude,
  string dates, PROPOSED status

Application layer (packages/application):
- createAssignment: throws CONFLICT before DB write if duplicate found
- fillDemandRequirement: same check before entering transaction

AI Assistant (packages/api/router/assistant-tools.ts):
- create_allocation: checks before creating, returns helpful error message
- fill_demand: same check using demand's projectId

UI (apps/web):
- AllocationModal: amber warning when resource already assigned to
  selected project with overlapping dates (non-blocking)

Database cleanup:
- Found and merged 1 duplicate: Wong Wong on Porsche Taycan Sport Film
  (2 overlapping PROPOSED assignments merged into 1)

Regression: 298 engine tests pass (283 + 15 new). TypeScript clean.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-23 08:51:49 +01:00
Hartmut eacbdb5d47 perf: optimize Activity Log — lazy diff, 30-day default, getById
- List query: exclude changes JSONB from select (only metadata)
- Default to last 30 days when no date filter (avoids full table scan)
- New getById query: fetches full changes JSONB on demand
- ExpandedDiff component: fetches diff only when user expands an entry
- 5-minute staleTime on expanded diffs (cacheable, rarely changes)

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 22:55:45 +01:00
Hartmut 7a7430851c feat: complete audit coverage — comment, webhook, system-role, dispo, scenario
- comment.ts: create (body preview), resolve, delete
- webhook.ts: create, update, delete, test (result in summary)
- system-role-config.ts: update with before/after
- dispo.ts: commitImportBatch (IMPORT with counts), cancelImportBatch
- scenario.ts: applyScenario (CREATE with allocation count)

Audit coverage now: 29/36 routers (81%). Remaining 7 are read-only
(dashboard, staffing, chargeability-report, computation-graph,
report, insights.detectAnomalies, notification read/dismiss).

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 22:46:34 +01:00
Hartmut 66878f18f4 feat: Activity History system — full audit coverage, UI, AI tools
Infrastructure (Phase 1):
- AuditLog schema: add source, entityName, summary fields + index
- createAuditEntry() helper: auto-diff, auto-summary, fire-and-forget
- auditLog query router: list, getByEntity, getTimeline, getActivitySummary

Audit Coverage (Phase 2 — 14 routers, 50+ mutations):
- vacation: create, approve, reject, cancel, batch ops (8 mutations)
- user: create, updateRole, setPermissions, resetPermissions (5 mutations)
- entitlement: set, bulkSet (3 mutations)
- client: create, update, delete, batchUpdateSortOrder
- org-unit: create, update, deactivate
- country: create, update, createCity, updateCity, deleteCity
- management-level: createGroup, updateGroup, createLevel, updateLevel, deleteLevel
- settings: updateSystemSettings (sensitive fields sanitized), testSmtp
- blueprint: create, update, updateRolePresets, delete, batchDelete, setGlobal
- rate-card: create, update, deactivate, addLine, updateLine, deleteLine, replaceLines
- calculation-rules: create, update, delete
- effort-rule: create, update, delete
- experience-multiplier: create, update, delete
- utilization-category: create, update

Admin UI (Phase 3):
- /admin/activity-log page with global searchable timeline
- Filters: entity type, action, user, date range, text search
- Expandable before/after diff view per entry
- Summary cards showing top entity types by change count
- EntityHistory reusable component for entity detail pages
- Sidebar nav link with clock icon

AI Assistant (Phase 4):
- query_change_history tool: "Who changed project X?"
- get_entity_timeline tool: "What happened to resource Y?"

Regression: 283 engine + 37 staffing tests pass. TypeScript clean.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 22:39:30 +01:00
Hartmut ac845d72b7 refactor: deduplicate modals, notifications, confirms, comboboxes, proficiency
Modal Overlay (Finding 1 — 6 admin files):
- Migrated CountriesClient, ManagementLevelsClient, OrgUnitsClient,
  CalculationRulesClient, UtilizationCategoriesClient, RoleModal
  from inline fixed-overlay to AnimatedModal component
- Gains: animated transitions, backdrop blur, escape key for free

Notification Helper (Finding 9 — 9 API files, 14 call sites):
- New createNotification() + createNotificationsForUsers() in
  packages/api/src/lib/create-notification.ts
- Handles exactOptionalPropertyTypes spread + SSE emit internally
- Simplified: budget-alerts, estimate-reminders, auto-staffing,
  vacation-conflicts, chargeability-alerts, comment, vacation, notification

ConfirmDialog (Finding 3 — 11 files):
- Replaced all window.confirm() calls with ConfirmDialog component
- Files: CommentThread, EffortRules, ExperienceMultipliers,
  ManagementLevels, CalculationRules, Countries, RateCards,
  ApplyEffortRules, ApplyExperienceMultipliers, NotificationCenter,
  ReminderModal

EntityCombobox (Finding 4 — 3 files):
- New generic EntityCombobox<T> with customization hooks
- ResourceCombobox + ProjectCombobox rewritten as thin wrappers
- All consumers unchanged (backwards-compatible props)

Proficiency Constants (Finding 2 — 2 files):
- SkillsAnalytics + SkillMarketplace now import from skills/shared.tsx
- Deleted ~70 LOC of local duplicate definitions

Regression: 283 engine + 37 staffing tests pass. TypeScript clean.
AI Assistant: all 87 tools verified accessible.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 21:50:39 +01:00
Hartmut 03922764db feat: redesign Clients admin — drag-and-drop, inline edit, tags
Schema:
- Client model: add tags String[] field
- Shared types + Zod schemas updated for tags

API:
- client.create/update: accept tags array
- client.delete: with safety checks (no projects, no children)
- client.batchUpdateSortOrder: batch reorder in transaction

UI (complete redesign of ClientsAdminClient):
- Drag-and-drop reordering via @dnd-kit (sortable)
- Inline editing: click name/sortOrder to edit in-place
- Tag pills: auto-colored by hash, add/remove inline
- Tag auto-suggest from existing tags across all clients
- Sticky "Add Client" input row at top
- Search/filter by name, code, or tag
- Delete with inline confirmation
- Optimistic reorder (instant UI update)
- Full dark theme support

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 21:04:20 +01:00
Hartmut fd400122a4 feat: computation graph — add all missing engine variables and calculations
Added 30+ new nodes covering every engine calculation module:
- SAH: publicHolidayDays, scheduleRules separation
- Allocation: workingDays, utilizationPct intermediates
- Chargeability: bd/mdi/mo/pdr/absence ratio breakdowns
- Effort rules (new domain): scopeItems, totalFrames, expandedHours
- Experience multipliers (new domain): costMultiplier, billMultiplier, shoringRatio
- Commercial terms: pricingModel, paymentTermDays, warrantyMonths, milestones
- Spread (new domain): monthCount, weekCount, monthlySpread, weeklyPhasing
- Budget: allocCount, estVsActualGap
- Project: projectStart/End, resourceSnapshots, chapters

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 20:33:07 +01:00
Hartmut 7e4b21afe9 feat: Dispo V2 import — API router + admin UI
API Router (packages/api/src/router/dispo.ts):
- 12 adminProcedure endpoints wired to existing application layer
- stageImportBatch, validateImportBatch, commitImportBatch
- listImportBatches, getImportBatch, cancelImportBatch
- listStagedResources/Projects/Assignments/Vacations/Unresolved
- resolveStagedRecord (APPROVE/REJECT/SKIP actions)

Admin UI:
- /admin/dispo-imports — batch list with status filter, new import modal
- /admin/dispo-imports/[batchId] — detail with 6 tabs:
  Summary, Resources, Projects, Assignments, Vacations, Unresolved
- Unresolved review queue with approve/skip per-record actions
- Commit workflow with pre-validation and progress indicator
- Sidebar nav link under Admin

Also fixes: timeline filter dropdown z-index (toolbar relative z-20)

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 19:07:20 +01:00
Hartmut 046d16dd97 feat: add 12 new AI assistant tools for Sprint 1-5 features
New HartBOT tools:
- detect_anomalies: budget burn, staffing gaps, utilization, timeline risks
- get_skill_gaps: skill supply vs demand analysis
- get_project_health: 3-dimension health scoring per project
- get_budget_forecast: burn rate + exhaustion date per project
- get_insights_summary: anomaly counts by category
- run_report: dynamic report queries (resource/project/assignment)
- list_comments / create_comment / resolve_comment: collaboration
- lookup_rate: rate card lookup by client/chapter/level
- simulate_scenario: what-if staffing simulation (read-only)
- generate_project_narrative: AI executive summary generation

All tools follow existing patterns: assertPermission() gating,
ctx.db for Prisma queries, __action: "invalidate" for mutations.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-20 07:45:56 +01:00
Hartmut fbeab5cd79 feat: Sprint 5 — AI insights, webhooks/Slack, PWA, performance monitoring
AI-Powered Insights (G9):
- Rule-based anomaly detection: budget burn rate, staffing gaps, utilization,
  timeline overruns across all active projects
- AI narrative generation via existing Azure OpenAI integration
- Cached in project dynamicFields to avoid regeneration
- New /analytics/insights page with anomaly feed + project summaries
- Sidebar nav: "AI Insights" under Analytics

Webhook System + Slack (G10):
- Webhook model in Prisma (url, secret, events, isActive)
- HMAC-SHA256 signed payloads with 5s timeout fire-and-forget dispatch
- Slack-aware: routes hooks.slack.com URLs through Slack formatter
- 6 events integrated: allocation.created/updated/deleted, project.created/
  status_changed, vacation.approved
- Admin UI: /admin/webhooks with CRUD, test button, event checkboxes
- webhook router: list, getById, create, update, delete, test

PWA Support (G11):
- manifest.json with standalone display, brand-colored icons (192+512px)
- Service worker: cache-first for static, network-first for API, offline fallback
- ServiceWorkerRegistration component with 60-min update checks
- InstallPrompt banner with 30-day dismissal memory
- Apple Web App meta tags + viewport theme color

Performance Monitoring (A15):
- Pino structured logging (JSON prod, pretty dev) via LOG_LEVEL env
- tRPC logging middleware on all protectedProcedure calls
- Request ID (UUID) per call for log correlation
- Slow query warnings (>500ms) at warn level
- GET /api/perf endpoint: memory, uptime, SSE connections, node version

Fix: renamed scenario.apply to scenario.applyScenario (tRPC reserved word)

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-20 06:57:20 +01:00
Hartmut e1368c7ef7 feat: Sprint 4 — scenario planner, report builder, comments, dashboard widgets
What-If Scenario Planner (G5):
- New /projects/[id]/scenario page with side-by-side baseline vs scenario
- simulate mutation: pure cost/hours/headcount/utilization computation
- apply mutation: creates real PROPOSED assignments from scenario
- Impact cards: cost delta, hours delta, headcount, skill coverage %
- Per-resource utilization impact table with over-allocation warnings
- "What-If" button added to project detail page

Custom Report Builder (G7):
- New /reports/builder page with full config panel
- Entity selector (resource/project/assignment), column picker, filter builder
- Dynamic Prisma query with eq/neq/gt/lt/contains/in operators
- Sortable results table with pagination (50/page)
- CSV export via exportReport mutation
- Sidebar nav link under Analytics

Collaboration Layer (G8):
- Comment model in Prisma (entityType/entityId, replies, @mentions, resolved)
- comment router: list, count, create, resolve, delete
- @mention parsing with notification creation + SSE delivery
- CommentInput with @mention autocomplete (arrow nav, Enter/Tab confirm)
- CommentThread with avatar, timestamp, reply, resolve, delete
- Integrated as "Comments" tab in estimate workspace with count badge

Dashboard Widgets:
- BudgetForecastWidget: progress bars per project, burn rate, exhaustion date
- SkillGapWidget: supply vs demand per skill, shortage/surplus indicators
- ProjectHealthWidget: 3-dimension health circles + composite score
- 3 new application use-cases + dashboard router queries
- All registered in widget-registry with lazy imports

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-19 21:47:47 +01:00