stadtwerke/ARCHITECTURE.md

342 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# InnungsApp — Technische Architektur
> **Version:** 1.0 | **Stand:** Februar 2026
---
## 1. Überblick
InnungsApp besteht aus drei Hauptkomponenten:
```
┌─────────────────────────────────────────────────────────────┐
│ CLIENTS │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Mobile App │ │ Admin Web App │ │
│ │ (React Native) │ │ (Next.js) │ │
│ │ iOS + Android │ │ Browser │ │
│ └────────┬────────┘ └────────┬────────┘ │
└───────────┼────────────────────┼──────────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ SUPABASE │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ │
│ │ Auth │ │ Postgres │ │ Storage │ │ Realtime │ │
│ │ Magic │ │ + RLS │ │ PDFs │ │ Push + │ │
│ │ Link │ │ Database │ │ Images │ │ Events │ │
│ └──────────┘ └──────────┘ └──────────┘ └───────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ EXTERNE DIENSTE │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ │
│ │ Expo │ │ Resend │ │ PostHog │ │ Mux │ │
│ │ Push │ │ E-Mail │ │ Analytics│ │ Video │ │
│ │ (FCM/APNs│ │ Transact.│ │ │ │ (Q2) │ │
│ └──────────┘ └──────────┘ └──────────┘ └───────────┘ │
└─────────────────────────────────────────────────────────────┘
```
---
## 2. Mobile App (React Native + Expo)
### Tech Stack
| Schicht | Technologie | Begründung |
|---|---|---|
| Framework | React Native 0.74 + Expo SDK 51 | Eine Codebasis iOS + Android |
| Navigation | Expo Router v3 (file-based) | Typ-sicher, einfach wartbar |
| State Management | Zustand | Leichtgewichtig, kein Redux-Overhead |
| Data Fetching | TanStack Query v5 | Caching, Background Refetch, Optimistic Updates |
| UI-Komponenten | Custom + NativeWind (Tailwind on Native) | Konsistentes Design, schnelle Entwicklung |
| Push Notifications | Expo Notifications + FCM/APNs | Out-of-the-box mit Expo |
| Auth | Supabase Auth Client | Magic Link Flow |
| Type Safety | TypeScript (strict mode) | Pflicht für Produktionscode |
### Ordnerstruktur
```
apps/mobile/
├── app/ # Expo Router — File-based Navigation
│ ├── (auth)/
│ │ ├── login.tsx # Magic Link Login Screen
│ │ └── verify.tsx # Token Verification
│ ├── (tabs)/
│ │ ├── _layout.tsx # Tab Bar Layout
│ │ ├── index.tsx # Dashboard / Home Feed
│ │ ├── members.tsx # Mitgliederverzeichnis
│ │ ├── news.tsx # Mitteilungen Feed
│ │ ├── termine.tsx # Terminkalender
│ │ └── stellen.tsx # Lehrlingsbörse
│ ├── member/[id].tsx # Mitglied Detailansicht
│ ├── news/[id].tsx # Beitrag Detailansicht
│ ├── termin/[id].tsx # Termin Detailansicht
│ └── _layout.tsx # Root Layout (Auth Guard)
├── components/
│ ├── ui/ # Atomare UI-Komponenten
│ │ ├── Button.tsx
│ │ ├── Card.tsx
│ │ ├── Badge.tsx
│ │ ├── Avatar.tsx
│ │ └── Input.tsx
│ ├── members/ # Feature-spezifische Komponenten
│ ├── news/
│ ├── termine/
│ └── stellen/
├── hooks/
│ ├── useAuth.ts
│ ├── useMembers.ts
│ ├── useNews.ts
│ └── usePushNotifications.ts
├── lib/
│ ├── supabase.ts # Supabase Client Singleton
│ ├── queryClient.ts # TanStack Query Client
│ └── notifications.ts # Push Token Registration
├── store/
│ └── auth.ts # Zustand Auth Store
├── types/
│ └── database.ts # Generierte Supabase Types
└── constants/
├── colors.ts # Design Tokens
└── config.ts # Env-Variablen
```
---
## 3. Admin Web App (Next.js)
### Tech Stack
| Schicht | Technologie |
|---|---|
| Framework | Next.js 14 (App Router) |
| Styling | Tailwind CSS + shadcn/ui |
| Auth | Supabase Auth (SSR) |
| Data Fetching | Server Components + TanStack Query (Client) |
| Tables | TanStack Table v8 |
| Forms | React Hook Form + Zod |
| Charts | Recharts |
| Deployment | Vercel |
### Ordnerstruktur
```
apps/admin/
├── app/
│ ├── (auth)/
│ │ └── login/page.tsx
│ ├── (dashboard)/
│ │ ├── layout.tsx # Sidebar Layout
│ │ ├── page.tsx # Overview Dashboard
│ │ ├── members/
│ │ │ ├── page.tsx # Mitgliederliste
│ │ │ ├── new/page.tsx # Mitglied anlegen
│ │ │ └── [id]/page.tsx # Mitglied bearbeiten
│ │ ├── news/
│ │ │ ├── page.tsx
│ │ │ └── new/page.tsx
│ │ ├── termine/
│ │ ├── stellen/
│ │ └── settings/
│ └── layout.tsx
├── components/
│ ├── ui/ # shadcn/ui Komponenten
│ ├── data-table/
│ └── forms/
└── lib/
├── supabase-server.ts # Supabase SSR Client
└── actions.ts # Server Actions
```
---
## 4. Backend: Supabase
### Warum Supabase?
- **Kein eigener API-Server** nötig für MVP → spart 46 Wochen Entwicklung
- **PostgreSQL** mit vollem SQL-Zugriff → keine NoSQL-Kompromisse
- **Row Level Security** → Multi-Tenancy ohne eigene Middleware
- **Realtime** → Live-Updates ohne WebSocket-Implementierung
- **Storage** → S3-kompatibel, CDN included
- **Auth** → Magic Link, Sessions, JWT out-of-the-box
- **EU-Region Frankfurt** → DSGVO-konform
### Supabase Services genutzt
| Service | Verwendung |
|---|---|
| Auth | Magic Link Login, Session-Management, JWT |
| Database | PostgreSQL, alle Tabellen |
| Row Level Security | Multi-Tenancy, Datenisolation |
| Storage | PDF-Anhänge, Profilbilder, Logos |
| Realtime | Live-Updates (News Feed, Teilnehmerlisten) |
| Edge Functions | Komplexe Businesslogik (Einladungs-E-Mails) |
---
## 5. Multi-Tenancy Konzept
### Datenisolation via Row Level Security (RLS)
Jede Innung ist eine `organization`. Alle Tabellen haben eine `org_id` Spalte.
```sql
-- Beispiel RLS Policy für die members-Tabelle
CREATE POLICY "members_isolation" ON members
FOR ALL
USING (org_id = (
SELECT org_id FROM user_roles
WHERE user_id = auth.uid()
));
```
**Prinzip:**
- Kein Nutzer sieht Daten außerhalb seiner `org_id`
- Policy wird für jede Operation (SELECT, INSERT, UPDATE, DELETE) durchgesetzt
- Supabase prüft dies auf Datenbankebene — kein Bypass möglich
### Tenancy Identifikation
- **MVP:** `org_id` wird beim Login aus `user_roles` geladen und in allen Queries mitgegeben
- **Post-MVP:** Subdomain-Routing (`innung-elektro-stuttgart.innungsapp.de`) mit Middleware-Lookup
---
## 6. Authentifizierung
### Login Flow
```
Nutzer gibt E-Mail ein
Supabase sendet Magic Link
Nutzer klickt Link im E-Mail
App/Browser öffnet sich, Token wird verarbeitet
Supabase Auth gibt Session zurück (JWT)
App lädt user_roles → bestimmt org_id und Rolle
Redirect zu korrekter Startseite
```
### Rollen-System
```sql
CREATE TYPE user_role AS ENUM ('admin', 'member', 'public');
CREATE TABLE user_roles (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid REFERENCES auth.users NOT NULL,
org_id uuid REFERENCES organizations NOT NULL,
role user_role NOT NULL DEFAULT 'member',
created_at timestamptz DEFAULT now(),
UNIQUE(user_id, org_id)
);
```
---
## 7. Push Notifications
### Architektur
```
Admin erstellt Beitrag
Supabase Edge Function wird getriggert (via Database Webhook)
Edge Function fetcht alle Push Tokens der org_id
Expo Push Notification Service (EPNS)
┌──┴──┐
▼ ▼
APNs FCM
(iOS) (Android)
```
### Push Token Registrierung (Mobile)
```typescript
// hooks/usePushNotifications.ts
async function registerPushToken() {
const { status } = await Notifications.requestPermissionsAsync();
if (status !== 'granted') return;
const token = await Notifications.getExpoPushTokenAsync({
projectId: Constants.expoConfig.extra.eas.projectId,
});
await supabase
.from('push_tokens')
.upsert({ user_id: user.id, token: token.data });
}
```
---
## 8. Infrastruktur & Kosten
### Monatliche Kosten (MVP, bis 100 Innungen)
| Service | Plan | Kosten/Monat |
|---|---|---|
| Supabase | Pro | 25 € |
| Vercel | Pro | 20 € |
| Resend (E-Mail) | Starter | 0 € (bis 3.000 Mails) |
| Expo EAS Build | Production | 29 € |
| PostHog | Cloud | 0 € (bis 1 Mio. Events) |
| Apple Developer | (jährlich) | 8 € |
| **Gesamt** | | **~82 €/Monat** |
### Skalierung (ab 500 Innungen)
| Service | Plan | Kosten/Monat |
|---|---|---|
| Supabase | Team | 599 € |
| Vercel | Enterprise | ~400 € |
| Resend | Business | 89 € |
| **Gesamt** | | **~1.100 €/Monat** |
Break-even bei 6 zahlenden Innungen à 200 €.
---
## 9. Deployment & CI/CD
### Pipeline
```
git push → GitHub/Gitea
├── Mobile: Expo EAS Build (iOS + Android)
│ └── App Store / Play Store (manual submit)
└── Web Admin: Vercel Deploy (automatisch)
└── Preview URL für jeden Branch
```
### Environments
| Environment | Supabase | Vercel | Verwendung |
|---|---|---|---|
| `development` | Lokal (Docker) | localhost:3000 | Entwicklung |
| `staging` | Staging-Projekt | staging.innungsapp.de | Pilot-Tests |
| `production` | Pro-Projekt | app.innungsapp.de | Live |