Architectuur
Systeemoverzicht
De RL Padel Academy app is een mobile-first club-management applicatie. Een React Native/Expo frontend communiceert met een zelfgehoste PocketBase backend via diens REST API. Er is geen aparte API-gateway of middleware-laag — de mobiele client praat rechtstreeks met PocketBase.
De gedeelde pakketten packages/ui en packages/utils worden door de frontend-app gebruikt voor gedeelde componenten en hulpfuncties.
De Expo-app verbindt met EXPO_PUBLIC_PB_URL (standaard http://localhost:8090). In productie is dit een HTTPS-endpoint dat naar de PocketBase-server wijst.
Tech Stack
| Laag | Technologie | Versie | Rol |
|---|---|---|---|
| Mobiel framework | Expo | SDK 52 | Build-toolchain en native runtime |
| Navigatie | Expo Router | ~4.0 | Bestandsgebaseerde routing met route-groups |
| UI-bibliotheek | React Native | 0.76 | Kernrenderende primitieven |
| Styling | NativeWind | ^4.1 | Tailwind CSS utility-klassen voor React Native |
| Styling (fallback) | React Native StyleSheet | ingebouwd | Inline stijlobjecten voor complexe/dynamische stijlen |
| Backend | PocketBase | 0.22 | Ingebedde Go-server met SQLite, REST API en admin-UI |
| Auth-persistentie | AsyncStorage | 1.23.1 | Slaat PocketBase auth-token op tussen app-sessies |
| Pakketbeheer | pnpm | >=8 | Workspace-bewust monorepo-pakketbeheer |
| Taal | TypeScript | ^5.3 | Statische typering in alle pakketten |
Frontend Architectuur
Bestandsgebaseerde Routing (Expo Router 4)
Expo Router gebruikt het bestandssysteem onder apps/frontend/app/ als route-definitie. Het project gebruikt twee route-groups:
(auth)/— niet-geauthenticeerde schermen (inloggen)(app)/— geauthenticeerde schermen (alle functionaliteitsschermen)
Route-groups zijn omhuld door hun eigen _layout.tsx-bestanden. De root-_layout.tsx bevat RootLayoutNav, die AuthContext bewaakt en programmatische redirects uitvoert:
- Niet-geauthenticeerde gebruiker buiten
(auth)→ redirect naar/(auth)/ - Geauthenticeerde gebruiker binnen
(auth)→ redirect naar/(app)/home
Dit is de enige plek waar routing-guards worden afgedwongen. Elk scherm binnen (app)/ mag aannemen dat er een geldige geauthenticeerde gebruiker is.
AuthContext
context/AuthContext.tsx biedt een React-context met de volgende vorm:
interface AuthContextValue { user: AppUser | null; isLoading: boolean; login(email: string, pass: string): Promise<void>; logout(): void;}AuthProvider omhult de gehele app. Bij het mounten roept het initPocketBase() aan vanuit lib/pocketbase.ts, die een eerder opgeslagen token leest uit AsyncStorage, dit laadt in de PocketBase auth-store en authRefresh() aanroept om het te valideren. Als de validatie mislukt wordt de store gewist. De provider abonneert zich ook op pb.authStore.onChange zodat tokenwijzigingen direct worden weerspiegeld in de React-state.
Aangepaste Tabnavigatie
In plaats van de ingebouwde tabnavigator van Expo Router implementeert de app een eigen horizontaal scrollbare tabbar in app/(app)/_layout.tsx. Het actieve tabblad-set wordt berekend vanuit ROLE_TABS[user.role] — een statisch opzoekobject dat elke rol koppelt aan een geordende lijst van tabsleutels.
Backend Architectuur
PocketBase
PocketBase is een enkele Go-binary die het volgende bundelt:
- Een SQLite-database voor alle persistente gegevens
- Een REST API (
/api/collections/:name/records) automatisch gegenereerd uit het schema - Een realtime-subscriptie-eindpunt voor live-updates
- Een bestandsopslaglaag die geüploade bestanden serveert
- Een Admin UI op
/_/voor schemabeheer en recordinspectie
Het schema is gedefinieerd in apps/pocketbase/pb_schema.json. Het setup.sh-script downloadt de binary en past migraties toe; start.sh start de server op poort 8090.
Toegangsregelpatroon
PocketBase-toegangsregels zijn filter-expressies die per verzoek worden geëvalueerd:
| Patroon | Expressie | Gebruik |
|---|---|---|
| Elke ingelogde gebruiker | @request.auth.id != '' | Leesbewerkingen op clubcontent |
| Eigen record | @request.auth.id = user.id | Reserveringen, facturen |
| Eigenaar-only | @request.auth.role = 'eigenaar' | Beheermutaties op contentcollecties |
| Trainer of eigenaar | @request.auth.role = 'trainer' || @request.auth.role = 'eigenaar' | Trainingenbeheer |
| Zelf of eigenaar | @request.auth.id = trainer.id || @request.auth.role = 'eigenaar' | Trainerbeschikbaarheid |
Dataflow: App Start naar Scherm met Data
Kleurensysteem
Alle schermen delen hetzelfde donkergroene ontwerppalet, gedefinieerd als een COLORS/C-constanteobject:
| Token | Hex | Gebruik |
|---|---|---|
bg | #0a0c0b | Paginaachtergrond |
surface | #111410 | Kaartachtergronden |
surface2 | #181c17 | Geneste surfaces, invoervelden |
teal | #2e8b76 | Primaire merkkleur, CTA-knoppen |
tealLight | #3aad94 | Gemarkeerde waarden, actief tabbladtekst |
gold | #c9a84c | Waarschuwingsstatus, “bijna vol”-indicators |
text | #eaebe8 | Primaire tekst |
text2 | #9a9e98 | Secundaire/metatekst |
text3 | #5a5e58 | Subtekst, plaatsaanduidingen |
Monorepo Structuur
| Pad | Doel |
|---|---|
apps/frontend | Expo Router 4 + React Native iOS-app |
apps/pocketbase | PocketBase 0.22 backend (download via setup.sh) |
packages/ui | Gedeelde RN-componenten: Button, Card, Badge, SectionLabel, StatBox |
packages/utils | Pure TypeScript-hulpfuncties: format.ts en date.ts |
tools/docs-site | Astro 5 + Starlight documentatiesite |
docs/ | Markdown/MDX-documenten (architectuur, bedrijfslogica, datamodellen) |
De scheiding stelt de backend en frontend in staat onafhankelijk te evolueren en maakt het eenvoudig om een webdashboard of adminpaneel toe te voegen als nieuwe app.