Commit Graph

172 Commits

Author SHA1 Message Date
Hartmut bfcadd2c52 refactor(web): decompose TimelineView, ReportBuilder, and ResourceModal into focused components
Extract overlay/popover JSX from TimelineView (1268→1037 lines) into TimelineDragOverlays and
TimelinePopovers. Extract ResourceMonthConfigSection from ReportBuilder (1132→1018 lines).
Extract ResourceSkillsEditor and ResourceOrgClassification from ResourceModal (1035→714 lines).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 23:16:38 +02:00
Hartmut b3da8817dc refactor(web): extract render functions from TimelineProjectPanel into dedicated module
Move renderOpenDemandRow, renderProjectUtilOverlay, and renderProjectDragHandles
(534 lines) to timelineProjectRenderers.tsx. TimelineProjectPanel: 1230 -> 687 lines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 09:05:47 +02:00
Hartmut d1d33aa810 refactor(web): extract ReportResultsPanel and nav icons from monolithic components
Extract ReportResultsPanel (293 lines) from ReportBuilder (1231→1044 lines)
and move 38 inline icon components from AppShell (937→833 lines) to nav-icons.tsx.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 08:58:31 +02:00
Hartmut 17f2de5f48 refactor(web): decompose AllocationsClient and UsersClient into focused subcomponents
AllocationsClient (1364→962 lines): extracted AllocationRow, AllocationGroupedBody,
OpenDemandsPanel, and AllocationBatchDialogs.
UsersClient (1338→895 lines): extracted UserEditModal and UserCreateModal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 08:49:50 +02:00
Hartmut 85e1bcc06f refactor(web): decompose ProjectWizard into step components
Extract each wizard step into its own file under project-wizard/:
StepBar, DynamicFieldInput, Step1Identity, ResourcePersonPicker,
Step2Timeline, Step3Staffing, Step4Suggestions, Step5Review.
Main file reduced from 1,385 to 112 lines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 08:30:33 +02:00
Hartmut f3fa902773 fix(web): make invalidation hooks async with Promise.all and fix cross-view staleness
- useInvalidateTimeline and useInvalidatePlanningViews now return
  Promise.all instead of fire-and-forget void calls
- Timeline mutations now use useInvalidatePlanningViews to also
  invalidate allocation list views, preventing stale data
- AllocationsClient sequential awaits replaced with single
  invalidatePlanningViews() call (parallel invalidation)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 08:24:33 +02:00
Hartmut f18777c365 refactor(web): split TimelineContext into data, view, and display contexts
Reduces unnecessary re-renders by separating the monolithic 20+ property
context into TimelineDataContext, TimelineViewContext, and
TimelineDisplayContext. Panel components now subscribe only to the
slices they need.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 08:17:58 +02:00
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 797aa5e350 fix(a11y): add ARIA attributes to core UI components
AnimatedModal: ariaLabelledBy prop, EntityCombobox: combobox/listbox
pattern, FilterBar: role="search", SortableColumnHeader: aria-sort,
global-error: html lang attr, eslint label rule depth config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 23:06:25 +02:00
Hartmut 6830bfb314 refactor(web): extract 4 pure render functions from TimelineResourcePanel
Move renderAllocBlocksFromData, renderLoadGraph, renderHeatmapOverlay,
renderDailyBars into timelineResourceRender.tsx (707 lines).

TimelineResourcePanel reduced from 1,270 to 589 lines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 22:57:19 +02:00
Hartmut 9bd7172018 test(web): add 162 tests for animation components and hooks
Components: AnimatedNumber (14), InfiniteScrollSentinel (16),
FadeIn (22), StaggerList (26).

Hooks: useUrlFilters (32), useWidgetFilterOptions (27),
useProjectDragContext (27).

Web test suite: 96 → 103 files, 1076 → 1238 tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 22:45:44 +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 c0ba062460 test(web): add 57 UI component and hook tests with jsdom cleanup
Fix jsdom environment: add esbuild automatic JSX transform and
afterEach cleanup to prevent DOM leakage between tests.

Components: Badge (8), Button (13), FilterBar (5), EmptyState (8),
ConfirmDialog (8), useSelection hook (15).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 17:06:42 +02:00
Hartmut 63db4a09e6 refactor(web): set up component test infra + decompose ProjectWizard
Phase 4a: Add @testing-library/react, user-event, jest-dom, jsdom.
Switch vitest environment to jsdom, add setup file, create test-utils
with QueryClient wrapper.

Phase 4b: Extract ProjectWizard form logic into project-wizard/ subdir:
- types.ts: WizardState, Assignment, constants, factory functions
- useProjectWizardForm.ts: form state hook + canGoNext pure function

Phase 4c: 32 tests for canGoNext validation (all 5 steps), makeDefaultState,
and makeReq factory function.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 17:00:45 +02:00
Hartmut 9bd3781c03 fix(types): flatten tRPC Zod schema types to resolve TS2589 inference depth errors
Cast Zod schemas with .refine()/.superRefine() to z.ZodType<InferredType> at the
procedure level. This short-circuits TypeScript's deep type recursion through
tRPC's middleware chain, eliminating 4 of 5 @ts-expect-error TS2589 suppressions
in web components (VacationModal, ProjectModal, UsersClient, CountriesClient).

Applied same pattern to allocation, timeline, staffing, dashboard, project, and
resource query/mutation procedures to reduce client-side type depth.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 15:28:12 +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 82acc56b8d chore: add pre-commit hooks, tighten ESLint, activate Sentry DSN, publish CI coverage (Phase 1)
- Install husky v9 + lint-staged: pre-commit runs eslint --fix and prettier on staged files
- Tighten ESLint base config: no-console→error, ban-ts-comment (ts-ignore banned, ts-expect-error with description allowed), reportUnusedDisableDirectives→error
- Migrate web app from deprecated `next lint` to `eslint src/` with flat config and react-hooks plugin
- Convert all 5 @ts-ignore to @ts-expect-error with descriptions, remove stale disable comments
- Add NEXT_PUBLIC_SENTRY_DSN to docker-compose.prod.yml and .env.example
- Add coverage artifact upload step to CI test job
- Pre-existing violations (102 warnings) downgraded to warn in web config for Phase 2 cleanup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 14:49:29 +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 0339b11038 fix(ui): remove utilization row background tint from timeline
Remove the colored background tint for 50-100% utilized rows entirely.
Only over-utilized rows (>100%) keep the red warning tint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:53:21 +02:00
Hartmut 5afc6c8c94 fix(ui): remove blue-shifted hardcoded colors from timeline components
Replace hardcoded blue-shifted rgba values and slate-* classes with neutral
CSS variable references in timeline resource/project panels, tooltips,
constants, and heatmap mono palette. Change utilization row tint from blue
to green. Replace slate-950 open demand backgrounds with --surface-card.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:46:41 +02:00
Hartmut 60d89a1bc8 fix(ui): replace blue-shifted hardcoded gradient in WidgetContainer dark mode
The widget wrapper had a hardcoded dark gradient using rgba(22,23,26) and
rgba(16,17,19) which are blue-shifted. Replace with CSS variable references
--surface-elevated and --surface-card for neutral dark backgrounds.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 10:35:44 +02:00
Hartmut 05aa864359 refactor(ui): replace inline INPUT_CLS/LABEL_CLS/BTN_DANGER constants and action link classes with CSS component classes
Remove duplicated Tailwind class string constants from 15 component files.
Use app-input, app-select, app-label, app-action-danger-btn, and
app-action-delete CSS component classes from globals.css instead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 09:21:03 +02:00
Hartmut 9ba49c9ab8 fix(ui): add dark mode variants to dashboard, layout, notification and chargeability components
Add missing dark: class variants for backgrounds, borders, and text across
dashboard widgets, AppShell sidebar, notification cards, and the chargeability
report table. Replace hardcoded slate/gray hex values with CSS variable
references. Fix chargeability hover tint and remove ineffective sticky thead.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 09:20:50 +02:00
Hartmut 9b5cd8549d refactor(ui): replace inline INPUT_CLS/BTN_DANGER/action link constants with component classes
- Replace 13 local INPUT_CLS/SELECT_CLS/LABEL_CLS/BTN_DANGER constants with
  app-input, app-select, app-label, app-action-danger-btn component classes
  (CustomFieldFilterBar, RolePresetsEditor, FieldCard, BlueprintFieldCatalog,
  BlueprintFieldEditor, BlueprintsClient, EstimateWizard, EstimateWorkspace-
  DraftEditor, DemandLineEditor, ScopeItemEditor, AssumptionEditor,
  ProjectWizard, BulkEditModal)
- Replace inline text-blue-600/text-red-500 action link strings with
  app-action-edit / app-action-delete in AllocationsClient, ProjectsClient,
  ScenarioPlanner, ProjectDemandsTable, RolesClient, BlueprintsClient,
  CreateTaskModal, RateCardsClient, UsersClient, ManagementLevelsClient

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-10 07:02:08 +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 13262b5cec refactor(ui): unify dark theme — replace hardcoded hex with CSS variables
- Replace sidebar #0d0e22 hardcoded hex with .sidebar-panel class backed by
  --surface-card CSS variable so all three sidebar elements (desktop, mobile,
  mobile header) share the same neutral-dark color as the main content
- Remove purple logo gradient (dark:from-[#0d0e22] dark:to-[#13162a]) — now uses
  --surface-elevated for a neutral, unified look
- Add .dark slate-*/gray-900 overrides: bg-slate-700/800/900, border-slate-800,
  hover:bg-slate-800 all map to --surface-elevated/--surface-card/--border-subtle
- Remove dead hardcoded rgb(45 51 71) rule for dark bg-gray-100 (was overridden
  further down anyway; now consistently uses --surface-elevated)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 22:25:10 +02:00
Hartmut 1383169352 feat(ui): Aurora design system — glassmorphic dark mode, warm light mode, snappy animations
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 22:10:52 +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 1a67af6761 fix(dashboard): measure grid container width after hydration completes, not just on mount 2026-04-09 20:58:57 +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 446aea5319 feat(dashboard): combine vertical + horizontal compaction for gap-free widget layout 2026-04-09 20:42:49 +02:00
Hartmut 4875096b13 fix(dashboard): restore vertical compaction so widgets auto-align when dragged 2026-04-09 20:19:24 +02:00
Hartmut 36900a1219 Merge branch 'worktree-agent-a7de1005' 2026-04-09 19:31:11 +02:00
Hartmut d7a35b2d7a feat(web): add React error boundaries and Next.js error.tsx fallbacks
Runtime errors in components now show a friendly "Something went wrong"
screen instead of a white page. Timeline and staffing panel are
individually wrapped. Route-level error.tsx handles server component errors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 19:16:26 +02:00
Hartmut 6bf60c8e07 feat(web): persist list-page filters in URL search params
Resources, projects, and allocations filter state now syncs to/from
URL so filters survive refresh and can be shared via link.
Text inputs are debounced (300ms) to avoid URL churn.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 17:00:30 +02:00
Hartmut 7264f0728a perf(timeline): add useCallback/useMemo to timeline components
Prevents redundant re-renders when parent state changes by stabilising
event handler references and memoising expensive derived data in
TimelineView, TimelineResourcePanel, and TimelineProjectPanel.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 16:54:38 +02:00
Hartmut 75167d6129 fix(merge): resolve post-merge type errors from batch-1 agents
- ScenarioPlanner.Baseline.shortCode: string → string | null (matches Prisma)
- ScenarioPlanner.SimulationResult.chargeabilityTarget: number → number | null
- Remove runtime Zod parse from scenario procedures (typed by Prisma already)
- Float64Array index access: add non-null assertions for noUncheckedIndexedAccess

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 14:38:32 +02:00
Hartmut f3cb75bfc7 feat(mobile): add mobile summary view for 320-428px viewports (Sprint 4c)
Read-only capacity snapshot with utilization donut, top 5 active projects,
open demand alert banner, and quick-link grid — single-column card layout
optimised for PWA standalone mode.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:37:08 +02:00
Hartmut 607af1a857 feat(bench): add Resource Bench Board page
Shows resources with available capacity in a selected date window.
- Filter by date range (with DateRangePresets), min hours/day slider, and free-text search
- Cards show role, chapter, available h/day with color-coded capacity bar
- Links to individual resource profiles
- "Bench" nav entry added to Resources section in AppShell

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:30:44 +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 7a5e98e2e9 perf(timeline): add horizontal virtualization for allocation bars
Tracks scroll position via requestAnimationFrame to avoid re-renders
on every pixel. Allocation bars outside the visible horizontal window
(+ 10-column overscan) are skipped during render, reducing DOM nodes
significantly at day zoom (365 days × 40px = 14,600px canvas).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:26:38 +02:00
Hartmut e75d966b8d feat(timeline): add inline allocation editor on double-click
Double-clicking an allocation bar opens an inline editor overlay
with start date, end date, and hours/day fields. Saves via
trpc.allocation.update, closes on Escape or click outside.
Only visible to users with manage permissions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:24:43 +02:00
Hartmut fa54ef4cbd feat(timeline): add keyboard navigation with shortcut overlay
- Arrow left/right scrolls the timeline by 1 day (Shift: 1 week)
- Delete/Backspace deletes selected allocations
- ? toggles a keyboard shortcut overlay
- Floating ? button in bottom-right corner provides persistent access
- (Del) hint added to the FloatingActionBar delete button

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:20:32 +02:00
Hartmut 05f6eba5d8 refactor(staffing): decompose 735-line StaffingPanel into focused components
Splits StaffingPanel.tsx into:
- StaffingSearchForm: skill tags, dates, hours input, submit button
- ScoringExplanation: the 3-column scoring breakdown card
- StaffingResultCard: individual suggestion card with details and assign form
- StaffingResultsList: list orchestration with loading/empty states
- StaffingPanel: thin orchestrator (~100 lines) managing state and tRPC query

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:17:55 +02:00
Hartmut 594ae4f10b feat(allocations): add Excel export button to allocations toolbar
Adds an Export button that downloads visible/filtered allocation rows
as an xlsx file via the existing downloadWorkbookSheets utility.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:14:58 +02:00
Hartmut 7435fdc125 feat(timeline): Sprint 2b — AI staffing suggestions in DemandPopover
Shows top 3 resource suggestions (name, utilization, available h/d) below the
demand details using the existing staffing.getProjectStaffingSuggestions query.
Includes a shimmer loading skeleton while fetching. Each "Fill" button opens
the fill demand modal with the demand pre-loaded.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:11:36 +02:00
Hartmut 16ce6db07e feat(allocations): Sprint 2a — bulk date shift via BatchActionBar
Add "Shift Dates…" action to the batch action bar. Opens a modal with a
signed integer input; on confirm calls the existing timeline.batchShiftAllocations
procedure (allocationIds, daysDelta, mode="move").

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 13:10:06 +02:00