# FocusApp - Todo Application Eine moderne, minimalistische Todo-Anwendung mit Drag & Drop, gebaut mit React und ASP.NET Core 8.0. ## πŸš€ Features - βœ… **Todo-Verwaltung** - Erstellen, Bearbeiten, Loschen von Aufgaben - 🎯 **Drag & Drop** - Intuitive Neuordnung der Aufgaben - 🎨 **Dark/Light Mode** - Automatische Theme-Erkennung - πŸ“± **Responsive Design** - Optimiert fur Desktop und Mobile - πŸ”„ **RESTful API** - Saubere Backend-Architektur ## πŸ“‹ Voraussetzungen - **Docker** und **Docker Compose** - **MariaDB** (externer Host, z.B. LXC Container) - **Git** ## 🐳 Deployment ### 1. MariaDB initialisieren (einmalig) Die FocusApp benΓΆtigt eine MariaDB Datenbank. Das Init-Script erstellt die Datenbank, den User und die Tabellen auf dem externen MariaDB-Server. ```bash # .env editieren - echte MariaDB-Zugangsdaten eintragen vim .env # Init-Script als MariaDB Root ausfuehren mysql -h $DB_HOST -u root -p < init-db.sql ``` Die `.env` enthalt: ``` DB_HOST=maria-db-server.domain.local DB_PORT=3306 DB_NAME=focusapp DB_USER=focusapp DB_PASSWORD=change-password DB_ROOT_PASSWORD=change-root-password ``` ### 2. Docker Image bauen ```bash docker compose build ``` Oder direkt aus dem GitHub Container Registry pullen (nach dem ersten CI-Run): ```bash docker compose pull ``` ### 3. App starten ```bash docker compose up -d ``` Die App laeuft auf: `http://localhost:5000` ### 4. Logs anzeigen ```bash docker compose logs -f ``` ## πŸ”„ CI/CD mit GitHub Actions Bei jedem Push auf `main` wird automatisch: 1. Das Docker-Image gebaut (Multi-Stage: Node + .NET) 2. Nach `ghcr.io` (GitHub Container Registry) gepusht 3. Alte Images aufgeraeumt (letzte 4 bleiben erhalten) ### Manuelles Deployment auf dem Host ```bash # Neuestes Image pullen docker compose pull # Container neustarten docker compose up -d ``` ## βš™οΈ Konfiguration Die App wird ueber Umgebungsvariablen konfiguriert, die in `docker-compose.yml` gesetzt werden: | Variable | Beschreibung | |---|---| | `ASPNETCORE_ENVIRONMENT` | `Production` oder `Development` | | `ConnectionStrings__DefaultConnection` | MariaDB Connection String | Der Connection-String wird aus der `.env` zusammengesetzt: ``` Server=${DB_HOST};Port=${DB_PORT};Database=${DB_NAME};User=${DB_USER};Password=${DB_PASSWORD} ``` ## πŸ“‘ API Endpoints ### Todos abrufen ```http GET /api/focustasks ``` ### Todo erstellen ```http POST /api/focustasks Content-Type: application/json { "title": "Neue Aufgabe", "description": "Optional" } ``` ### Todo aktualisieren ```http PUT /api/focustasks/{id} Content-Type: application/json { "id": 1, "title": "Geaendert", "description": "Neue Beschreibung" } ``` ### Todo loeschen ```http DELETE /api/focustasks/{id} ``` ### Reihenfolge aktualisieren ```http POST /api/focustasks/reorder Content-Type: application/json [1, 3, 2, 4] ``` ## 🎯 Entwicklung ### Backend (Development) ```bash dotnet run ``` API laeuft auf: `http://localhost:5000` ### Frontend (Development) ```bash cd client npm install npm run dev ``` React Dev Server laeuft auf: `http://localhost:5173` API-Calls werden automatisch an `http://localhost:5000` weitergeleitet (siehe `vite.config.ts`). ## πŸ“¦ Projektstruktur ``` FocusApp/ β”œβ”€β”€ client/ # React Frontend (TypeScript, Vite) β”‚ β”œβ”€β”€ src/ β”‚ β”‚ β”œβ”€β”€ components/ # React Komponenten β”‚ β”‚ β”œβ”€β”€ App.tsx # Haupt-App β”‚ β”‚ β”œβ”€β”€ api.ts # Axios API Client β”‚ β”‚ └── main.tsx # Entry Point β”‚ β”œβ”€β”€ build/ # Production Build β”‚ └── package.json β”œβ”€β”€ Controllers/ β”‚ └── FocusTasksController.cs β”œβ”€β”€ Data/ β”‚ └── FocusContext.cs # EF Core DbContext β”œβ”€β”€ Models/ β”‚ β”œβ”€β”€ FocusTask.cs # Domain Model β”‚ └── Dtos.cs # API Data Transfer Objects β”œβ”€β”€ Program.cs # ASP.NET Startup β”œβ”€β”€ FocusApp.csproj # Projekt-Datei β”œβ”€β”€ appsettings.json # Config β”œβ”€β”€ Dockerfile # Multi-Stage Docker Build β”œβ”€β”€ docker-compose.yml # Docker Compose Konfiguration β”œβ”€β”€ .env.example # Environment Template └── init-db.sql # MariaDB Init Script ``` ## πŸ› Troubleshooting ### Container startet nicht ```bash # Logs pruefen docker compose logs app # Container Status docker compose ps ``` ### Datenbank-Fehler ```bash # Pruefen ob MariaDB erreichbar ist mysql -h $DB_HOST -u $DB_USER -p # DB neu initialisieren mysql -h $DB_HOST -u root -p < init-db.sql ``` ### Port bereits belegt Port in `docker-compose.yml` aendern: ```yaml ports: - "5001:5000" ``` ## πŸ” Sicherheit ### Authentifizierung mit Authelia Die FocusApp hat **keine eigene Authentifizierung**. Alle Endpoints sind offen zugΓ€nglich. FΓΌr einen Produktiveinsatz **muss** die App hinter einem Authentifizierungs-Proxy betrieben werden. [Authelia](https://www.authelia.com/) stellt Single Sign-On (SSO) bereit und schΓΌtzt die App mit einem Reverse Proxy. **Architektur:** ``` Browser β†’ nginx + Authelia β†’ FocusApp (Docker) ↓ MariaDB (extern) ``` **Voraussetzungen:** - Authelia lΓ€uft als eigener Container/Dienst - nginx als Reverse Proxy mit Authelia-Integration **nginx-Konfiguration mit Authelia:** ```nginx # Authelia snippet einbinden include /etc/nginx/authelia/authelia-location.conf; server { listen 443 ssl; server_name focus.example.com; ssl_certificate /etc/ssl/certs/focus.crt; ssl_certificate_key /etc/ssl/private/focus.key; # Schuetzt alle Routes hinter Authelia location / { include /etc/nginx/authelia/authelia-authrequest.conf; proxy_pass http://localhost:5000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Remote-User $remote_user; } } ``` **Authelia-Konfiguration (`configuration.yml`):** ```yaml access_control: default_policy: one_factor rules: # API-Endpoints ebenfalls schuetzen - domain: focus.example.com resources: - "^/api/.*$" policy: one_factor session: name: focusapp_session secret: "your-session-secret" cookies: - domain: focus.example.com authelia_url: https://auth.example.com default_redirection_url: https://focus.example.com identity_providers: - id: ldap # oder: - id: openid_connect ``` **Wichtig:** - Ohne Authelia ist die App komplett offen β€” kein Schutz fΓΌr API oder Frontend - Authelia prΓΌft vor jedem Request die Sitzung - Der `/api/` Pfad muss ebenfalls geschΓΌtzt werden (nicht nur `/`) - FΓΌr API-Clients (z.B. Mobile Apps) kann eine API-Key-LΓΆsung implementiert werden ### Reverse Proxy (nginx) ohne Authelia FΓΌr lokale Entwicklung/Tests ohne Auth: ```nginx server { listen 443 ssl; server_name focus.example.com; ssl_certificate /etc/ssl/certs/focus.crt; ssl_certificate_key /etc/ssl/private/focus.key; location / { proxy_pass http://localhost:5000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection keep-alive; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` --- **Version:** 2.0.0 **Letzte Aktualisierung:** 09. August 2026