Commit Graph

292 Commits

Author SHA1 Message Date
Hartmut 43bfd9ed0a test(api): add test coverage for project and resource mutation routers
Tests auth gates (unauthenticated, wrong role, missing permissions),
input validation (duplicate shortCodes/EIDs, primary role limits, schema
enforcement), and success paths with audit logging for create, update,
deactivate, batchUpdateCustomFields, and hardDelete procedures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 23:42:36 +02:00
Hartmut 5a4836d292 perf(api): eliminate 3 N+1 query patterns
- timeline-holiday-load-support: deduplicate getResolvedCalendarHolidays
  by location key so resources sharing the same country/state/city resolve
  holidays once instead of per-resource
- rate-card-lookup: add lookupRatesBatch that loads rate card lines once
  and scores locally per demand line, replacing per-line DB round-trips
  in estimate-demand-lines autoFillDemandLineRates
- config-readmodels: include _count in utilization-category list query
  instead of calling getById per category for project counts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 22:59:45 +02:00
Hartmut dd2c9c0f88 perf(api,web,db): refactor and optimize for enterprise readiness
- Add missing @@index([userId]) on Account and Session models (auth query perf)
- Batch holiday-auto-import to eliminate N+1 query pattern (O(n) → O(1))
- Reduce SessionProvider refetchInterval from 5min to 15min
- Fix Cache-Control catch-all to stop blocking static asset caching
- Decompose assistant-tools.ts (2,562 → 809 lines) into callers, helpers, access-control modules
- Add @next/bundle-analyzer for data-driven bundle optimization
- Add @react-pdf/renderer to optimizePackageImports
- Add safety caps (take limits) on unbounded findMany queries

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 22:34:41 +02:00
Hartmut c098cedf06 perf(db): add missing indexes, fix N+1 batch delete, add pagination limits
- Add indexes on Resource(blueprintId, roleId), DemandRequirement(roleId),
  Assignment(roleId) — commonly filtered FK columns that were missing indexes
- Replace N+1 batch delete pattern (2N queries) with findAllocationEntries()
  that does 2 total queries via findMany({ id: { in: ids } })
- Add take/skip pagination with default limit of 500 to listDemands and
  listAssignments to prevent unbounded result sets

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 08:09:39 +02:00
Hartmut 110e4ff1aa fix(security): harden auth reset, rate limiter fallback, and CI secrets
- Move CI_AUTH_SECRET from plaintext to ${{ secrets.CI_AUTH_SECRET }}
- Wrap password reset (update + session kill + token mark) in $transaction
  to prevent stale sessions on partial failure (CWE-613)
- Rate limiter Redis fallback now uses stricter degraded limits
  (maxRequests/10) and logs at error level instead of warn

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 08:03:42 +02:00
Hartmut 2f2fe2631f test(api): add 38 tests for project read, project cost, and staffing shared utils
Project identifier: 4-step fallback lookup, search summaries with fuzzy notes.
Project cost: pagination, cost/person-day calculations, utilization percent.
Staffing shared: createDateRange, ACTIVE_STATUSES, createLocationLabel,
calculateAllocatedHoursForDay with absence fractions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 16:49:23 +02:00
Hartmut 45cf7b8c29 test(api): add 36 tests for insights anomalies and resource identifier read
Insights: budget burn rate, staffing gaps, timeline overruns, utilization thresholds,
summary counts, sorting. Resource: resolveByIdentifier, getHoverCard, getById,
getByEid with alias fallback, getByIdentifierDetail mapping.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 16:45:26 +02:00
Hartmut 378ed61002 test(api): add 34 router tests for estimate read/workflow and vacation read
Covers estimate list, getById, version snapshot aggregation, rethrowEstimateRouterError,
submit/approve/createRevision workflow procedures. Vacation read covers isSameUtcDay,
list, getById, getForResource, team overlap, and team overlap detail.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 16:41:18 +02:00
Hartmut a0de69a520 test(api): add 68 router tests for comment, project-lifecycle, dispo, holiday-calendar
Covers comment CRUD/resolve/delete, project status transitions and cascade
deletes, dispo import batch read/cancel/commit/resolve, and holiday calendar
catalog read with identifier fallback lookup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 16:37:02 +02:00
Hartmut 2484eb9b9d test(api): add 50 router tests for settings, webhook, and calculation rules
Phase 3c continued: covers admin settings CRUD with secret handling,
webhook lifecycle with SSRF validation, and calculation rules with
controller/manager authorization boundaries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 16:29:10 +02:00
Hartmut efe3b96676 test(api): add 48 router tests for client, role, and blueprint CRUD
Phase 3c: covers list/getById/create/update for all three routers
including authorization guards, conflict detection, NOT_FOUND errors,
and audit logging verification.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 16:26:12 +02:00
Hartmut dfeb4d361e fix(tests): align 20 drifted tests with current source behavior
Tests fell behind source changes: lastTotpAt replay-attack prevention,
activeSession invalidation on password reset, select clauses in
permission updates, UNAUTHORIZED (anti-enumeration) for disabled TOTP,
and password minimum raised from 8 to 12 characters.

Also fix root eslint.config.mjs to ignore packages/ (linted via turbo)
and add --no-warn-ignored to lint-staged to suppress warnings for
ignored files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 15:41:42 +02:00
Hartmut 43de66e982 feat(api): add audit helpers, tool registry, shared tool manifest types, and UI primitives
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 21:14:26 +02:00
Hartmut 5ad1048519 feat(dashboard): expand grid to 16 columns with auto-migration for saved 12-col layouts 2026-04-09 20:50:40 +02:00
Hartmut 1a8ea11331 feat(db): add deletedAt audit timestamp to soft-deletable models
Add deletedAt DateTime? to User, Client, Role, Resource, and Blueprint
models for GDPR-compliant deactivation audit trail. Soft-delete mutations
now stamp deletedAt: new Date() on deactivation and clear it on
reactivation. Migration and test assertions updated accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 20:03:38 +02:00
Hartmut f7407bd882 fix(api): add centralized Prisma → TRPCError middleware on protectedProcedure
P2002/P2025/P2003 now map to CONFLICT/NOT_FOUND/BAD_REQUEST with generic
messages. Raw Prisma error details no longer reach the client.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 19:58:00 +02:00
Hartmut 245b59723a fix(api): update resource-router tests for select-based listStaff queries
Tests expected include: { resourceRoles } but the Prisma select audit
changed the query to select: { ...RESOURCE_LIST_SELECT, resourceRoles }.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 19:33:58 +02:00
Hartmut 070be70848 refactor(application): extract vacation management into application use-cases
Moves approve, reject, cancel, and request vacation business logic
out of the tRPC procedure layer into packages/application, matching
the pattern used by allocation use-cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 17:11:37 +02:00
Hartmut 3c0179fcec fix(api): wrap audit log writes inside their parent transactions
Prevents mutations from committing without an audit trail if the
auditLog.create call fails after the main write already succeeded.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 16:40:10 +02:00
Hartmut a01f99561d fix(api): fix import paths missed by router reorganisation
- allocation-conflict-procedures: allocation-shared.js → allocation/shared.js
- allocation/index.ts: add missing allocationConflictProcedures spread
- allocation-conflict-check.test.ts: router/allocation.js → allocation/index.js

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 14:47:16 +02:00
Hartmut 1a8ed97d5e Merge branch 'worktree-agent-a2939317' 2026-04-09 14:44:51 +02:00
Hartmut b2c8d98b25 refactor(api): reorganise allocation router into allocation/ subdirectory
Moves read, assignment-procedures, assignment-mutations, and demand
procedures into allocation/ so the domain boundary is discoverable
without grep.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 14:44:17 +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 24435a1824 test(allocation): add conflict check tests for checkConflicts query
Covers: no-conflict baseline, overbooking detection with per-day breakdown,
vacation overlap reporting, edit-mode excludeAssignmentId exclusion,
NOT_FOUND guard, and fallback country-hours capacity path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 10:20:37 +02:00
Hartmut 1204c186ef perf(api): eliminate N+1 queries, add query guards and missing indexes
- Notification fan-out: replace sequential for loops with Promise.all (allocation-effects, notification-broadcast, create-notification)
- Public holiday batch: group resources by location combo, resolve holidays once per group, replace per-holiday delete/findFirst/create with 3 batched queries (~18K → ~5 queries)
- Add take guards to unbounded findMany calls (resource-analytics: 5000, resource-marketplace: 2000, resource-capacity: 1000, chargeability-report: 2000)
- auto-staffing: add select with only needed fields + take: 5000
- schema.prisma: add 5 missing indexes (ManagementLevel.groupId, Blueprint.isActive/target, Comment.parentId, Vacation.requestedById, Resource.managementLevelGroupId)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 08:35:13 +02:00
Hartmut 1d6d75ecf6 fix(api): wrap critical mutations in transactions and fix TOCTOU race conditions
- applyProjectScenario: wrap assignment loop in db.$transaction to prevent partial updates
- vacation approve/reject: fix TOCTOU race via updateMany with status-guard in WHERE + CONFLICT on count=0
- vacation cancel: wrap vacation.update + entitlement.updateMany in $transaction
- batchApprove: collect mutations, wrap in $transaction, dispatch SSE/notifications after commit
- Fix dead-code bug in createHappyPathDb where $transaction was assigned after return
- Add atomicity and concurrency tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 08:34:59 +02:00
Hartmut d2caba8d7c fix(test): use relative dates in insights summary test
Hardcoded dates (2026-03-20 / 2026-04-05) were now in the past, causing
the demand window filter (endDate >= now) to exclude the mock demand
requirement and miss the expected staffing anomaly.

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

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

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 00:11:12 +02:00
Hartmut ed4d4e4640 test(api): fill router auth and security coverage gaps
Four new test files — 27 tests total:
- role-router-auth.test.ts (8): UNAUTHORIZED/FORBIDDEN on all mutations for
  unauthenticated/USER callers; MANAGER and ADMIN happy paths
- webhook-router-auth.test.ts (6): adminProcedure guard verified for all
  six webhook procedures across USER/MANAGER/ADMIN roles
- comment-sanitization-router.test.ts (4): proves stripHtml runs before
  db.comment.create — script tags stripped, plain text and @mentions preserved
- auth-anomaly-check/route.test.ts (+5 unit tests): detectAuthAnomalies()
  unit coverage — empty window, global threshold, per-entity threshold, null
  entityId, and both anomaly types firing simultaneously

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-02 23:31:26 +02:00
Hartmut e3c585a403 test(scenario): add unit regression coverage for all four scenario modules
Previously untested business logic — no direct tests existed for the
scenario domain beyond auth guards and delegation stubs.

scenario-shared.test.ts (13 tests)
  - roundToTenths: rounding edge cases
  - getScenarioAvailability: null/undefined fall through to DEFAULT_AVAILABILITY
  - collectScenarioSkillSet: null, empty, lowercase, dedup, whitespace filter
  - calculateScenarioEntryHours: null resourceId → calculateAllocation,
    non-null → calculateEffectiveBookedHours with context map lookup

scenario-apply.test.ts (6 tests)
  - NOT_FOUND guard
  - remove:true → CANCELLED status, not counted in appliedCount
  - assignmentId without remove → update branch, appliedCount 1
  - no assignmentId / no resourceId → skipped, appliedCount 0
  - resourceId only → create with computed dailyCostCents (lcrCents × hours)
  - mixed changes → correct aggregate appliedCount

scenario-baseline.test.ts (6 tests)
  - NOT_FOUND guard
  - empty project → zeroed totals
  - costCents computed from lcrCents × effective hours
  - CANCELLED assignments excluded via findMany WHERE filter
  - demands mapped with headcount and roleName from roleEntity
  - totalCostCents is sum of all assignment costCents

scenario-simulation.test.ts (6 tests)
  - NOT_FOUND guard
  - unchanged carry-through → delta.headcount 0
  - remove change → delta.headcount -1
  - new resource → delta.headcount +1
  - budget exceeded → warnings includes /exceeds budget/i
  - skill coverage → delta.skillCoveragePct > 0 when scenario adds skills

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-02 21:30:46 +02:00
Hartmut e7e525df49 fix(timeline): clear multi-select on drag start and lock in SSE edge-case coverage
- useTimelineDrag: onProjectBarMouseDown and single-alloc drag path now reset
  multiSelectRef + multiSelectState before starting a new drag, so the
  FloatingActionBar is dismissed immediately when an unrelated drag begins
- FloatingActionBar.test.tsx: 4 regression tests for the null-render guard
  (count=0) and all three label variants
- useTimelineSSE.test.ts: 2 new tests — tab hides during pending reconnect
  timer (clears timer, resyncs on next open) and first-ever connection fails
  before any open (retry open still resyncs correctly)
- assistant-tools-user-admin-inventory-read.test.ts: add isActive to expected
  findMany select shape (already in production, test was stale)

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

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

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-02 08:55:39 +02:00
Hartmut e5ecea81c5 fix(auth): resolve MFA post-activation login failures — tickets #38 #40 #41
#41 (critical): Replace plain Error throws in authorize() with CredentialsSignin
subclasses (MfaRequiredError / MfaRequiredSetupError / InvalidTotpError).
Auth.js v5 forwards CredentialsSignin.code to the client via SignInResponse.code;
plain throws become CallbackRouteError and the message is never visible.
Signin page now checks result.code ?? result.error for exact code matching.

#38: MfaPromptBanner converted to fully client-side component via
trpc.user.getMfaStatus.useQuery() — disappears immediately after MFA enable
without requiring page reload. Snooze key remains userId-scoped via useSession().
Server-side prisma.user.findUnique call removed from (app)/layout.tsx.

#40: NEXTAUTH_URL default fallback removed from docker-compose.yml.
The variable is now required (:?) — docker compose up fails with a descriptive
error if the value is missing, preventing silent localhost redirect bugs.

Tests: auth.test.ts (5), MfaPromptBanner.test.ts (7), reset-password.test.ts (6)
All new tests green. pnpm --filter @capakraken/web exec tsc --noEmit clean.

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

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

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

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

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

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

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

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

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-01 23:25:06 +02:00
Hartmut d3bfa8ca98 test(mfa): full MFA test coverage — unit + E2E
Unit tests (packages/api — 13 tests):
- generateTotpSecret: DB write, returns secret + uri
- verifyAndEnableTotp: valid token enables; invalid/already-enabled/no-secret guards
- verifyTotp (login): valid → ok; invalid → UNAUTHORIZED; not-enabled → BAD_REQUEST
- getCurrentMfaStatus: reads totpEnabled flag

E2E tests (apps/web/e2e/dev-system/mfa.spec.ts — 7 scenarios):
- Setup flow: generate secret, enable with valid code, reject invalid code, UI QR check
- Login flow: MFA prompt appears, valid code logs in, wrong code shows error + stays on prompt
- Login without MFA: no TOTP prompt for users without MFA enabled

Also: start.sh health-check timeout 30s → 90s (container startup can exceed 30s)

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-01 22:30:36 +02:00
Hartmut bfdf0a82da security/platform: close audit findings #19–#26
Tests, CSP nonce middleware, SSRF guard, perf-route hardening,
Docker env isolation, migration runbook, RBAC E2E coverage.

Tickets resolved:
- #19: MfaSetup.test.ts — static source tests confirming local QR rendering
- #20: ssrf-guard.test.ts (16 tests) + webhook-procedure-support mock fix
- #21: /api/perf route.test.ts (5 tests) — header-only auth, fail-closed
- #22: middleware.ts (nonce-based CSP) + middleware.test.ts (6 tests);
       layout.tsx async + nonce prop; CSP removed from next.config.ts
- #23: Active-session registry enforcement verified (already in codebase)
- #24: docker-compose.yml REDIS_URL hardcoded (no host-env substitution)
- #25: docker-compose.yml REDIS_URL + docs/developer-runbook.md created
- #26: e2e/dev-system/rbac-data-access.spec.ts (12 tests, 3 roles × 4 procedures)

Quality gates: tsc clean, api 1447/1447, web 189/189 passing.
Turbo concurrency capped at 2 (package.json) to prevent OOM under
parallel test runs.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-01 22:14:20 +02:00
Hartmut 7277e60691 test(api): widen resource capacity edge coverage 2026-04-01 07:52:40 +02:00
Hartmut 071ea13cc4 test(api): stabilize chargeability stats regression 2026-04-01 07:45:02 +02:00
Hartmut 8c5be51251 feat(platform): checkpoint current implementation state 2026-04-01 07:42:03 +02:00
Hartmut 41916a4e46 refactor(api): share owned resource read access 2026-04-01 07:35:34 +02:00
Hartmut a0c98cf24d test(api): close assistant split regression gaps 2026-04-01 07:33:00 +02:00
Hartmut 254f2caa94 test(api): cover assistant timeline resource selection 2026-04-01 00:44:53 +02:00
Hartmut 3d9d3dd5a7 test(api): cover assistant system role configs 2026-04-01 00:44:42 +02:00
Hartmut 9c58952170 test(api): cover assistant import export tools 2026-04-01 00:44:29 +02:00
Hartmut 67f57e2791 test(api): cover ai client helpers 2026-04-01 00:44:16 +02:00
Hartmut ef282e5e00 test(api): add assistant master data mutation helpers 2026-04-01 00:42:49 +02:00
Hartmut ed021947ad test(api): add assistant timeline allocation mutation helpers 2026-04-01 00:42:43 +02:00
Hartmut 0039a9997a test(api): cover assistant project computation views 2026-04-01 00:42:02 +02:00
Hartmut 22ead3ca3d test(api): cover assistant project cover tools 2026-04-01 00:41:55 +02:00