2026-08-10 17:11:29 +02:00
2026-08-09 16:12:34 +02:00
2026-08-09 16:46:52 +02:00
2026-08-09 18:30:47 +02:00
2026-08-09 16:00:44 +02:00
2026-08-09 13:51:00 +02:00
2026-08-09 16:04:25 +02:00
2026-08-09 14:05:44 +02:00
2026-08-09 15:35:10 +02:00
2026-08-09 18:24:56 +02:00
2026-08-09 16:24:34 +02:00
2026-08-09 12:22:40 +02:00
2026-08-09 13:09:01 +02:00
2026-08-09 16:21:25 +02:00
2026-08-09 16:12:34 +02:00
2026-08-09 16:12:34 +02:00
2026-08-09 13:51:00 +02:00
2026-08-09 14:29:24 +02:00
2026-08-09 16:00:44 +02:00
2026-08-09 18:29:21 +02:00

FocusApp - Todo Application

Eine moderne, minimalistische Todo-Anwendung mit Drag & Drop, gebaut mit React und ASP.NET Core.

🚀 Features

  • Todo-Verwaltung - Erstellen, Bearbeiten, Loschen von Aufgaben
  • 🎯 Drag & Drop - Intuitive Neuordnung der Aufgaben
  • 📱 Responsive Design - Optimiert fur Desktop und Mobile
  • 🔄 RESTful API - Saubere Backend-Architektur

UI

📋 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 und den User auf dem externen MariaDB-Server.

# .env aus Template erstellen und editieren
cp .env.example .env
vim .env

# Init-Script als MariaDB Root ausfuehren
mysql -h $DB_HOST -u root -p < init-db.sql

Die .env.example enthalt:

DB_HOST=maria-db-server.domain.local
DB_PORT=3306
DB_NAME=focusapp
DB_USER=focusapp
DB_PASSWORD=<CHANGE_ME>

2. Docker Image bauen

docker compose build

Oder direkt aus dem GitHub Container Registry pullen (nach dem ersten CI-Run):

docker compose pull

3. App starten

docker compose up -d

Die App laeuft auf: http://localhost:5000

4. Logs anzeigen

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

# 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
DB_HOST MariaDB Host
DB_PORT MariaDB Port
DB_NAME Datenbankname
DB_USER Datenbank-User
DB_PASSWORD Datenbank-Passwort

📡 API Endpoints

Todos abrufen

GET /api/focustasks

Todo erstellen

POST /api/focustasks
Content-Type: application/json

{
  "title": "Neue Aufgabe",
  "description": "Optional"
}

Todo aktualisieren

PUT /api/focustasks/{id}
Content-Type: application/json

{
  "id": 1,
  "title": "Geaendert",
  "description": "Neue Beschreibung"
}

Todo loeschen

DELETE /api/focustasks/{id}

Reihenfolge aktualisieren

POST /api/focustasks/reorder
Content-Type: application/json

[1, 3, 2, 4]

Health Check

GET /api/health

Response (200 OK):

{
  "status": "healthy",
  "database": "connected",
  "timestamp": "2026-08-09T12:00:00Z",
  "version": "2.0.0"
}

Response (503 Service Unavailable):

{
  "status": "unhealthy",
  "database": "disconnected",
  "timestamp": "2026-08-09T12:00:00Z",
  "version": "2.0.0"
}

Uptime Kuma Konfiguration:

  • URL: http://localhost:5000/api/health
  • Methode: GET
  • Erwarteter Status: 200
  • Intervall: 60 Sekunden

Docker Healthcheck:

  • Automatisch in docker-compose.yml konfiguriert
  • Prüft alle 30 Sekunden den Health Endpoint
  • Container wird als healthy/unhealthy markiert

🎯 Entwicklung

Demo-Modus

Ohne MariaDB läuft die App automatisch im Demo-Modus mit SQLite und 4 Beispielaufgaben:

dotnet run
  • Frontend: http://localhost:5000
  • Swagger: http://localhost:5000/swagger
  • Datenbank: focusapp-demo.db (automatisch erstellt)

Für Produktion mit MariaDB simply die .env ausfüllen (siehe Deployment).

Backend (Development)

dotnet run

API laeuft auf: http://localhost:5000

Frontend (Development)

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).

Tests

Backend (xUnit):

cd FocusApp.Tests
dotnet test

Frontend (ESLint):

cd client
npm run lint

📦 Projektstruktur

FocusApp/
├── client/                    # React Frontend (TypeScript, Vite)
│   ├── src/
│   │   ├── components/        # React Komponenten
│   │   │   ├── TaskCard.tsx
│   │   │   └── TaskForm.tsx
│   │   ├── styles/            # CSS Design System
│   │   ├── App.tsx            # Haupt-App
│   │   ├── api.ts             # Axios API Client
│   │   ├── types.ts           # TypeScript Types
│   │   └── 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
├── Properties/
├── Program.cs                 # ASP.NET Startup
├── FocusApp.csproj            # Projekt-Datei
├── FocusApp.sln               # Solution File
├── Directory.Build.props
├── appsettings.json           # Config
├── Dockerfile                 # Multi-Stage Docker Build
├── docker-compose.yml         # Docker Compose Konfiguration
├── .env.example               # Environment Template
├── init-db.sql                # MariaDB Init Script
├── LICENSE                    # MIT License
└── renovate.json              # Dependency Updates

🐛 Troubleshooting

Container startet nicht

# Logs pruefen
docker compose logs app

# Container Status
docker compose ps

Datenbank-Fehler

# 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:

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 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:

# 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):

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:

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;
    }
}

License

Licensed under the MIT License - Copyright (c) 2026 Stefan Koelle (https://stefankoelle.de)

S
Description
No description provided
Readme MIT
628 KiB
Languages
C# 57.2%
TypeScript 35.9%
HTML 2.7%
Dockerfile 2.5%
JavaScript 1.7%