Architecture
TimeTiles is a full-stack monorepo built with Next.js 16, Payload CMS 3, and PostgreSQL + PostGIS. This page covers the high-level architecture. See the sub-pages for deep dives into specific systems.
File parsing, schema detection, geocoding, and event creation.
Data Ingestion PipelinePayload Workflows, 3-queue architecture, and system jobs.
Background JobsSchema-driven filter generation and SQL/Payload adapters.
Dynamic FiltersTrust levels, quotas, and rate limiting.
Resource ProtectionThemes, branding, layout templates, and custom CSS.
UI CustomizationRFC 7234 caching for scheduled URL imports.
HTTP CachingMulti-language field mapping for event data.
Language SupportPayload CMS content i18n with next-intl.
Content LocalizationSystem Overview
┌──────────────────────────────────────────────────┐
│ Next.js 16 │
│ ┌───────────┐ ┌───────────┐ ┌──────────────┐ │
│ │ React 19 │ │ Payload │ │ API Routes │ │
│ │ Frontend │ │ CMS 3 │ │ (REST) │ │
│ └─────┬─────┘ └─────┬─────┘ └──────┬───────┘ │
│ │ │ │ │
│ ┌─────▼───────────────▼───────────────▼───────┐ │
│ │ PostgreSQL 17 + PostGIS 3.5 │ │
│ └─────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘
│
┌────▼────────────────────────────────┐
│ Background Workers │
│ ingest │ default │ maintenance │
└─────────────────────────────────────┘State Management
Three layers, each for a different type of state:
| Layer | Library | What it manages | Example |
|---|---|---|---|
| Server state | React Query | API data, caching, refetching | Events list, cluster data |
| Client state | Zustand | UI state, ephemeral interactions | Filter drawer open/closed, map bounds |
| URL state | nuqs | Shareable, bookmarkable state | Active filters, selected catalog |
35 custom React Query hooks in lib/hooks/ handle all data fetching. Components never call fetch() directly.
Data Flow
CSV/Excel upload or scheduled URL fetch
→ Payload Workflow queued (ingest queue)
→ Dataset detection, schema analysis
→ User reviews schema (AWAITING_APPROVAL)
→ Geocoding via providers (Nominatim → Google → OpenCage)
→ Events created in PostgreSQL
→ PostGIS spatial indexing
→ React Query cache invalidation
→ Map + timeline updateBackground Jobs
3-queue architecture using Payload’s built-in job system:
| Queue | Worker | Purpose |
|---|---|---|
ingest | worker-ingest | File imports, geocoding, event creation |
default | worker-default | Schedule manager, webhooks |
maintenance | worker-maintenance | Cleanup, cache expiry, audit rotation |
4 ingest workflows orchestrate the import pipeline. 9 system jobs run on cron schedules. See Background Jobs for the full reference.
Database
PostgreSQL 17 with PostGIS 3.5 for spatial data. Key patterns:
- Payload CMS manages schema and migrations — all tables in the
payloadschema - PostGIS functions for clustering (
ST_ClusterKMeans), distance, and spatial queries - GeoJSON standard — coordinates always in
[longitude, latitude]order - Drizzle ORM (via Payload) for type-safe database access
Frontend
- MapLibre GL JS for interactive maps with WebGL rendering
- Server-side clustering via PostGIS — the frontend never processes raw event data
- Apache ECharts for timeline histograms and charts
- next-intl for i18n (English, German) with
localePrefix: "as-needed"routing - Tailwind CSS + shadcn/ui component library in
packages/ui/
Key Design Decisions
Payload CMS integrated mode — CMS runs inside the Next.js process, sharing the same server. No separate API server needed.
PostGIS over client-side geo — All spatial queries, clustering, and distance calculations happen in the database. The frontend receives pre-processed GeoJSON.
Payload Workflows over state machines — The import pipeline uses Payload’s native workflow system for task orchestration, replacing the earlier hook-driven state machine.
React Query over Redux — Server state is managed by React Query with intelligent caching and background refetching. Client-only state uses Zustand (lightweight, no boilerplate).
Monorepo with Turbo — Shared packages (ui, assets, eslint-config, etc.) with parallel builds and intelligent caching.