Commit Graph

368 Commits

Author SHA1 Message Date
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 52d425043b feat: unified Data Import page — merge Dispo + Skill imports
New /admin/imports page with tabs:
- "Dispo Import" tab: renders DispoImportClient (lazy-loaded)
- "Skill Matrix" tab: renders BatchSkillImport (lazy-loaded)
- Tab state via ?tab= URL param

Routing:
- /admin/dispo-imports → redirects to /admin/imports?tab=dispo
- /admin/skill-import → redirects to /admin/imports?tab=skills
- /admin/dispo-imports/[batchId] detail routes still work

Sidebar: single "Data Import" link under ACN-Orga (was 2 links)

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-23 10:38:03 +01:00
Hartmut cefd3e0bf8 refactor: move Dispo Import + Skill Import into ACN-Orga submenu
Both import pages are now grouped under the ACN-Orga collapsible
section in the admin sidebar instead of being separate top-level items.

ACN-Orga submenu now contains:
- Countries
- Org Units
- Util. Categories
- Mgmt Levels
- Dispo Import (moved)
- Skill Import (moved)

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-23 10:02:50 +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 ea9263de29 fix: ChargeabilityWidget hooks order — move useMemo before early return
React Rules of Hooks violation: filteredTop and filteredWatch useMemo
hooks were placed AFTER the isLoading early return, causing "Rendered
more hooks than during the previous render" error that crashed the
entire dashboard.

Fix: moved rawTop/rawWatch/month declarations and filteredTop/filteredWatch
useMemo hooks BEFORE the isLoading early return so hooks always run
in the same order.

Verified in Chrome: dashboard loads with zero console errors.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-23 09:36:37 +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 208f866d68 feat: shared widget filter system for all dashboard widgets
Shared infrastructure:
- WidgetFilterBar: declarative filter component (search, select, toggle)
- useWidgetFilterOptions: cached hook for clients, countries, roles, chapters

Widget integration (5 widgets):
- ProjectHealth: search (name) + select (client)
- BudgetForecast: search (name) + select (client)
- Chargeability: select (chapter) + toggle (include proposed)
- SkillGap: search (skill name)
- TopValue: select (chapter)

Backend: added clientId/clientName to ProjectHealth and BudgetForecast
query results for client-based filtering.

Filter state persisted via widget config (survives page reload).
All filters use compact 11px inputs with full dark theme support.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-23 09:21:46 +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 1f079d0309 chore: add start/stop/restart scripts for Planarchy
- scripts/start.sh: docker compose up, prisma generate, clear .next cache,
  start Next.js, wait for health check, show status
- scripts/stop.sh: kill Next.js by PID + fuser, docker compose stop
- scripts/restart.sh: stop then start

Usage:
  ./scripts/start.sh    # Start everything
  ./scripts/stop.sh     # Stop everything
  ./scripts/restart.sh  # Full restart

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-23 08:35:15 +01:00
Hartmut 624badebad feat: make responsiblePerson required on project creation/edit
- Zod schema: responsiblePerson now min(1) required, no longer optional
- ProjectModal: required indicator (*), HTML required attribute, no undefined fallback
- ProjectWizard: same fix for create flow
- Existing projects with null responsiblePerson still work (DB allows null)
- Validation enforced at API boundary on new creates/updates

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-23 07:35:42 +01:00
Hartmut 3c0befb7db feat: enhanced timeline hover tooltip with role, dates, status
The tooltip shown when hovering over project strips in the timeline
now includes additional information:
- Role name (e.g. "3D Artist", "Project Manager")
- Assignment date range (2026-03-01 → 2026-06-30)
- Status badge when not CONFIRMED (shows PROPOSED, DRAFT, etc.)
- Lead person and order type on the same line

Data comes from already-loaded timeline entries — no extra API calls.
Safe change: tooltip is pointer-events-none and read-only.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-23 07:30:08 +01:00
Hartmut d46937300a fix: Activity Log — replace useInfiniteQuery with simple useQuery + cursor
The useInfiniteQuery with tRPC as-any cast wasn't passing cursors
correctly, causing no data to load on initial page visit.

Replaced with simple useQuery + manual cursor state:
- First 50 entries load immediately on mount
- "Load more" button appends next page via cursor
- Filter changes reset cursor and entries
- keepPreviousData prevents flash during pagination

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 23:01:30 +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 3d117708ff fix: stat card sub-text on separate line below main number
The sub-text (e.g. "36 active", "30 total") was rendering inline
next to the large number, creating confusing "36₃₆ active" appearance.
Fixed by wrapping the number in a block <div> and the sub-text in a
block <p>, ensuring they stack vertically.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 22:05:55 +01:00
Hartmut 0f129dc0de fix: add InfoTooltip column descriptions + dark theme to 3 new widgets
Budget Forecast Widget:
- Project: "Active projects with a defined budget"
- Budget Usage: "Percentage of total budget consumed by current allocations"
- Burn/mo: "Monthly burn rate based on currently active allocations"
- Exhaustion: "Projected date when budget will be fully consumed"

Project Health Widget:
- Project: "Active projects scored across three health dimensions"
- B / S / T: "Budget health, Staffing health, Timeline health"
- Score: "Composite score: average of Budget, Staffing, Timeline (0-100)"
- Score badge: dark theme variants for green/amber/red

Skill Gap Widget:
- Skill: "Skills required by open demand positions"
- Demand: "Number of unfilled demand requirements needing this skill"
- Supply: "Number of active resources with this skill at proficiency 3+"
- Gap: "Supply minus Demand: negative = shortage, positive = surplus"

All three: added dark:bg-gray-800/50 thead, dark:divide-gray-800 tbody,
dark:hover:bg-gray-800/30 rows, dark:text-gray-100/300/400 text colors.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 22:04:30 +01:00
Hartmut 2c65abd231 refactor: redesign widget container for dark theme consistency
WidgetContainer redesign:
- Remove grey bg-gray-50/50 header background (clashed with dark theme)
- Header now uses transparent background with subtle separator line
- Add description prop — shows catalog description under title
- Drag grip dots appear on hover (6-dot pattern, hidden by default)
- Remove button appears on hover with red highlight
- Dark theme: bg-gray-900, border-gray-700/60, gray-800 separator
- Drag state: ring-2 ring-brand-400/30 with scale effect
- Hover state: shadow-md with border color transition

DashboardClient: passes widget.description to WidgetContainer

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 21:55:17 +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 c7b76e086d feat: unified Skills Hub — merge analytics + marketplace into one page
Combines SkillsAnalytics (496 LOC) and SkillMarketplace (346 LOC) into
a single tabbed Skills Hub (770 LOC total, -9% code).

New structure:
- skills/shared.tsx: ProficiencyBadge, GapIndicator, constants (extracted)
- skills/OverviewTab.tsx: KPI cards, top 10 table, distribution chart, export
- skills/SearchTab.tsx: skill search + proficiency + availability filter
- skills/GapsTab.tsx: supply vs demand table with gap indicators
- skills/PeopleFinderTab.tsx: multi-rule AND/OR builder, chapter filter, export
- SkillsHub.tsx: tabbed container with URL-persisted tab state (?tab=)

Routing:
- /analytics/skills renders SkillsHub (was SkillsAnalytics)
- /analytics/skill-marketplace redirects to /analytics/skills?tab=search
- Sidebar: "Skill Marketplace" removed, renamed to "Skills Hub"

No API changes — reuses existing queries with conditional fetching per tab.
Full dark theme support on all components.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 21:33:21 +01:00
Hartmut 1f4c230b8b feat: Clients admin — hierarchical tree view with parent/child support
- Tree structure: clients rendered as indented tree with visual connectors
- Expand/collapse: chevron toggle, children count badge, expand/collapse all
- Parent selector: dropdown on add + "Move..." inline picker on each client
  (excludes self and descendants to prevent circular refs)
- Search: shows matching clients AND their ancestors for context
- Depth visualization: alternating backgrounds, border-l connectors
- Drag-and-drop: preserved, reorders among siblings only

No API changes needed — router already supported parentId in CRUD.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 21:14:51 +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 a9a8a13424 fix: Blueprint list dark theme — target badges and sidebar categories
- PROJECT badge: dark:bg-purple-900/40 dark:text-purple-300
- RESOURCE badge: dark:bg-blue-900/40 dark:text-blue-300
- Global badge: dark:bg-amber-900/40 dark:text-amber-300
- Table rows: dark:hover:bg-gray-800/50, dark:border-gray-700/50
- Blueprint name: dark:text-gray-100
- Field/preset counts: dark:text-gray-400
- Sidebar category buttons in .map(): added missing dark: variants
  (root cause of persistent white hover backgrounds)

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 20:54:07 +01:00
Hartmut 4bd4b23657 fix: add missing brand-950 to Tailwind config
Root cause: brand-950 was used in 13+ files but never defined in
tailwind.config.ts (brand colors only went 50-900). All dark:bg-brand-950
classes produced no CSS output, making dark backgrounds invisible.

Fix: add brand-950 mapped to --accent-900 CSS variable (same as 900,
the darkest shade available). This makes all existing brand-950 classes
work across the entire codebase.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 20:39:08 +01:00
Hartmut 60c52eba24 fix: Blueprint catalog dark theme — use solid backgrounds, stronger contrast
- Field cards inactive: dark:bg-gray-800 (solid, no opacity)
- Field cards active: dark:bg-brand-950/60 with dark:border-brand-600/50
- Sidebar: dark:bg-slate-800/80 (darker than modal background)
- Sidebar active item: dark:bg-brand-900/60 (visible brand tint)
- Sidebar hover: dark:hover:bg-gray-700/60
- Custom field form: dark:bg-gray-800 (solid)
- Dispo import subtitle text update

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 20:34:12 +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 2988e7bf0b fix: Blueprint catalog dark theme — match app-wide dark styling
Add dark: variants to all Blueprint field catalog and card components:
- Modal: dark:bg-gray-900, borders dark:border-gray-700
- Sidebar: dark:bg-gray-800/50, active dark:bg-brand-950/40
- Field cards: dark:bg-gray-800/50 (inactive), dark:bg-brand-950/30 (active)
- Type icons: dark:bg-gray-700 (inactive), dark:bg-brand-900/50 (active)
- Toggle: dark:bg-gray-600 (off track)
- Inputs: dark:bg-gray-800, dark:border-gray-600, dark:text-gray-100
- Labels/text: dark:text-gray-200/300/400/500 throughout
- Custom field form: dark:bg-gray-800/50, dark:border-gray-600

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 20:16:21 +01:00
Hartmut 5d9f4218a0 refactor: Blueprint UI — catalog-based field selection
Replace manual field definition with a visual field catalog where admins
toggle available attributes on/off and set defaults inline.

New files:
- blueprint-field-catalog.ts: 36 pre-defined fields across 7 categories
  (Client & Billing, Technical Specs, Scope, Person Info, Organization,
  Contract, Skills & Work) for both PROJECT and RESOURCE targets
- FieldCard.tsx: toggle card with type icon, expandable default value
  editor, required/show-in-list toggles, helper text
- BlueprintFieldCatalog.tsx: main catalog modal with category sidebar,
  search bar, collapsible sections, custom field support

UX improvements:
- All standard fields pre-defined — users toggle instead of typing
- Default values set inline on each card (type-appropriate inputs)
- Fields grouped by category with enable counts
- Search/filter to find fields quickly
- Custom fields still supported via "Add Custom Field"
- Full backward compatibility: existing fieldDefs auto-map to catalog

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 19:25:08 +01:00
Hartmut da984da470 fix: timeline filter dropdown z-index — add z-0 to scroll container
The scroll container's relative positioning created a stacking context
that rendered its children (z-30 sticky labels) above the toolbar's
dropdown (z-[60]). Adding z-0 to the scroll container explicitly places
it below the toolbar's z-20 stacking context, allowing dropdowns to
render on top.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 19:10:24 +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 7a57b5e649 fix: timeline filter dropdown rendered behind scroll container
Add relative z-20 to TimelineToolbar so ProjectCombobox and
ResourceCombobox dropdowns (z-[60]) render above the scroll
container below. The scroll container's relative positioning
was creating a stacking context that overlapped the dropdowns.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 18:55:18 +01:00
Hartmut 7b48b26c26 fix: timeline filter dropdown clipped by overflow-hidden
Remove overflow-hidden from timeline page wrapper — it was clipping
the ProjectCombobox and ResourceCombobox dropdown menus. The
max-h-[100dvh] constraint combined with min-h-0 on flex children
is sufficient to keep the scroll container within viewport bounds.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 18:53:11 +01:00
Hartmut 17c335830e Merge pull request 'feat: Alive Enterprise Redesign — Sprints 0-5 + perf + bug fixes' (#16) from feature/alive-enterprise-redesign into main 2026-03-22 18:45:20 +01:00
Hartmut ba00fd9f55 feat: integrate Sentry error tracking
- @sentry/nextjs installed and configured for client, server, and edge
- Instrumentation hook registers Sentry on Node.js and edge runtimes
- Global error boundary captures unhandled errors to Sentry
- next.config.ts wrapped with withSentryConfig (source maps disabled)
- No-op when NEXT_PUBLIC_SENTRY_DSN is not set

To enable: set NEXT_PUBLIC_SENTRY_DSN in .env.local or .env.production

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-22 18:38:27 +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
Hartmut 6f34659587 feat: Sprint 3 — automation, intelligence, skill marketplace
Auto-Staffing Suggestions (A6):
- generateAutoSuggestions() ranks top-3 resources on demand creation
- Uses existing staffing engine (skill 40%, availability 30%, cost 20%, util 10%)
- Creates in-app notification with match scores for managers
- Triggered after createDemandRequirement and partial fillDemandRequirement

Vacation Conflict Detection (A7):
- checkVacationConflicts() warns when >50% chapter absent on same days
- Returns warnings array in approve/batchApprove responses (advisory, non-blocking)
- Creates VACATION_CONFLICT_WARNING notification for approver

Weekly Chargeability Alerts (A10):
- checkChargeabilityAlerts() finds resources >15pp below target
- Cron endpoint: GET /api/cron/chargeability-alerts
- Duplicate-safe by resourceId + month composite key

Rate Card Auto-Apply (A11):
- lookupRate() finds best matching rate card line (weighted scoring)
- Auto-fills demand line rates in estimate create/updateDraft when rates are 0
- Marks auto-filled lines with metadata.autoAppliedRateCard
- New lookupDemandLineRate query for on-demand UI lookups

Public Holiday Auto-Import (A12):
- autoImportPublicHolidays() generates holidays by resource federal state
- Cron endpoint: GET /api/cron/public-holidays?year=2027
- Duplicate-safe, uses existing getPublicHolidays() from shared

Skill Marketplace MVP (G6):
- New page: /analytics/skill-marketplace with 3 sections
- Skill Search: filter by name, proficiency, availability, sortable results
- Skill Gap Heat Map: supply vs demand per skill, shortage/surplus indicators
- Skill Distribution: top-20 horizontal bar chart (reuses SkillDistributionChart)
- New getSkillMarketplace query in resource router
- Sidebar nav link under Analytics for ADMIN/MANAGER/CONTROLLER

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-19 21:39:05 +01:00
Hartmut 6e5b9ec85b feat: Sprint 2 — test coverage, Dependabot, coverage gates, E2E expansion
API Router Integration Tests (43 new tests):
- dashboard-router.test.ts: 11 tests (all 5 queries + RBAC)
- project-router.test.ts: 17 tests (full CRUD + batch ops + RBAC)
- resource-router-crud.test.ts: 15 tests (CRUD + hover card + skill import)
- Fix: mock budget-alerts + cache in existing allocation/timeline tests

E2E Test Suite Expansion (29 new tests, 7 spec files):
- dashboard.spec.ts: widget grid, stat cards, add widget modal
- allocations.spec.ts: list, create modal, filters, column toggle
- estimates.spec.ts: list, wizard steps, navigation
- vacations.spec.ts: self-service, management, team calendar
- staffing.spec.ts: search, suggestions, skill tags
- admin.spec.ts: settings, users, roles, blueprints
- navigation.spec.ts: nav links, sidebar collapse, theme, mobile menu

Coverage Gates:
- api package: 80% lines, 75% branches
- application package: 80% lines, 75% branches (new vitest.config.ts)
- shared package: 70% lines, 65% branches
- CI updated to run per-package vitest --coverage

Dependabot:
- Weekly npm dependency checks with grouped minor+patch
- GitHub Actions version checks
- 10 PR limit for npm, 5 for Actions

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-19 21:29:58 +01:00
Hartmut 4118995319 feat: Sprint 1 — staffing assign, dashboard cache, bulk ops, notifications
Staffing "Assign" Button:
- Inline assignment form on each suggestion card in StaffingPanel
- Pre-fills project, dates, hours from search criteria
- 1-click confirm creates allocation with PROPOSED status
- Success/error toasts, removes assigned suggestions from list

Dashboard Redis Caching:
- New cache utility (packages/api/src/lib/cache.ts) with get/set/invalidate
- All 5 dashboard queries wrapped with 60s TTL cache-aside pattern
- Auto-invalidation on allocation + project mutations (fire-and-forget)
- Graceful fallthrough to DB if Redis unavailable

Bulk Operations:
- CSV export for selected resources and projects (apps/web/src/lib/csv-export.ts)
- Project batch delete mutation with cascade (assignments, demands, rules)
- Export/Delete buttons added to BatchActionBar on both list pages

Budget Overrun Notifications:
- checkBudgetThresholds() alerts at 80% (HIGH) and 100% (URGENT)
- Called after every allocation mutation, duplicate-safe
- Targets ADMIN + MANAGER users with SSE delivery

Estimate Approval Reminders:
- checkPendingEstimateReminders() finds SUBMITTED versions > 3 days old
- Cron endpoint: GET /api/cron/estimate-reminders (optional CRON_SECRET auth)
- Creates in-app REMINDER notifications, duplicate-safe

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-19 20:43:36 +01:00
Hartmut 0d78fe1770 feat: Sprint 0 — CI/CD pipeline, production Docker, health checks
CI Pipeline (.github/workflows/ci.yml):
- 5 jobs: typecheck, lint, test, build, e2e (parallel where possible)
- PostgreSQL 16 + Redis 7 service containers for test/e2e
- pnpm store, Turborepo, Playwright browser caching
- Concurrency groups cancel in-progress runs

Production Docker:
- Dockerfile.prod: 3-stage build (deps → build → runtime ~150MB)
- docker-compose.prod.yml: postgres + redis + app with health checks
- .dockerignore for fast builds
- next.config.ts: output: "standalone" for minimal runtime

Health Check Endpoints:
- GET /api/health — liveness probe (200 OK, no deps)
- GET /api/ready — readiness probe (postgres + redis connectivity)

Documentation:
- docs/ci-cd-manual.md — full pipeline manual with troubleshooting
- plan.md — Product Owner strategic plan (bottlenecks, growth, automation)

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-19 20:33:18 +01:00
Hartmut c02f453679 fix: hover card, preferences modal, timeline scroll, multi-drag
- ResourceHoverCard: add isInitialLoading to useEffect deps so
  mouseover/mouseout listeners attach after canvas mounts
- PreferencesModal: lift prefsOpen state to AppShell, render modal
  outside sidebar's backdrop-blur stacking context
- Timeline page: constrain to max-h-[100dvh] overflow-hidden so
  horizontal scrollbar is accessible without scrolling to bottom
- Multi-drag: pass selectedAllocationIds from ref at drag completion
  to prevent stale closure in onMultiDragComplete callback

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-19 20:30:43 +01:00
Hartmut 5ffc0d92e4 perf: lazy-load xlsx/recharts, split estimate tabs, memoize nav
- xlsx dynamically imported via cached singleton in excel.ts and
  skillMatrixParser.ts (removes ~100 kB from 4 routes)
- recharts extracted into lazy-loaded SkillDistributionChart and
  PeakTimesChart components (removes ~60 kB from 3 routes)
- EstimateWorkspaceClient: 7 tab components + 2 editors loaded via
  next/dynamic (reduces /estimates/[id] from 323 kB to 138 kB)
- ImportModal lazy-loaded in ResourcesClient (deferred until open)
- NavItem memoized with React.memo, top 5 routes get prefetch=true
- Raw <img> replaced with next/image in ProjectsClient, CoverArtSection
- tRPC QueryClient: refetchOnWindowFocus/Reconnect disabled globally

Heaviest routes reduced 39-66% First Load JS:
  /analytics/skills: 383→132 kB (-66%)
  /estimates/[id]:   323→138 kB (-57%)
  /resources/[id]:   458→210 kB (-54%)
  /estimates:        310→170 kB (-45%)
  /resources:        363→222 kB (-39%)

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-19 01:23:33 +01:00
Hartmut f1f1be21c7 feat: Sprint 3 — delight, polish, and responsive sidebar
Celebration micro-interactions:
- SuccessToast: auto-dismissing pill toast (success/info/warning variants)
- ConfettiBurst: pure CSS 20-particle confetti on project creation
- Project wizard: confetti + toast on successful creation
- Vacation approval/rejection: contextual toasts
- Allocation status change: success toast
- Button: active:scale-[0.97] press feedback on all variants

Collapsible sidebar + responsive:
- Desktop: toggle collapse (72px icons-only mode) with localStorage persistence
- NavTooltip: hover labels on collapsed icons
- Mobile: hamburger menu + slide-in overlay with backdrop
- Auto-close sidebar on mobile navigation
- Scroll-to-top on route change (smooth behavior)

Hover polish + accessibility:
- Table rows: animated left-border accent + hover-lift
- Stat cards + widgets: hover elevation + border glow
- Timeline blocks: scale(1.02) + shadow-md on hover
- Smooth scroll globally with prefers-reduced-motion fallback
- Filter chips: framer-motion scale+fade enter/exit
- Dropdowns: scaleY origin-top reveal animation
- Preferences modal: scale+fade entrance
- Link underline: animated ::after width expansion on hover

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-19 01:02:51 +01:00
Hartmut a97597093f feat: Sprint 2 — data storytelling and visual richness
Timeline project color system:
- 16-color deterministic palette (same project = same color always)
- Resource panel: allocation blocks colored by project instead of uniform green
- Project panel: colored left border + dot on project headers
- ProjectColorLegend: floating strip showing color-to-project mapping
- Utilization intensity tint: subtle background gradient on resource rows

Table visual enhancements:
- Resources: inline 3px utilization bar below chargeability percentage
- Resources: 32px avatar circles with initials + role-derived colors
- Projects: animated budget bars, styled resource count badges
- Allocations: 3px left border colored by status (green/amber/blue/gray/red)

KPI progress rings:
- Budget utilization: ProgressRing wrapping AnimatedNumber on dashboard
- Chargeability report: ring on average chargeability summary card
- Resource detail: rings on chargeability target + actual metrics
- Vacation balance: ring showing remaining days with color thresholds
- Demand widget: mini rings on FTE fill rate per project
- Resource detail: FadeIn on SkillRadarChart

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-19 00:58:06 +01:00
Hartmut ae92923c28 feat: Sprint 1 — Alive Enterprise animation foundation
Animation primitives (6 new components):
- AnimatedNumber: count-up with easeOutExpo, de-DE locale formatting
- ShimmerSkeleton: diagonal gradient sweep replacing animate-pulse
- FadeIn: framer-motion viewport-triggered fade + slide
- StaggerList/StaggerItem: staggered children entrance
- Sparkline: pure SVG inline trend chart with draw-in animation
- ProgressRing: animated circular progress with CSS transitions

Sidebar & page transitions:
- Sliding nav indicator (framer-motion layoutId animation)
- Icon frame hover glow (brand-color shadow)
- Smooth section collapse/expand (AnimatePresence height animation)
- PageTransition wrapper (fade-up on route change)
- AnimatedModal component (scale + fade with custom bezier)
- Notification badge bounce on count increase

Dashboard animations:
- StatCards: AnimatedNumber count-up + staggered FadeIn + budget color tinting
- WidgetContainer: fade-slide-up on mount
- Chargeability: animated percentages + inline utilization bars
- ProjectTable/MyProjects: animated numbers + staggered row entrance

Shimmer skeletons & table animations:
- Replaced animate-pulse across 20+ loading states with shimmer gradient
- Staggered row entrance (fadeSlideIn) on Resources, Projects, Allocations tables
- hover-lift utility class for subtle card/row elevation on hover
- Content-shaped skeletons (avatars, text bars, badges)

Light mode surface depth:
- Mesh gradient page background (subtle accent-tinted corners)
- Enhanced card shadows (two-layer depth)
- Sidebar glassmorphism upgrade (bg-white/60, backdrop-blur-2xl, saturate-150)
- Toolbar sticky backdrop blur
- Enhanced focus ring with brand-color glow

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-19 00:48:55 +01:00
Hartmut 407266bc28 chore: update plan and fix useMultiSelectIntersection types
Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-19 00:37:14 +01:00
Hartmut e7b74f13bd refactor: consolidate duplicated code across web and API packages
- Extract shared render helpers (vacation blocks, range overlay, overbooking blink) into renderHelpers.tsx
- Centralize status badge styles and vacation color maps into status-styles.ts
- Extract dragMath.ts utility from useTimelineDrag for reuse
- Split useInvalidatePlanningViews into useInvalidateTimeline (4 queries) + useInvalidatePlanningViews (8 queries)
- Adopt findUniqueOrThrow() and Prisma select constants across API routers
- Add shared fmtEur() helper for API-side money formatting
- Wrap TimelineResourcePanel and TimelineProjectPanel with React.memo
- Fix pre-existing TS2589 deep type errors in TeamCalendar and VacationModal
- 38 files changed, reducing ~400 lines of duplicated code

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