System Architektur
ZurückTechnischer Aufbau der SVT Regatta Applikation. Die Plattform laeuft auf zwei Raspberry Pi im Docker Swarm mit einer PostgreSQL Datenbank auf Linode. Alle Verbindungen sind via Cloudflare Tunnel verschluesselt.
Infrastruktur
graph TB
subgraph Internet
USER["Browser / Mobile"]
CF["Cloudflare<br/>CDN + DNS + Tunnel"]
CFA["Cloudflare Access<br/>Zero Trust"]
end
subgraph RaspberryPi["Docker Swarm (2x Raspberry Pi)"]
subgraph Services
FE["Frontend<br/>Flask :5001<br/>Resultate, Termine, News"]
ADMIN["Admin<br/>Flask :5002<br/>CRUD, Upload, Staff"]
API["API<br/>FastAPI :5004<br/>REST Endpoints"]
end
subgraph TestServices["Test Services"]
FE_T["Frontend Test<br/>Flask :5003"]
ADMIN_T["Admin Test<br/>Flask :5005"]
API_T["API Test<br/>FastAPI :5007"]
end
CRON["systemd Timer<br/>Staff Reminders<br/>taeglich 09:00"]
end
subgraph External["Externe Dienste"]
DB[("PostgreSQL<br/>Linode<br/>svt-regatta-db")]
TWILIO["Twilio<br/>SMS"]
SMTP["SMTP2GO<br/>E-Mail"]
CLAUDE["Claude AI<br/>News Generator"]
GHCR["GitHub Container<br/>Registry (GHCR)"]
end
USER -->|HTTPS| CF
CF -->|Tunnel| FE
CF -->|Tunnel| FE_T
CF -->|Tunnel + Access| ADMIN
CF -->|Tunnel + Access| ADMIN_T
CF -->|Tunnel| API
FE --> DB
ADMIN --> DB
API --> DB
FE_T --> DB
ADMIN_T --> DB
API_T --> DB
ADMIN --> TWILIO
ADMIN --> SMTP
ADMIN --> CLAUDE
ADMIN_T --> TWILIO
ADMIN_T --> SMTP
FE_T --> TWILIO
CRON -->|curl| ADMIN_T
GHCR -.->|docker pull| Services
style FE fill:#152B55,color:#fff
style ADMIN fill:#1a5d3a,color:#fff
style API fill:#0d6efd,color:#fff
style FE_T fill:#152B55,color:#fff,stroke-dasharray: 5 5
style ADMIN_T fill:#1a5d3a,color:#fff,stroke-dasharray: 5 5
style API_T fill:#0d6efd,color:#fff,stroke-dasharray: 5 5
style DB fill:#336791,color:#fff
style CF fill:#f38020,color:#fff
style CFA fill:#f38020,color:#fff
style TWILIO fill:#F22F46,color:#fff
style SMTP fill:#2ecc71,color:#fff
style CLAUDE fill:#7c3aed,color:#fff
style GHCR fill:#333,color:#fff
style CRON fill:#ffc107,color:#000
Datenfluss - Resultate Upload
sequenceDiagram
participant RL as Regattaleiter
participant ST as Sailrace Timer App
participant AD as Admin Portal
participant DB as PostgreSQL
participant FE as Frontend
RL->>ST: Zeitmessung Rennen
ST->>ST: CSV Export
RL->>AD: CSV Upload
AD->>DB: Results INSERT (Draft)
AD->>AD: Review & Edit
AD->>DB: UPDATE is_published=TRUE
AD->>DB: sync DNS + Ranking
FE->>DB: SELECT published results
FE->>FE: Anzeige Resultate + Gesamtwertung
Staff Benachrichtigung
sequenceDiagram
participant CRON as systemd Timer
participant AD as Admin Portal
participant DB as PostgreSQL
participant SMS as Twilio SMS
participant STAFF as Regattahelfer
participant PRES as Praesident
participant FE as Frontend
CRON->>AD: POST /api/staff-reminders/run
AD->>DB: Regatten in N Tagen?
DB-->>AD: Staff-Zuweisungen
alt Staff zugewiesen
AD->>SMS: Erinnerung + Confirm-Link
SMS->>STAFF: SMS
STAFF->>FE: Klick Confirm-Link
FE->>DB: SET confirmed_at
end
alt Kein Helfer / Kein Leiter
AD->>SMS: Missing-Staff Alert
SMS->>PRES: ACHTUNG SMS
end
alt Nicht bestaetigt (letzter Reminder)
AD->>SMS: Eskalation
SMS->>PRES: Eskalations-SMS
end
Datenbank Schema (Haupttabellen)
erDiagram
events ||--o{ regattas : "hat Termine"
events ||--o{ event_seasons : "pro Saison"
events ||--o{ race_days : "Renntage"
events ||--o{ event_entries : "Anmeldungen"
race_days ||--o{ races : "Rennen"
races ||--o{ results : "Resultate"
regattas ||--o{ regatta_staff : "Staff"
persons ||--o{ regatta_staff : "zugewiesen"
sailors ||--o{ event_entries : "Skipper"
registered_boats ||--o{ event_entries : "Boot"
boat_classes ||--o{ registered_boats : "Klasse"
events {
int id PK
string name
string slug
boolean has_season_ranking
}
regattas {
int id PK
date date
int event_id FK
time regatta_start
time regatta_end
}
races {
int id PK
int race_day_id FK
int race_number
boolean is_published
}
results {
int id PK
int race_id FK
string sailno
string boat_class
interval corrected_time
string penalty
}
sailors {
int id PK
string name
string email_hash
}
registered_boats {
int id PK
string sailno
boolean is_pool
}
Tech Stack
Backend
- Python 3.11 Flask + FastAPI
- PostgreSQL Linode Server
- Docker Swarm 2x Raspberry Pi
- Gunicorn WSGI Server
Frontend
- Bootstrap 5.3 CSS Framework
- Jinja2 Template Engine
- Vanilla JS Kein Framework
- Mermaid.js Diagramme
Security & DevOps
- Cloudflare Tunnel + Access
- SOPS + age Config Encryption
- Fernet PII Encryption
- GitHub Actions CI/CD
Entwickelt mit Claude Code (Anthropic Claude Opus). Diagramme via Mermaid.js.