Commit graph

1673 commits

Author SHA1 Message Date
Till JS
436e92c560 feat: unify QuickInputBar across all apps with locale + deferSearch
- Add `locale` prop to all 6 apps using QuickInputBar
  (todo, contacts, zitare, citycorners, questions, calendar)
- Enable `deferSearch` on apps with create flow
  (contacts, zitare, questions) to match todo behavior
- Pass locale through Calendar's UnifiedBar wrapper
- Questions: default to 'en' locale (English-first app)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 21:06:58 +01:00
Till JS
534b55b566 test(todo-web): add tests for unified TaskFilters and viewStore filter state
- Extract applyTaskFilters as pure utility function for testability
- Add 21 tests for task filtering (priority, project, labels, search, combined)
- Add 13 tests for viewStore filter methods (setters, clearFilters, reset)
- All 87 tests passing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 21:04:21 +01:00
Till JS
c1ca93b2f1 fix(contacts-web): add patches dir to Dockerfile for pnpm install
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 21:04:06 +01:00
Till JS
9edd1c6e2e feat(shared-ui): locale-aware highlighting + success feedback for InputBar
1. Extract hardcoded German highlight patterns into locale-specific sets
   (de, en, fr, it, es). InputBar accepts `locale` or custom
   `highlightPatterns` prop, defaulting to German for backward compat.

2. Add visual success feedback after creating: input bar flashes green
   with a checkmark icon for 1.2s, confirming the action was successful.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:55:31 +01:00
Till JS
45db42720c fix(todo): pixel-perfect skeleton loaders, PillNav tab group, and SSR head fix
- Rewrite TaskListSkeleton to match notepad design (spiral holes, red margin line, cream background)
- Rewrite TaskItemSkeleton as flat rows with border-bottom instead of card style
- Rewrite KanbanColumnSkeleton with glassmorphism and pill-shaped task cards
- Update KanbanBoardSkeleton with matching border-radius and dark mode support
- Group navigation pills (Liste/Kanban/Tags) into PillTabGroup for clear UX distinction from toggle pills (Filter)
- Add Phosphor icon support to PillTabGroup component
- Fix %sveltekit.head% appearing as literal text in production by removing duplicate placeholder from HTML comment
- Disable PWA service worker in dev mode

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:51:41 +01:00
Till JS
f5842ea50e refactor(todo-web): unify FilterStrip and KanbanFilters into TaskFilters
Replace two separate filter components with a single TaskFilters component
that supports both layouts via a variant prop ("strip" for bottom pill bar,
"bar" for inline kanban-style). Fixes a bug where FilterStrip's priority
and project filters were dead local state that never actually filtered tasks.

- Add filter state (priorities, project, labels, search) to viewStore
- Apply filters to all derived task lists in the list view
- Delete FilterStrip.svelte and KanbanFilters.svelte

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:48:34 +01:00
Till JS
e00e6ee8b7 feat(shared-ui): add deferred search mode to QuickInputBar
Instead of auto-searching on every keystroke (causing flickering loader),
show two static options: "create task" and "search". Search only runs
when explicitly selected, reducing API calls and improving UX.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:48:01 +01:00
Till JS
92adabc8e2 feat(todo,contacts): add TagStrip above PillNav, unified with Calendar design
Add horizontal glass-morphism tag filter strip to Todo and Contacts apps,
matching the existing Calendar TagStrip pattern. Includes TagStripModal for
inline tag search/create/edit/delete. Contacts app gets a centralized
tagsStore replacing multiple independent tag-loading calls.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:47:41 +01:00
Till JS
1075e811f2 feat(todo-web): show QuickInputBar only on list and kanban views
Hide the task input bar on non-task pages (settings, mana, tags, etc.)
where creating tasks doesn't make contextual sense.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:39:26 +01:00
Till JS
97d6787d40 feat(todo-web): redesign task list as physical notepad
Adds notepad container with cream paper background, spiral binding holes,
red margin line, and lined rows instead of card-style task items.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 20:16:40 +01:00
Till JS
43131986a9 fix(landing-builder): change prod port to 3050 (3030 used by chat)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:51:51 +01:00
Till JS
c78809834c fix(landing-builder): rework Dockerfile to copy workspace directly
Replace pnpm deploy with direct workspace copy approach since pnpm
deploy doesn't work well with workspace:* dependencies in partial copies.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:50:22 +01:00
Till JS
9d4b59fcf8 docs(devlog): rewrite morning session devlog with all 61 commits
Comprehensive devlog covering Manalink deployment, CityCorners features,
Spiral-DB stabilization, auth migration, legacy cleanup, observability,
Mukke redesign, and landing page builder.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:29:38 +01:00
Till JS
060eb01de7 fix(landing-builder): simplify Dockerfile COPY steps
Remove non-existent node_modules COPY for hoisted packages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:22:00 +01:00
Till JS
994f03c423 fix(landing-builder): add patches dir to Dockerfile for pnpm install
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:21:21 +01:00
Till JS
d29348d906 docs: add devlog for morning session + update guidelines to session-based
Switch devlog convention from daily to session-based (vormittag/abend).
Add devlog for Manalink prod-readiness work and deployment.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:20:40 +01:00
Till JS
df0b849408 feat: add org landing page builder service
New service that generates static Astro landing pages for organizations
and deploys them to Cloudflare Pages at {slug}.mana.how.

Components:
- Landing Builder Service (NestJS, port 3030) with Astro template
- Admin UI in Manacore web dashboard at /organizations/[id]/landing
- TeamSection + ContactSection for shared-landing-ui
- Two org themes (classic dark, warm light)
- LandingPageConfig types in shared-types
- Docker + CI/CD integration for Mac Mini deployment

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:20:10 +01:00
Till JS
da6dd4ecb8 chore: remove presi mobile app, update outdated mobile docs
- Delete apps/presi/apps/mobile/ (outdated Firebase-based, web app is primary)
- Update presi CLAUDE.md: remove mobile references, fix landing page status
- Update manadeck mobile CLAUDE.md: replace Supabase refs with Mana Core Auth
- Fix picture mobile: pin nativewind version, add shared-logger dependency
- Remove dev:presi:mobile script and env generation config

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 13:16:29 +01:00
Till JS
efcb18a98f refactor(auth): standardize mobile auth return format to { success, error }
Align mobile AuthProviders (chat, manacore) with web auth stores:
- Replace { error: { message } | null } with { success: boolean, error?: string }
- Add needsVerification support to signUp return type
- Update all consumer screens (login, register, reset-password) accordingly

All auth methods across web and mobile now use the same return pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:59:13 +01:00
Till JS
71277ba7aa refactor(manadeck-mobile): migrate from custom auth to @manacore/shared-auth
Replace 900+ lines of custom auth implementation (authService, tokenManager,
deviceManager, safeStorage) with ~280 lines wrapping @manacore/shared-auth.
Auth now goes through mana-core-auth directly instead of manadeck backend.

Backward-compatible API: all consumers (stores, apiClient, hooks) work
without changes thanks to wrapper maintaining the same export interface.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:55:28 +01:00
Till JS
c59eba7285 test(citycorners): add backend test suite (31 tests) and update documentation
Tests: Jest + ts-jest with mock factories. 4 test suites covering LocationService (CRUD, search), FavoriteService (add/remove, conflicts), LocationLookupService (web search, extraction, error handling), LocationController (endpoints, query params).

Docs: Complete CLAUDE.md rewrite with live URLs, all endpoints, web pages, features, environment variables, Docker config, and test overview.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:44:46 +01:00
Till JS
79207bf43f fix(matrix): strip react-native patches in Dockerfile before pnpm install
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:33:36 +01:00
Till JS
34adf50a8e fix(matrix): add eslint-config to Dockerfile, revert to explicit package copies
Copying all packages pulled in Astro deps that need git. Back to
explicit copies with eslint-config added.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:32:38 +01:00
Till JS
e0f7e325e0 fix(matrix): copy all packages dir in Dockerfile to fix workspace resolution
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:31:42 +01:00
Till JS
c1d390b7ec fix(matrix): add patches dir to Dockerfile for pnpm install
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:27:23 +01:00
Till JS
0f93496364 feat(citycorners): add web lookup for new locations via mana-search
Backend: GET /locations/lookup?q= endpoint that searches via mana-search, extracts content from top results, auto-detects address and category, returns pre-filled data with source links.

Frontend: /add page now has a two-step flow:
1. Search step: user enters a place name, backend scrapes the web
2. Edit step: form pre-filled with found data (name, description, address, category), user can review/edit before submitting. Shows source links.

Also fixed all API paths to use /api/v1/ prefix via centralized api() helper.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:23:24 +01:00
Till JS
416e031f69 feat(matrix): add tests, E2EE warning, and dynamic homeserver config
- Make SSO loginToken homeserver configurable via VITE_MATRIX_HOMESERVER
- Add vitest setup with 14 unit tests for Matrix client functions
  (discoverHomeserver, checkHomeserver, loginWithToken)
- Show amber warning banner when E2EE is not available

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:18:07 +01:00
Till JS
a4f52df138 fix(citycorners): add /api/v1/ prefix to all API calls and add location submission form
API paths: Created centralized api() helper in $lib/api.ts. All fetch calls now use /api/v1/ prefix matching the production NestJS route structure.

New feature: /add page where authenticated users can submit new locations with name, category, description, and optional address. Added "Hinzufügen" nav item with plus icon.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:12:56 +01:00
Till JS
241cb3332a refactor(auth): standardize URL resolution and token handling across all web auth stores
Align all 20 web app auth stores to a consistent pattern:
- Use DEV_* constants with import.meta.env.DEV guard (no localhost leak in prod)
- Pass backendUrl to initializeWebAuth for automatic 401 token refresh
- Add redirectTo to forgotPassword for correct post-reset redirect

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:11:52 +01:00
Till JS
f71e7d371b docs: add TODO for rotating leaked API keys from git history
Keys were removed from .env.development but remain in git history.
OpenAI, Gemini, Replicate, and Supabase keys need rotation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:10:53 +01:00
Till JS
b76746229e chore: remove @manacore/shared-supabase package
Package was unused — no imports found across the entire codebase.
All apps have migrated to direct PostgreSQL (Drizzle ORM) for backends
and mana-core-auth API for mobile/web clients.

Removes package and all documentation references.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:07:14 +01:00
Till JS
5bd967900f refactor(context-mobile): migrate from Supabase to backend API + mana-core-auth
Complete migration of Context mobile app from direct Supabase access
to NestJS backend API with mana-core-auth authentication.

New files:
- context/AuthProvider.tsx: mana-core-auth integration via @manacore/shared-auth
- services/backendApi.ts: Backend API client for spaces, documents, AI, tokens

Rewritten services (same exports, backend implementation):
- supabaseService.ts: Now thin wrapper around backendApi
- aiService.ts: Uses backendApi for auth token
- tokenCountingService.ts: Model prices from backend API
- tokenTransactionService.ts: All token ops via backend API
- revenueCatService.ts: Token balance via backend API

Updated 16 consumer files (auth forms, token components, AI toolbars)

Deleted:
- utils/supabase.ts, context/AuthContext.tsx
- services/spaceService.ts, services/spaceServiceDirect.ts

Dependencies:
- Added: @manacore/shared-auth, expo-secure-store
- Removed: @supabase/supabase-js, @google/generative-ai, openai, @azure/openai

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:01:58 +01:00
Till JS
c6d5d4840e fix(matrix): prod-readiness fixes for Manalink web app
Add error/404 page, security headers (hooks.server.ts), fix SSO to use
dynamic homeserver, make auth URL configurable via env var, remove all
console.log statements, and disable PWA devOptions in production.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 12:01:22 +01:00
Till JS
0e8d2026d3 fix(citycorners): change backend port to 3041 (3025 used by mana-llm)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:46:01 +01:00
Till JS
343f30e321 refactor(manacore-mobile): migrate from Supabase to mana-core-auth
Complete migration of ManaCore mobile app from direct Supabase access
to mana-core-auth API. Removes @supabase/supabase-js dependency entirely.

New files:
- context/AuthProvider.tsx: mana-core-auth integration via @manacore/shared-auth
- services/api.ts: ManaCoreApi client wrapping mana-core-auth REST endpoints

Migrated (17 files):
- Auth: signIn/signUp/signOut → @manacore/shared-auth with SecureStore
- Profiles: supabase.from('profiles') → /api/v1/auth/profile
- Organizations: supabase.from('organizations') → /api/v1/auth/organizations
- Credits: supabase.from('credit_transactions') → /api/v1/credits/balance
- Members: supabase.from('user_roles') → /api/v1/auth/organizations/:id/members

Simplified (teams not yet in mana-core-auth):
- CreateTeam, TeamList, TeamMembers → placeholder with TODO
- SendMana → shows balance only, transfer coming later

Deleted:
- utils/supabase.ts, utils/memoryStorage.ts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:41:48 +01:00
Till JS
99d16673bd fix(citycorners): add missing shared packages and patches to web Dockerfile
Add shared-i18n, shared-pwa, and patches directory to the Docker build context.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:38:45 +01:00
Till JS
9747e10d68 fix(todo): add missing shared-app-onboarding to Dockerfile
The onboarding package was imported in the layout but not copied
into the Docker build context, causing production builds to fail.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:37:49 +01:00
Till JS
71b9339310 refactor: move llm-playground from services/ to apps/playground/
The LLM playground is a SvelteKit web app (frontend), not a backend
microservice. Moving it to apps/ follows the monorepo convention where
all user-facing apps live under apps/.

- Moved services/llm-playground/ → apps/playground/apps/web/
- Renamed package from @mana-llm/playground to @playground/web
- Updated Dockerfile paths for new location
- Updated docker-compose.macmini.yml build context
- Removed unused concurrently dependency
- Added parent package.json

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:25:54 +01:00
Till JS
40718a7554 chore: remove dead Supabase keys and leaked API keys from env config
SECURITY: Remove live API keys that were committed to .env.development:
- Worldream OpenAI key (sk-proj-...)
- Worldream Gemini key
- Worldream Replicate token
- Worldream Supabase anon key (live JWT)

These keys should be rotated immediately.

Also removes dead Supabase config for:
- Maerchenzauber (archived)
- Memoro (archived)
- ManaDeck (migrated to PostgreSQL + Drizzle)
- ManaCore (will be migrated to mana-core-auth)

Cleans up generate-env.mjs to remove Memoro entries and
Supabase references from ManaDeck and Worldream.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:25:24 +01:00
Till JS
07365c31b2 chore: remove stale docs and outdated design plans
- docs/AUTOMATED_TESTING_SYSTEM.md (implementation report, workflow already exists)
- docs/README_ENV_AUDIT.md (index for already-deleted audit files)
- docs/DEPENDENCY_ALIGNMENT.md (version tracking, immediately outdated)
- .claude/plans/mana-search-service.md (draft from Jan 2025, service already built)
- .claude/plans/questions-app.md (draft from Jan 2025, app already built)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:15:29 +01:00
Till JS
fae139e7e0 fix(context): remove cloud API keys from mobile app, route through backend
SECURITY FIX: The mobile app had Azure OpenAI and Google Gemini API keys
exposed in client code (dangerouslyAllowBrowser: true).

Changes:
- Mobile aiService.ts: Remove OpenAI/Gemini SDKs, route all AI calls
  through the Context backend API (which uses mana-llm)
- Backend ai.controller.ts: Add /generate/mobile and /estimate/mobile
  endpoints that accept Supabase JWT tokens (extracts userId from payload)
- Original /generate and /estimate endpoints unchanged (mana-core-auth)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:13:55 +01:00
Till JS
a2f8c32059 feat(citycorners): add PWA, i18n (DE/EN), and migrate landing to Tailwind
PWA: @vite-pwa/sveltekit with shared-pwa config, offline fallback page, service worker with standard caching preset.

i18n: svelte-i18n with DE/EN locale files, all UI strings translated, language switcher in PillNav, auth pages use shared-i18n translations.

Landing: Migrated from scoped CSS to Tailwind CSS with @astrojs/tailwind. Hero section, card grid, category filter buttons, detail page with timeline. Removed unused components (Welcome, ThemeToggle, update-locations.js).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:11:51 +01:00
Till JS
7691f66cbb refactor(todo): move Feedback, Themes, Spiral to profile dropdown
Move secondary navigation items (Themes, Spiral) from the main pill
nav bar into the user profile dropdown menu. Feedback and Settings
were already there. This declutters the main nav to just core views:
Liste, Kanban, Filter, Tags.

Add themesHref and spiralHref optional props to PillNavigation
component so any app can show these in the user dropdown.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:10:41 +01:00
Till JS
ea7962501d chore: fix config conflicts, update README, clean up apps-archived
- Delete .prettierrc (conflicted with .prettierrc.json — kept tabs config)
- Delete .env.example (outdated, .env.development is the source of truth)
- Rewrite README.md with all 18 active projects (was listing only 4)
- Fix CLAUDE.md apps-archived section (listed 11 non-existent apps)
- Delete apps-archived/mukke (duplicate of active apps/mukke)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:06:40 +01:00
Till JS
7910737dd9 fix(mana-media): use prom-client directly instead of shared metrics package
mana-media uses NestJS 11 while shared-nestjs-metrics targets NestJS 10,
causing DynamicModule type incompatibility. Use prom-client directly with
a simple MetricsController to expose /metrics endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:06:09 +01:00
Till JS
677a499c93 feat(contacts): integrate spiral-db for visual contact network
Add spiral-db integration to Contacts as the third app using
pixel-based spiral visualization. Contacts are encoded with
name, company, city, and email/phone flags.

Changes:
- Add createContactSchema() to spiral-db with bool fields for
  hasEmail/hasPhone and nullable company/city
- Create Svelte 5 spiral store with importContacts from contactsStore
- Add SpiralCanvas component and /spiral route
- Wire up navigation (Ctrl+5) with auto-import on mount
- Favorites show as starred entries with gold border

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:02:19 +01:00
Till JS
512cf412cc feat(citycorners): add location search with QuickInputBar integration
Backend: GET /locations/search?q= endpoint with ILIKE on name, description, address.
Frontend: QuickInputBar wired up in app layout, searches locations via API, navigates to detail page on select.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 11:00:10 +01:00
Till JS
1c5c2446f6 feat(citycorners): add city guide app for Konstanz with full monorepo integration
New project with three apps:
- Landing (Astro): static site with SVG illustrations, location data
- Backend (NestJS, port 3025): CRUD API for locations + favorites, Drizzle ORM, auth via mana-core-auth
- Web (SvelteKit, port 5196): Tailwind 4, PillNav, auth (login/register/SSO), Leaflet map, favorites with optimistic updates, theme/settings

Infrastructure: DB init SQL, setup-databases.sh, generate-env.mjs, root package.json scripts, Dockerfiles, docker-compose.macmini.yml (backend:3025, web:5022), Cloudflare wrangler.toml.

Branding: registered in shared-branding (AppId, APP_BRANDING, APP_ICONS, MANA_APPS, CitycornersLogo).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 10:56:26 +01:00
Till JS
cf37d92633 feat(mukke): redesign FullPlayer as immersive fullscreen experience
Replace popup overlay with fullscreen page where the visualizer fills
the entire background. Controls overlay at bottom with gradient for
readability. Visualizer switcher in top-right corner.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 10:52:10 +01:00
Till JS
734ab8012a fix(docker): add patches directory to mana-media Dockerfile
The pnpm-lock.yaml references patches (react-native-reanimated) which
must be present for pnpm install --frozen-lockfile to succeed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 10:50:52 +01:00