Commit Graph

32 Commits

Author SHA1 Message Date
Hartmut c794e82464 test(web): add 23 edge-case tests across UI components and lib utils
Covers: aria-sort/aria-labelledby attributes, non-Error throws in
ErrorBoundary, NaN/MAX_SAFE_INTEGER in formatCents, invalid dates,
carriage returns in CSV, self-closing HTML tags in sanitize, non-digit
input in DateInput, panel-click-not-dismissing in ConfirmDialog,
role="search" on FilterBar.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 23:14:59 +02:00
Hartmut d3f721ce58 refactor(web): extract ResourcesClient types + inline components, fix test TS errors
Extract types.ts, FilterDropdown.tsx, BooleanBadge.tsx from
ResourcesClient.tsx into resource-client/ subdirectory.
ResourcesClient reduced from 1,613 to 1,507 lines.

Fix TypeScript strict mode errors across 8 test files:
- Add id/order to BlueprintFieldDefinition test objects
- Use FieldType enum instead of string literals in useFilters
- Add non-null assertions for mock.calls array access
- Type ScrollDiv for jsdom scrollLeft workaround
- Fix exactOptionalPropertyTypes violations

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 22:40:24 +02:00
Hartmut dcac9952ca test(web): add 232 tests for catalog, presets, skeleton, hooks
Lib: blueprint-field-catalog (74).

Hooks: useAppPreferences (25), useTheme (19),
useMultiSelectIntersection (12), useTimelineKeyboard (21).

Components: ColumnTogglePanel, DateRangePresets (17, timezone-safe),
ShimmerSkeleton (29), SuccessToast.

Fix ShimmerGroup tests to use plain divs (ShimmerSkeleton doesn't
forward the style prop from cloneElement).
Fix DateRangePresets tests to compute expected dates via toISOString
matching the component's UTC conversion.

Web test suite: 87 → 96 files, 844 → 1076 tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 17:27:35 +02:00
Hartmut a3d75973ee test(web): add 291 tests for parsers, hooks, and UI components
Lib utilities: scopeImportParser (31), status-styles (58),
planningEntryIds (10), uuid (11).

Hooks: useFilters (28), useRowOrder (18), usePermissions (30),
useViewPrefs (24).

Components: AnimatedModal (14), DateInput (22), InfoTooltip (13),
ProgressRing (19).

Web test suite: 75 → 87 files, 553 → 844 tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 17:14:11 +02:00
Hartmut 98dca6126f test(web): add 210 tests for lib utils, hooks, and UI components
Lib utilities: format (38), sanitize (12), project-colors (18),
csv-export (14).

Hooks: useDebounce (8), useTableSort (22), useLocalStorage (18),
useColumnConfig (19).

Components: BatchActionBar (17), SortableColumnHeader (14),
FilterChips (14), ErrorBoundary (16).

Web test suite: 63 → 75 files, 343 → 553 tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 17:11:00 +02:00
Hartmut 0d79f97d7a fix(types): remove unnecessary as any casts in web components
- ProjectHealthWidget: row already typed as ProjectHealthRow with id field
- ResourceDetail: use narrowed unknown cast instead of any for error code
- provider.tsx: same pattern for TRPCClientError data access
- ChatPanel: use intersection type for Next.js typed route push

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 15:13:06 +02:00
Hartmut e4bf121b33 feat(ui): weekend/vacation/checkbox colors follow accent theme
- Unify Saturday+Sunday into single isWeekend flag (header + grid lines)
- Replace hardcoded amber vacation bar/tooltip colors with brand-* classes
- Add global accent-color for checkboxes and radio buttons via CSS variable
- Update VACATION_TIMELINE_COLORS/BORDER to use brand palette (SICK stays red)
- Vacation-only tooltip uses neutral dark surface with brand accent border

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 14:06:44 +02:00
Hartmut d1a21a79b2 fix(ui): comprehensive dark-theme hardcoded color pass
Phase 1 — globals.css: add ~45 new dark-mode override rules covering 250+
component instances at once:
- bg-*-50 (red/green/blue/yellow/amber/purple/indigo/orange/brand/emerald)
- border-*-200 (colored alert/badge borders)
- hover:bg-*-50/100 (colored hover states)
- text-amber-700/orange-600/green-600/emerald-700/brand-700 (missing overrides)
- divide-gray-50 (ChargeabilityWidget sticky section dividers)

Phase 2 — targeted component fixes:
- Button.tsx: add dark variants to secondary (bg-gray-800) and ghost variants
- DynamicFieldEditor.tsx: add dark variants to INPUT_NORMAL and INPUT_ERROR constants
- WidgetContainer.tsx: replace slate-900 (blue-tinted) gradient with neutral
  surface-card values (rgb 22,23,26 / 16,17,19)
- status-styles.ts: add explicit dark variants to PROJECT_STATUS_BADGE and
  ORDER_TYPE_BADGE (consistent with other badge maps in same file)

Phase 3 — dashboard widget tables:
- TopValueWidget: dark thead, tbody divider, row hover
- DemandWidget: dark thead, tbody divider, row hover
- ChargeabilityWidget: dark sticky h3 headers (bg-white→surface-card),
  border-gray-100 thead rows, divide-gray-50 tbodys

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 22:37:43 +02:00
Hartmut 1833182e90 fix(security): harden input validation schemas and fix SSR sanitize bypass
- blueprint rolePresets: cap array at 100 items to prevent storage abuse
- notification CreateManagedNotification: add .max() on title (500),
  body (2000), type (100), entityType/entityId (200), link (1000),
  taskAction (200)
- settings: add .max() on all string config fields; add regex allowlist
  (/^[a-zA-Z0-9._-]+$/) on model name fields (geminiModel,
  azureDalleDeployment, azureOpenAiDeployment) to prevent path manipulation
- sanitizeHtml: fix SSR bypass — server-side branch now strips HTML tags
  instead of returning the raw string unchanged

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 21:38:16 +02:00
Hartmut 485e220c49 fix(api,web): env startup validation, QueryClient defaults, warn on missing REDIS_URL
- Throw at startup in production if REDIS_URL/DATABASE_URL/NEXTAUTH_SECRET missing
- Warn in development when REDIS_URL falls back to localhost
- QueryClient: add gcTime, disable refetchOnWindowFocus, skip retry on 4xx

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 16:42:34 +02:00
Hartmut 1df208dbcc feat(timeline): add pulse animation for in-flight drag mutations
Allocation bars that have active optimistic overrides (post-drag,
awaiting server confirmation) now pulse subtly via animate-pulse.
The pending set is derived from the existing optimisticAllocations
map keys, requiring no additional state.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:28:46 +02:00
Hartmut bc0bb5bdb8 test: add coverage for gitlooper ticket sweep
- useFocusTrap.test.ts: 7 unit tests covering rAF-deferred focus,
  Tab/Shift+Tab wrapping, empty-list guard, and cleanup (#56)
- nextConfig.test.ts: 3 tests for /login and /blueprints redirects (#51 #52);
  5 tests for COMPLETED demand exclusion filter logic (#66)

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-03 17:33:27 +02:00
Hartmut bf8577dbaf feat(auth): proactive session expiry redirect across all delivery paths
- Split auth config into auth.config.ts (edge-safe, no argon2) and auth-edge.ts
  for middleware use; auth.ts now spreads the shared config
- Middleware wraps with auth() to redirect unauthenticated requests to /auth/signin
  before any page render; passes through /auth/, /api/, /invite/ paths
- SessionGuard client component watches useSession() and redirects on
  status=unauthenticated, closing the SPA navigation gap
- QueryCache + MutationCache in TRPCProvider redirect on UNAUTHORIZED tRPC errors
  without retrying; SessionProvider polls session state every 5 minutes
- Middleware tests updated for async auth wrapper and auth-edge mock

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-03 10:42:10 +02:00
Hartmut f8550110eb security: fix 4 OWASP quick-wins from audit round 2
A04-1 (High): docker-compose E2E_TEST_MODE now defaults to "false"
  via ${E2E_TEST_MODE:-false} — prevents accidental security bypass in
  non-test deployments. runtime-env.ts throws at startup if
  E2E_TEST_MODE=true in production.

A05-3 (Medium): all 4 cron routes now fail-closed when CRON_SECRET
  is unset. Extracted shared verifyCronSecret() helper to
  apps/web/src/lib/cron-auth.ts.

A02-1 (Low): verifyCronSecret uses crypto.timingSafeEqual for
  constant-time Bearer token comparison.

A10-1 (Medium): Slack webhook routing uses strict hostname check
  (parsedUrl.hostname === "hooks.slack.com") instead of .includes()
  to prevent bypass via subdomain confusion.

Tickets created for remaining findings: #28 (TOTP rate limit),
#29 (allocations role check), #30 (API keys in DB), #31 (pgAdmin
creds), #32 (MFA enforcement), #33 (auth anomaly alerting),
#34 (comment server-side sanitization).

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-01 22:57:51 +02:00
Hartmut 73ef3b2bba test(web): align workbook export buffer typing 2026-03-31 23:06:00 +02:00
Hartmut 160ba99b5c refactor(insights): share workbook export and ai defaults 2026-03-31 22:53:53 +02:00
Hartmut db50e2e555 feat(import): harden workbook parser boundaries 2026-03-31 22:48:30 +02:00
Hartmut f6daf21983 feat(import): harden untrusted spreadsheet boundaries 2026-03-30 08:02:52 +02: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 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 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 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 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 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
Hartmut ddec3a927a feat: timeline multi-select, demand popover, resource hover card, merged tooltips, dark mode fixes
Major timeline enhancements:
- Right-click drag multi-selection with floating action bar (batch delete/assign)
- DemandPopover for demand strip details (replaces broken "Loading" modal)
- ResourceHoverCard on name hover showing skills, rates, role, chapter
- Merged heatmap+vacation tooltips into unified TimelineTooltip component
- Fixed overbooking blink animation (date normalization, z-index ordering)
- Fixed dark mode sticky column bleed-through in project view
- System roles admin page, notification task management, performance review docs

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-18 23:43:51 +01:00
Hartmut 093e13b88f feat: project cover art with AI generation, branding rename, RBAC fix, computation graph
- Add DALL-E cover art generation for projects (Azure OpenAI + standard OpenAI)
- CoverArtSection component with generate/upload/remove/focus-point controls
- Client-side image compression (10MB input → WebP/JPEG, max 1920px)
- DALL-E settings in admin panel (deployment, endpoint, API key)
- MCP assistant tools for cover art (generate_project_cover, remove_project_cover)
- Rename "Planarchy" → "plANARCHY" across all UI-facing text (13 files)
- Fix hardcoded canEdit={true} on project detail page — now checks user role
- Computation graph visualization (2D/3D) for calculation rules
- OG image and OpenGraph metadata

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-18 11:31:56 +01:00
Hartmut eb283147d1 feat: project colors, timeline filters, sidebar fix, GitLooper agent, and misc improvements
- Fix sidebar double-highlight on /vacations/my (Gitea #6): add isNavItemActive() helper
- Add project color picker (schema + API + modal + timeline rendering)
- Add ProjectCombobox/ResourceCombobox to timeline toolbar
- Show PENDING vacations on timeline with dashed/dimmed style
- Add "show demand projects" preference with localStorage persistence
- Add ProjectAssignmentsTable with total hours/cost columns
- Extend vacation API to accept status arrays
- Add GitLooper formal YAML agent configuration
- Extend user admin with permission overrides UI
- Add delete-assignment use case tests
- Add status-styles.ts shared badge constants
- Centralize formatMoney/formatCents in format.ts

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-17 10:22:52 +01:00
Hartmut b0e55786c3 feat: AI assistant (HartBOT), demand filling, budget-per-role, project favorites, and UX improvements
AI Assistant (HartBOT):
- Chat panel with inline layout, session persistence, message history (up-arrow recall)
- OpenAI function calling with 20+ tools (search, navigate, create/cancel allocations, update status)
- RBAC-aware tool filtering, fuzzy search with word-level matching
- Navigation actions (router.push) and data invalidation after mutations
- Country/metro city/org unit/role filtering on resource search

Demand Filling Enhancements:
- Two-phase fill modal: plan multiple resources, then confirm & assign all at once
- Availability preview per resource (available/partial/conflict days, existing bookings)
- Coverage bar showing demand hours distribution across assigned resources
- Fill demand from project detail page (new Assign button per demand)
- Fixed: filled demands no longer shown on timeline, demand bars no longer overlap

Budget per Role:
- DemandRequirement.budgetCents field (schema + API + UI)
- Project wizard step 3: budget input per role with allocation summary bar
- Project detail: allocated vs booked budget per demand
- Fill demand modal: role budget display with cost estimates
- AllocationModal: budget field for demand editing

Project Favorites:
- User.favoriteProjectIds (JSONB) with toggle API
- Star button on projects list and detail page (optimistic updates)
- "My Projects" dashboard widget (favorites + responsible person projects)

Project Management:
- Edit project from detail page (ProjectModal integration)
- Edit demands from detail page (AllocationModal integration)
- Admin-only project deletion (cascades assignments + demands)
- Create user accounts from admin panel

Timeline Fixes:
- Country multi-select filter with backend support
- URL param sync for same-page navigation (AI assistant integration)
- Demand lane stacking (no more overlapping bars)
- Single-day booking resize handles (always visible, min 6px)
- Single-day resize allowed (start === end)
- "All Clients" toggle (select all / deselect all)

Other Fixes:
- crypto.randomUUID fallback for non-secure contexts
- Chat message limit raised (200 max, client sends last 40)
- Status dropdown portal (no longer clipped by table overflow)
- Cents display restored in budget views (2 decimal places)
- Allocations grouped view with project sub-groups (collapsed by default)
- Server-side resource search for project wizard (no 500 limit)

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-16 15:31:48 +01:00
Hartmut 625a842d89 feat: dashboard overhaul, chargeability reports, dispo import enhancements, UI polish
Dashboard: expanded chargeability widget, resource/project table widgets
with sorting and filters, stat cards with formatMoney integration.

Chargeability: new report client with filtering, chargeability-bookings
use case, updated dashboard overview logic.

Dispo import: TBD project handling, parse-dispo-matrix improvements,
stage-dispo-projects resource value scores, new tests.

Estimates: CommercialTermsEditor component, commercial-terms engine
module, expanded estimate schemas and types.

UI: AppShell navigation updates, timeline filter/toolbar enhancements,
role management improvements, signin page redesign, Tailwind/globals
polish, SystemSettings SMTP section, anonymization support.

Tests: new router tests (anonymization, chargeability, effort-rule,
entitlement, estimate, experience-multiplier, notification, resource,
staffing, vacation).

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-14 23:29:07 +01:00
Hartmut ad0855902b refactor: complete v2 refactoring plan (Phases 1-5)
Phase 1 — Quick Wins: centralize formatMoney/formatCents, extract
findUniqueOrThrow helper (19 routers), shared Prisma select constants,
useInvalidatePlanningViews hook, status badge consolidation, composite
DB indexes.

Phase 2 — Timeline Split: extract TimelineContext, TimelineResourcePanel,
TimelineProjectPanel; split 28-dep useMemo into 3 focused memos.
TimelineView.tsx reduced from 1,903 to 538 lines.

Phase 3 — Query Performance: server-side filtering for getEntriesView,
remove availability from timeline resource select, SSE event debouncing
(50ms batch window).

Phase 4 — Estimate Workspace: extract 7 tab components and 3 editor
components. EstimateWorkspaceClient 1,298→306 lines,
EstimateWorkspaceDraftEditor 1,205→581 lines.

Phase 5 — Package Cleanup: split commit-dispo-import-batch (1,112→573
lines), extract shared pagination helper with 11 tests.

All tests pass: 209 API, 254 engine, 67 application.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-14 23:03:42 +01:00
Hartmut dd55d0e78b chore(repo): initialize planarchy workspace 2026-03-14 14:31:09 +01:00