Mathics

POST
LOGGET

Et planlægnings- og vagtplanssystem til folkene i tårnet. Flyvekontrol kører 24/7 på tværs af flere positioner, der hver kræver specifikke certificeringer, med hvileregler, der ikke er valgfri, og en arbejdsstyrke, der — ligesom alle andre — også gerne vil have weekender fri og forudsigelige vagtbytter. At gøre det i et regneark er præcis så elendigt, som det lyder.

Problemets form

At bygge en vagtplan for en ATC-enhed er ikke en generisk shift-planner. Et par ting gør det specifikt:

  • Positionsbundet — controllere er ikke ombyttelige. Hver godkendt position kræver en, der i øjeblikket er certificeret til den, med opdaterede currency-timer.
  • Hårde hvileregler — minimumshvile mellem vagter, maksimum timer pr. uge, recency-krav. De er regulative, ikke præferencer.
  • Tidszone-ærlighed — operationer krydser UTC og lokal tid, og en vagtplan vist i den forkerte zone er værre end ingen plan overhovedet.
  • Bytter og fravær — controllere bytter vagter og søger fravær konstant. Hver ændring skal revalideres mod de samme constraints i realtid.
  • Høj tæthed — måneders vagter × dusinvis af controllere × flere positioner er mange celler, og de skal alle være læsbare, scrollbare og redigerbare uden at UI’et kvæles.

Produktet er bygget op om et timeline-grid-view, der overflader alt det, og lader en planlægger bygge, justere og validere en plan uden at forlade siden.

Stack

Produktet er en full-stack React-app på Cloudflare, bygget op om TanStack-økosystemet og et Radix-baseret designsystem.

  • TanStack Start — full-stack React-framework. SSR for hurtigt first paint på et tungt vagtplansview, med server-funktioner til datalogik, der ikke skal sendes til klienten.
  • TanStack Router — typesikker routing med searchparam-as-state til vagtplansviewet (datointerval, filtre, valgt position osv. lever alle i URL’en og overlever refresh / deling).
  • TanStack Query — server-state cache. Vagtplansviewet læser fra mange endpoints parallelt; React Query håndterer dedup, invalidering og optimistiske opdateringer, når en planlægger dropper en vagt på en celle.
  • TanStack Table + react-window — timeline-griddet er en virtualiseret tabel. Måneders vagter × dusinvis af controllere passer ikke i et naivt DOM-træ.
  • TanStack Form + Zod — fraværsanmodninger, byttetilbud og de små forms spredt rundt i appen. Zod-skemaer er den eneste sandhedskilde for validering og deles med API-kontrakten.
  • Radix UI primitives + et Shadcn-style designsystem — tilgængelige, headless komponenter (dialog, popover, dropdown, tooltip, scroll-area osv.) styled med Tailwind. class-variance-authority + tailwind-merge holder varianter ryddelige.
  • Tailwind CSS v4 — stylinglaget.
  • Motion — mikroanimationer ved tilstandsændringer (vagt-drop, byt-afgørelse, konflikt-banner-reveals).
  • Recharts — udnyttelses-, træthed- og dækningsanalyser lagt oven på vagtplanen.
  • date-fns + date-fns-tz — hver dato i systemet er tidszone-bevidst; intet renderes uden en eksplicit zone.
  • Orval — genererer den typede API-klient + React Query-hooks + Zod-skemaer ud fra backendens OpenAPI-spec, så klienten aldrig driver fra kontrakten.
  • MSW — request-mocking til lokal udvikling og Storybook-stories, så UI’et kan bygges og testes mod realistiske svar uden backend.
  • Sonner — toasts ved byt-godkendelser, sync-fejl osv.
  • Tabler Icons + Lucide — ikonsystem.
  • Sentry — fejlsporing for både React-appen og SSR-runtimen.
  • Cloudflare Workers + Wrangler — deployer til edge, tæt på hvor planlæggerne faktisk sidder.
  • Paraglide — i18n med typesikre message-nøgler.

Kvalitet og tooling

  • Storybook med a11y- og Vitest-addons — hver interaktiv komponent har stories, og Vitest-addon kører dem som tests i CI.
  • Playwright til end-to-end-flows, der spænder over flere sider (publicer en plan, controller accepterer et byt, planlægger gennemgår).
  • Vitest i browser-mode til de units, der rører DOM og kræver reel layout/interaktion.
  • ESLint v9 + Prettier med sorterede imports og Tailwind-klasse-sortering.
  • Husky + lint-staged + commitlint så det rodede fanges, før det lander.

Resultat

I produktion hos dem, der faktisk skal planlægge tårne. Arkitekturen er bygget til løbende at blive udvidet — nye constraint-typer, nye analyselag, nye integrationer med de underliggende bemandingssystemer — uden at omskrive overfladen.