mitai-jinkendo/.claude/docs/working/SHINKAN_PROJECT_SETUP.md

1203 lines
32 KiB
Markdown
Raw Permalink Normal View History

# Shinkan Jinkendo – Technisches Setup
> **Trainer- und Vereinsplattform für Kampfsport-Trainingsplanung**
> Basis: Mitai Jinkendo Ökosystem
> Domain: shinkan.jinkendo.de (真観 - "Wahre Beobachtung")
---
## 1. Fachliche Einordnung
**Shinkan ist KEINE persönliche Tracking-App.**
Shinkan ist eine **trainer- und vereinszentrierte Planungs- und Inhaltsplattform** mit Fokus auf:
- Übungsverwaltung und -suche
- Trainingsplanung für Gruppen
- Standardisierung und Wiederverwendung
- Freigabe und Governance von Inhalten
- Import aus bestehendem MediaWiki
**Primäre Nutzer in MVP:** Trainer, Vereinsadmins, Redakteure
**Nicht in MVP:** Individuelle Sportler-Apps, persönliches Tracking, Gürtel-Tracking
**Abgrenzung zu Mitai:**
- Mitai = persönliches Körper- und Trainings-Tracking
- Shinkan = Trainer-Arbeit, Übungen, Trainingsplanung, Vereinsstandards
---
## 2. Übernommene Infrastruktur von Mitai
| Komponente | Status | Verwendung |
|-----------|---------|------------|
| Auth-System | ✅ 1:1 übernehmen | Token + bcrypt |
| Membership-Basis | ✅ Übernehmen | Tiers, Features (vereinfacht) |
| User-Profiles | ✅ Übernehmen | Multi-Profile pro Account |
| Tech-Stack | ✅ 1:1 | React 18 + FastAPI + PostgreSQL 16 |
| Docker/Compose | ✅ 1:1 | Dev + Prod Umgebungen |
| PWA | ✅ 1:1 | Mobile + Desktop |
| Design-System | ✅ Basis | CSS-Variablen, mobile-first |
| Versioning | ✅ 1:1 | version.py + Migrations |
| Gitea CI/CD | ✅ 1:1 | Auto-Deploy dev/prod |
**Ports:**
- Prod: 3003/8003 (Frontend/Backend)
- Dev: 3098/8098 (Frontend/Backend)
---
## 3. Technische Basis (identisch zu Mitai)
```
Frontend: React 18 + Vite + PWA (Node 20)
Backend: FastAPI Python 3.12
Datenbank: PostgreSQL 16 Alpine
Container: Docker + Docker Compose
Auth: Token-basiert + bcrypt
KI: OpenRouter API (optional, nicht MVP-kritisch)
```
---
## 4. Verzeichnisstruktur (angepasst)
```
shinkan-jinkendo/
├── backend/
│ ├── main.py # App-Setup + Router-Registration
│ ├── db.py # PostgreSQL Connection Pool
│ ├── db_init.py # DB-Init + Migrations
│ ├── auth.py # Hash, Verify, Sessions, Feature-Access
│ ├── models.py # Pydantic Models
│ ├── version.py # Versionskontrolle
│ ├── migrations/ # SQL-Migrationen (001_*.sql)
│ └── routers/
│ ├── auth.py # Login, Register, Sessions
│ ├── profiles.py # User-Profiles
│ ├── clubs.py # Vereine / Sparten
│ ├── groups.py # Trainingsgruppen
│ ├── skills.py # Fähigkeiten (Admin + CRUD)
│ ├── methods.py # Trainingsmethoden (Admin + CRUD)
│ ├── exercises.py # Übungen (Kern-Modul)
│ ├── training_units.py # Trainingseinheiten
│ ├── training_programs.py # Trainingsprogramme
│ ├── planning.py # Planungsansichten
│ ├── import_wiki.py # MediaWiki-Import
│ ├── admin.py # Admin-Panel
│ └── membership.py # Subscription (vereinfacht)
│
├── frontend/
│ ├── src/
│ │ ├── App.jsx # Root, Auth-Gates, Navigation
│ │ ├── app.css # CSS-Variablen + Styles
│ │ ├── version.js # Frontend-Versionierung
│ │ ├── config/
│ │ │ ├── appNav.js # Hauptnavigation
│ │ │ └── adminNav.js # Admin-Navigation
│ │ ├── context/
│ │ │ ├── AuthContext.jsx
│ │ │ └── ProfileContext.jsx
│ │ ├── pages/
│ │ │ ├── Dashboard.jsx
│ │ │ ├── ExercisesPage.jsx # Übungssuche + CRUD
│ │ │ ├── PlanningPage.jsx # Trainingsplanung
│ │ │ ├── GroupsPage.jsx # Gruppenverwaltung
│ │ │ ├── SkillsPage.jsx # Fähigkeiten (Admin)
│ │ │ ├── MethodsPage.jsx # Methoden (Admin)
│ │ │ ├── ImportPage.jsx # MediaWiki-Import
│ │ │ └── SettingsPage.jsx
│ │ └── utils/
│ │ ├── api.js # ALLE API-Calls
│ │ └── planning.js # Planungshelfer
│ └── public/
│ ├── manifest.json # PWA-Manifest
│ └── icons/
│
├── .claude/
│ ├── commands/ # Slash-Commands
│ ├── docs/
│ │ ├── functional/
│ │ │ └── SHINKAN_REQUIREMENTS.md # Anforderungsdokument
│ │ ├── technical/
│ │ │ └── SHINKAN_DOMAIN_MODEL.md # Domänenmodell
│ │ └── rules/ # Architektur-Regeln (wie Mitai)
│ └── library/
│
├── docker-compose.yml # Production
├── docker-compose.dev-env.yml # Development
├── .env
├── .gitignore
└── CLAUDE.md # Agent-Einstieg
```
---
## 5. Domänenmodell (MVP Core)
### 5.1 Organisationsstruktur
```sql
-- Vereine
clubs (
id SERIAL PRIMARY KEY,
name VARCHAR(200) NOT NULL,
abbreviation VARCHAR(50),
description TEXT,
status VARCHAR(50) DEFAULT 'active',
created_at TIMESTAMP DEFAULT NOW()
)
-- Sparten (optional, kann auch später)
divisions (
id SERIAL PRIMARY KEY,
club_id INT REFERENCES clubs(id),
name VARCHAR(200) NOT NULL,
focus_area VARCHAR(100), -- karate, selbstverteidigung, gewaltschutz
created_at TIMESTAMP DEFAULT NOW()
)
-- Trainingsgruppen
training_groups (
id SERIAL PRIMARY KEY,
club_id INT REFERENCES clubs(id),
division_id INT REFERENCES divisions(id),
name VARCHAR(200) NOT NULL,
focus VARCHAR(100),
level VARCHAR(50),
age_group VARCHAR(50),
weekday VARCHAR(20),
time_start TIME,
time_end TIME,
location VARCHAR(200),
trainer_id INT REFERENCES profiles(id),
co_trainer_ids JSONB, -- [1, 2, 3]
status VARCHAR(50) DEFAULT 'active',
created_at TIMESTAMP DEFAULT NOW()
)
```
### 5.2 Fähigkeiten und Methoden (Kataloge)
```sql
-- Fähigkeiten (global)
skills (
id SERIAL PRIMARY KEY,
name VARCHAR(200) NOT NULL,
category VARCHAR(100), -- kihon, kumite, kata, selbstverteidigung, fitness
description TEXT,
importance INT, -- 1-5
keywords JSONB,
status VARCHAR(50) DEFAULT 'active',
created_at TIMESTAMP DEFAULT NOW()
)
-- Trainingsmethoden (global)
training_methods (
id SERIAL PRIMARY KEY,
name VARCHAR(200) NOT NULL,
abbreviation VARCHAR(20),
category VARCHAR(100), -- intervall, rollenspiel, zirkel, koordination, etc.
description TEXT,
typical_duration INT, -- in Minuten
typical_group_size VARCHAR(50),
related_skills JSONB, -- [skill_id, skill_id, ...]
keywords JSONB,
status VARCHAR(50) DEFAULT 'active',
created_at TIMESTAMP DEFAULT NOW()
)
```
### 5.3 Übungen (Kernobjekt)
```sql
-- Übungen
exercises (
id SERIAL PRIMARY KEY,
title VARCHAR(300) NOT NULL,
summary TEXT, -- Kurzbeschreibung
goal TEXT NOT NULL, -- Ziel der Übung
execution TEXT NOT NULL, -- Durchführung
preparation TEXT, -- Vorbereitung / Aufbau
trainer_notes TEXT, -- Hinweise für Trainer
equipment JSONB, -- ["Matten", "Pratzen", "Bälle"]
-- Metadaten
duration_min INT,
duration_max INT,
group_size_min INT,
group_size_max INT,
age_groups JSONB, -- ["minis", "kinder", "erwachsene"]
-- Fachliche Zuordnung
focus_area VARCHAR(100), -- karate, selbstverteidigung, gewaltschutz
secondary_areas JSONB,
training_character VARCHAR(50), -- grundlage, aufbau, vertiefung, festigung, diagnose
-- Methode
primary_method_id INT REFERENCES training_methods(id),
secondary_method_ids JSONB,
-- Freigabe
visibility VARCHAR(50) DEFAULT 'private', -- private, club, official
status VARCHAR(50) DEFAULT 'draft', -- draft, in_review, approved, archived
created_by INT REFERENCES profiles(id),
club_id INT REFERENCES clubs(id),
-- Import
import_source VARCHAR(50), -- mediawiki, manual
import_id VARCHAR(200),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
)
-- Übungs-Fähigkeiten (M:N)
exercise_skills (
id SERIAL PRIMARY KEY,
exercise_id INT REFERENCES exercises(id) ON DELETE CASCADE,
skill_id INT REFERENCES skills(id),
is_primary BOOLEAN DEFAULT false,
intensity INT, -- 1-5
development_contribution VARCHAR(50), -- low, medium, high
required_level INT, -- Eingangs-Niveau
target_level INT, -- Ziel-Niveau
created_at TIMESTAMP DEFAULT NOW()
)
-- Übungsvarianten
exercise_variants (
id SERIAL PRIMARY KEY,
exercise_id INT REFERENCES exercises(id) ON DELETE CASCADE,
variant_name VARCHAR(200) NOT NULL,
description TEXT,
execution_changes TEXT,
duration_min INT,
duration_max INT,
equipment_changes JSONB,
difficulty_adjustment VARCHAR(50), -- easier, harder, adapted
age_group_override JSONB,
skill_focus_override JSONB,
created_at TIMESTAMP DEFAULT NOW()
)
-- Medien (1:N)
exercise_media (
id SERIAL PRIMARY KEY,
exercise_id INT REFERENCES exercises(id) ON DELETE CASCADE,
media_type VARCHAR(50), -- image, video, document, sketch
file_path TEXT,
title VARCHAR(200),
description TEXT,
sort_order INT,
is_primary BOOLEAN DEFAULT false,
context VARCHAR(100), -- ablauf, detail, trainer_hint
created_at TIMESTAMP DEFAULT NOW()
)
```
### 5.4 Trainingsplanung
```sql
-- Training Templates / Standards (vereinbar)
training_templates (
id SERIAL PRIMARY KEY,
name VARCHAR(300) NOT NULL,
type VARCHAR(50), -- template, standard
club_id INT REFERENCES clubs(id),
division_id INT REFERENCES divisions(id),
goal TEXT,
focus_areas JSONB,
duration_total INT,
visibility VARCHAR(50) DEFAULT 'private',
status VARCHAR(50) DEFAULT 'active',
version INT DEFAULT 1,
created_by INT REFERENCES profiles(id),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
)
-- Trainingsabschnitte (für Templates + Units)
training_sections (
id SERIAL PRIMARY KEY,
parent_type VARCHAR(50), -- template, unit
parent_id INT,
title VARCHAR(200) NOT NULL,
section_type VARCHAR(100), -- aufwaermen, kihon, kumite, kata, abschluss, etc.
sort_order INT,
duration_planned INT,
goal TEXT,
notes TEXT,
is_combination BOOLEAN DEFAULT false, -- Übungen als Komplex
combination_method_id INT REFERENCES training_methods(id),
created_at TIMESTAMP DEFAULT NOW()
)
-- Übungen in Abschnitten
section_exercises (
id SERIAL PRIMARY KEY,
section_id INT REFERENCES training_sections(id) ON DELETE CASCADE,
exercise_id INT REFERENCES exercises(id),
variant_id INT REFERENCES exercise_variants(id),
sort_order INT,
duration_planned INT,
notes TEXT,
created_at TIMESTAMP DEFAULT NOW()
)
-- Konkrete Trainingseinheiten
training_units (
id SERIAL PRIMARY KEY,
group_id INT REFERENCES training_groups(id),
date DATE NOT NULL,
time_start TIME,
time_end TIME,
derived_from_template_id INT REFERENCES training_templates(id),
derived_from_unit_id INT REFERENCES training_units(id),
title VARCHAR(300),
goal TEXT,
focus_areas JSONB,
-- Durchführung
actual_time_start TIME,
actual_time_end TIME,
completion_status VARCHAR(50), -- planned, in_progress, completed
-- Reflexion
reflection_text TEXT,
what_worked_well TEXT,
what_to_improve TEXT,
created_by INT REFERENCES profiles(id),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
)
-- Trainingsprogramme
training_programs (
id SERIAL PRIMARY KEY,
club_id INT REFERENCES clubs(id),
division_id INT REFERENCES divisions(id),
name VARCHAR(300) NOT NULL,
description TEXT,
goal TEXT,
duration_weeks INT,
focus_areas JSONB,
visibility VARCHAR(50) DEFAULT 'private',
status VARCHAR(50) DEFAULT 'active',
created_by INT REFERENCES profiles(id),
created_at TIMESTAMP DEFAULT NOW()
)
-- Programm-Einheiten (Reihenfolge)
program_units (
id SERIAL PRIMARY KEY,
program_id INT REFERENCES training_programs(id) ON DELETE CASCADE,
unit_order INT,
template_id INT REFERENCES training_templates(id),
week_number INT,
notes TEXT,
created_at TIMESTAMP DEFAULT NOW()
)
```
### 5.5 Governance
```sql
-- Änderungsanfragen (für geschützte Inhalte)
content_change_requests (
id SERIAL PRIMARY KEY,
content_type VARCHAR(50), -- exercise, template, skill, method
content_id INT,
requested_by INT REFERENCES profiles(id),
change_description TEXT,
change_details JSONB,
status VARCHAR(50) DEFAULT 'pending', -- pending, approved, rejected
reviewed_by INT REFERENCES profiles(id),
review_notes TEXT,
created_at TIMESTAMP DEFAULT NOW(),
reviewed_at TIMESTAMP
)
```
### 5.6 MediaWiki-Import
```sql
-- Import-Tracking
wiki_import_log (
id SERIAL PRIMARY KEY,
import_type VARCHAR(50), -- skill, method, exercise
import_status VARCHAR(50), -- success, partial, failed
items_total INT,
items_imported INT,
items_failed INT,
error_log JSONB,
imported_by INT REFERENCES profiles(id),
created_at TIMESTAMP DEFAULT NOW()
)
-- Import-Referenzen (für Re-Import-Schutz)
wiki_import_references (
id SERIAL PRIMARY KEY,
wiki_page_title VARCHAR(300),
wiki_page_id VARCHAR(100),
content_type VARCHAR(50), -- skill, method, exercise
local_id INT,
last_imported TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(wiki_page_title, content_type)
)
```
---
## 6. MVP Core-Features (Release 1)
### 6.1 Pflicht in MVP
**Organisationsstruktur:**
- ✅ Verein anlegen/verwalten
- ✅ Trainingsgruppen anlegen/verwalten
- ✅ Trainer zuordnen
**Kataloge:**
- ✅ Fähigkeiten-Katalog (Admin CRUD)
- ✅ Methoden-Katalog (Admin CRUD)
**Übungen:**
- ✅ Übung anlegen (minimal: Titel, Ziel, Durchführung)
- ✅ Übung vollständig beschreiben (alle Felder)
- ✅ Übungsvarianten anlegen
- ✅ Fähigkeiten zuordnen (Haupt/Neben, Intensität)
- ✅ Methoden zuordnen (Haupt/Neben)
- ✅ Medien hochladen (Bilder, Videos)
- ✅ Übung suchen und filtern
- Schnellsuche (Titel, Schlagworte)
- Filter (Bereich, Zielgruppe, Fähigkeit, Dauer, Gruppengröße)
- ✅ Übung drucken
- ✅ Freigabelogik (privat / Verein / offiziell)
**Trainingsplanung:**
- ✅ Trainingseinheit für Gruppe + Termin planen
- ✅ Training aus Vorlage ableiten
- ✅ Training aus altem Training kopieren
- ✅ Trainingsabschnitte verwalten
- ✅ Übungen zu Abschnitten zuordnen
- ✅ Kombinations-Flag für Abschnitte
- ✅ Kalenderansicht (Gruppe, Datum)
- ✅ Druckansicht
- ✅ Mobile Durchführungssicht
- ✅ Notizen zu Training + Übungen
- ✅ Reflexion nach Training
**Import:**
- ✅ Einseitiger MediaWiki-Import
- Fähigkeiten
- Methoden
- Übungen
- ✅ Import-Tracking (Erfolg/Fehler)
- ✅ Duplikat-Erkennung (Wiki-Referenz)
### 6.2 Bewusst NICHT in MVP
**Kern-Features, die warten:**
- ❌ KI-Trainingsplanung
- ❌ KI-Suche mit externen Calls
- ❌ Sportler-Tracking (individuelle Entwicklung)
- ❌ Gürtel/Graduierungs-System
- ❌ Technik-Mastery-Tracking
- ❌ Reifegradmodell (vollständig)
- ❌ Turnier-/Wettkampfbegleitung
- ❌ Community/Marktplatz
- ❌ Komplexe Membership-Matrix
- ❌ Vollhistorisierung jeder Änderung
- ❌ Bidirektionale Wiki-Sync
- ❌ Offline-Sync (vollständig)
**Rollen/Governance (vereinfacht):**
- ❌ Feingranulare Rechte-Matrix
- ❌ Workflow-basierte Freigabe
- ❌ Multi-Tenant-Administration
---
## 7. Initiale Migrationen (MVP)
### 7.1 001_auth_membership.sql
```sql
-- Von Mitai übernehmen:
-- profiles, sessions, features, tier_limits, subscriptions
-- (siehe Mitai 001_*.sql + 002_*.sql)
```
### 7.2 002_organization.sql
```sql
-- Vereine
CREATE TABLE clubs (
id SERIAL PRIMARY KEY,
name VARCHAR(200) NOT NULL,
abbreviation VARCHAR(50),
description TEXT,
status VARCHAR(50) DEFAULT 'active',
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Sparten (optional, kann später)
CREATE TABLE divisions (
id SERIAL PRIMARY KEY,
club_id INT REFERENCES clubs(id) ON DELETE CASCADE,
name VARCHAR(200) NOT NULL,
focus_area VARCHAR(100),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Trainingsgruppen
CREATE TABLE training_groups (
id SERIAL PRIMARY KEY,
club_id INT REFERENCES clubs(id) ON DELETE CASCADE,
division_id INT REFERENCES divisions(id),
name VARCHAR(200) NOT NULL,
focus VARCHAR(100),
level VARCHAR(50),
age_group VARCHAR(50),
weekday VARCHAR(20),
time_start TIME,
time_end TIME,
location VARCHAR(200),
trainer_id INT REFERENCES profiles(id),
co_trainer_ids JSONB,
status VARCHAR(50) DEFAULT 'active',
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_groups_club ON training_groups(club_id);
CREATE INDEX idx_groups_trainer ON training_groups(trainer_id);
```
### 7.3 003_catalogs.sql
```sql
-- Fähigkeiten
CREATE TABLE skills (
id SERIAL PRIMARY KEY,
name VARCHAR(200) NOT NULL,
category VARCHAR(100),
description TEXT,
importance INT CHECK (importance BETWEEN 1 AND 5),
keywords JSONB,
status VARCHAR(50) DEFAULT 'active',
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Trainingsmethoden
CREATE TABLE training_methods (
id SERIAL PRIMARY KEY,
name VARCHAR(200) NOT NULL,
abbreviation VARCHAR(20),
category VARCHAR(100),
description TEXT,
typical_duration INT,
typical_group_size VARCHAR(50),
related_skills JSONB,
keywords JSONB,
status VARCHAR(50) DEFAULT 'active',
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_skills_category ON skills(category);
CREATE INDEX idx_methods_category ON training_methods(category);
```
### 7.4 004_exercises.sql
```sql
-- Übungen
CREATE TABLE exercises (
id SERIAL PRIMARY KEY,
title VARCHAR(300) NOT NULL,
summary TEXT,
goal TEXT NOT NULL,
execution TEXT NOT NULL,
preparation TEXT,
trainer_notes TEXT,
equipment JSONB,
duration_min INT,
duration_max INT,
group_size_min INT,
group_size_max INT,
age_groups JSONB,
focus_area VARCHAR(100),
secondary_areas JSONB,
training_character VARCHAR(50),
primary_method_id INT REFERENCES training_methods(id),
secondary_method_ids JSONB,
visibility VARCHAR(50) DEFAULT 'private',
status VARCHAR(50) DEFAULT 'draft',
created_by INT REFERENCES profiles(id),
club_id INT REFERENCES clubs(id),
import_source VARCHAR(50),
import_id VARCHAR(200),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Übungs-Fähigkeiten
CREATE TABLE exercise_skills (
id SERIAL PRIMARY KEY,
exercise_id INT REFERENCES exercises(id) ON DELETE CASCADE,
skill_id INT REFERENCES skills(id),
is_primary BOOLEAN DEFAULT false,
intensity INT CHECK (intensity BETWEEN 1 AND 5),
development_contribution VARCHAR(50),
required_level INT,
target_level INT,
created_at TIMESTAMP DEFAULT NOW()
);
-- Varianten
CREATE TABLE exercise_variants (
id SERIAL PRIMARY KEY,
exercise_id INT REFERENCES exercises(id) ON DELETE CASCADE,
variant_name VARCHAR(200) NOT NULL,
description TEXT,
execution_changes TEXT,
duration_min INT,
duration_max INT,
equipment_changes JSONB,
difficulty_adjustment VARCHAR(50),
age_group_override JSONB,
skill_focus_override JSONB,
created_at TIMESTAMP DEFAULT NOW()
);
-- Medien
CREATE TABLE exercise_media (
id SERIAL PRIMARY KEY,
exercise_id INT REFERENCES exercises(id) ON DELETE CASCADE,
media_type VARCHAR(50),
file_path TEXT,
title VARCHAR(200),
description TEXT,
sort_order INT,
is_primary BOOLEAN DEFAULT false,
context VARCHAR(100),
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_exercises_created_by ON exercises(created_by);
CREATE INDEX idx_exercises_club ON exercises(club_id);
CREATE INDEX idx_exercises_visibility ON exercises(visibility);
CREATE INDEX idx_exercise_skills_skill ON exercise_skills(skill_id);
```
### 7.5 005_training_planning.sql
```sql
-- Templates / Standards
CREATE TABLE training_templates (
id SERIAL PRIMARY KEY,
name VARCHAR(300) NOT NULL,
type VARCHAR(50),
club_id INT REFERENCES clubs(id),
division_id INT REFERENCES divisions(id),
goal TEXT,
focus_areas JSONB,
duration_total INT,
visibility VARCHAR(50) DEFAULT 'private',
status VARCHAR(50) DEFAULT 'active',
version INT DEFAULT 1,
created_by INT REFERENCES profiles(id),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Abschnitte
CREATE TABLE training_sections (
id SERIAL PRIMARY KEY,
parent_type VARCHAR(50),
parent_id INT,
title VARCHAR(200) NOT NULL,
section_type VARCHAR(100),
sort_order INT,
duration_planned INT,
goal TEXT,
notes TEXT,
is_combination BOOLEAN DEFAULT false,
combination_method_id INT REFERENCES training_methods(id),
created_at TIMESTAMP DEFAULT NOW()
);
-- Übungen in Abschnitten
CREATE TABLE section_exercises (
id SERIAL PRIMARY KEY,
section_id INT REFERENCES training_sections(id) ON DELETE CASCADE,
exercise_id INT REFERENCES exercises(id),
variant_id INT REFERENCES exercise_variants(id),
sort_order INT,
duration_planned INT,
notes TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
-- Trainingseinheiten
CREATE TABLE training_units (
id SERIAL PRIMARY KEY,
group_id INT REFERENCES training_groups(id) ON DELETE CASCADE,
date DATE NOT NULL,
time_start TIME,
time_end TIME,
derived_from_template_id INT REFERENCES training_templates(id),
derived_from_unit_id INT REFERENCES training_units(id),
title VARCHAR(300),
goal TEXT,
focus_areas JSONB,
actual_time_start TIME,
actual_time_end TIME,
completion_status VARCHAR(50),
reflection_text TEXT,
what_worked_well TEXT,
what_to_improve TEXT,
created_by INT REFERENCES profiles(id),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Programme
CREATE TABLE training_programs (
id SERIAL PRIMARY KEY,
club_id INT REFERENCES clubs(id),
division_id INT REFERENCES divisions(id),
name VARCHAR(300) NOT NULL,
description TEXT,
goal TEXT,
duration_weeks INT,
focus_areas JSONB,
visibility VARCHAR(50) DEFAULT 'private',
status VARCHAR(50) DEFAULT 'active',
created_by INT REFERENCES profiles(id),
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE program_units (
id SERIAL PRIMARY KEY,
program_id INT REFERENCES training_programs(id) ON DELETE CASCADE,
unit_order INT,
template_id INT REFERENCES training_templates(id),
week_number INT,
notes TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_units_group_date ON training_units(group_id, date);
CREATE INDEX idx_sections_parent ON training_sections(parent_type, parent_id);
```
### 7.6 006_governance.sql
```sql
-- Änderungsanfragen
CREATE TABLE content_change_requests (
id SERIAL PRIMARY KEY,
content_type VARCHAR(50),
content_id INT,
requested_by INT REFERENCES profiles(id),
change_description TEXT,
change_details JSONB,
status VARCHAR(50) DEFAULT 'pending',
reviewed_by INT REFERENCES profiles(id),
review_notes TEXT,
created_at TIMESTAMP DEFAULT NOW(),
reviewed_at TIMESTAMP
);
CREATE INDEX idx_change_requests_status ON content_change_requests(status);
```
### 7.7 007_wiki_import.sql
```sql
-- Import-Log
CREATE TABLE wiki_import_log (
id SERIAL PRIMARY KEY,
import_type VARCHAR(50),
import_status VARCHAR(50),
items_total INT,
items_imported INT,
items_failed INT,
error_log JSONB,
imported_by INT REFERENCES profiles(id),
created_at TIMESTAMP DEFAULT NOW()
);
-- Import-Referenzen
CREATE TABLE wiki_import_references (
id SERIAL PRIMARY KEY,
wiki_page_title VARCHAR(300),
wiki_page_id VARCHAR(100),
content_type VARCHAR(50),
local_id INT,
last_imported TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(wiki_page_title, content_type)
);
CREATE INDEX idx_wiki_refs_page ON wiki_import_references(wiki_page_title);
```
---
## 8. MediaWiki-Import-Strategie
### 8.1 Grundprinzip
**Einseitig, einmalig, dann Shinkan-nativ weiter**
- ✅ Import aus MediaWiki nach Shinkan
- ❌ KEINE bidirektionale Synchronisation
- ❌ KEINE Live-Kopplung
- ❌ KEINE kontinuierliche Aktualisierung
### 8.2 Import-Reihenfolge
1. **Fähigkeiten** (skills) - Basis-Katalog
2. **Methoden** (training_methods) - Methodenkatalog
3. **Übungen** (exercises) - Hauptinhalt
**Programme/Trainings:** Nur wenn Datenqualität ausreicht
### 8.3 Import-Logik
```python
# Pseudo-Code Import-Workflow
for wiki_page in wiki_pages:
# Duplikat-Check
existing = check_wiki_reference(wiki_page.title, content_type)
if existing:
log_skip(wiki_page)
continue
# Parse + Transform
data = parse_wiki_page(wiki_page)
# Validate
if not validate_minimal_fields(data):
log_error(wiki_page, "missing required fields")
continue
# Import
try:
local_id = create_content(data)
create_wiki_reference(wiki_page, local_id)
log_success(wiki_page, local_id)
except Exception as e:
log_error(wiki_page, str(e))
```
### 8.4 Import-Metadaten
Jeder importierte Inhalt erhält:
- `import_source = 'mediawiki'`
- `import_id = wiki_page_id`
- Referenz in `wiki_import_references`
- Status = `draft` (muss nachbearbeitet werden)
### 8.5 Nach-Import-Workflow
Nach Import müssen Trainer/Admins:
- Importierte Inhalte prüfen
- Unvollständige Felder ergänzen
- Fähigkeiten/Methoden zuordnen
- Status auf `approved` setzen
---
## 9. Docker-Setup (wie Mitai)
### 9.1 docker-compose.yml (Production)
```yaml
version: '3.8'
services:
postgres:
image: postgres:16-alpine
container_name: shinkan-db-prod
environment:
POSTGRES_DB: shinkan
POSTGRES_USER: shinkan_user
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- shinkan-db-data:/var/lib/postgresql/data
ports:
- "5434:5432"
restart: unless-stopped
backend:
build:
context: ./backend
dockerfile: Dockerfile
container_name: shinkan-api
environment:
DB_HOST: postgres
DB_PORT: 5432
DB_NAME: shinkan
DB_USER: shinkan_user
DB_PASSWORD: ${DB_PASSWORD}
APP_URL: https://shinkan.jinkendo.de
ALLOWED_ORIGINS: https://shinkan.jinkendo.de
volumes:
- shinkan-media:/app/media
ports:
- "8003:8000"
depends_on:
- postgres
restart: unless-stopped
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
args:
VITE_API_URL: https://shinkan.jinkendo.de
container_name: shinkan-ui
ports:
- "3003:80"
restart: unless-stopped
volumes:
shinkan-db-data:
shinkan-media:
```
### 9.2 docker-compose.dev-env.yml (Development)
```yaml
version: '3.8'
services:
postgres:
image: postgres:16-alpine
container_name: dev-shinkan-postgres
environment:
POSTGRES_DB: shinkan_dev
POSTGRES_USER: shinkan_dev
POSTGRES_PASSWORD: dev_password
volumes:
- dev-shinkan-db-data:/var/lib/postgresql/data
ports:
- "5435:5432"
restart: unless-stopped
backend:
build:
context: ./backend
dockerfile: Dockerfile
container_name: dev-shinkan-api
environment:
DB_HOST: postgres
DB_PORT: 5432
DB_NAME: shinkan_dev
DB_USER: shinkan_dev
DB_PASSWORD: dev_password
APP_URL: https://dev.shinkan.jinkendo.de
ALLOWED_ORIGINS: https://dev.shinkan.jinkendo.de
volumes:
- dev-shinkan-media:/app/media
ports:
- "8098:8000"
depends_on:
- postgres
restart: unless-stopped
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
args:
VITE_API_URL: https://dev.shinkan.jinkendo.de
container_name: dev-shinkan-ui
ports:
- "3098:80"
restart: unless-stopped
volumes:
dev-shinkan-db-data:
dev-shinkan-media:
```
---
## 10. Initiale Version
```python
# backend/version.py
APP_VERSION = "0.1.0"
BUILD_DATE = "2026-04-21"
DB_SCHEMA_VERSION = "20260421"
MODULE_VERSIONS = {
"auth": "1.0.0",
"profiles": "1.0.0",
"clubs": "0.1.0",
"groups": "0.1.0",
"skills": "0.1.0",
"methods": "0.1.0",
"exercises": "0.1.0",
"training_units": "0.1.0",
"training_programs": "0.1.0",
"planning": "0.1.0",
"import_wiki": "0.1.0",
"admin": "1.0.0",
"membership": "1.0.0",
}
CHANGELOG = [
{
"version": "0.1.0",
"date": "2026-04-21",
"changes": [
"Initial MVP Setup",
"Feature: Übungsverwaltung (Kern-Modul)",
"Feature: Fähigkeiten- und Methodenkataloge",
"Feature: Trainingsplanung für Gruppen",
"Feature: Trainingsabschnitte mit Kombinations-Flag",
"Feature: MediaWiki-Import (einseitig)",
"Feature: Freigabelogik (privat/Verein/offiziell)",
]
}
]
```
---
## 11. Umsetzungs-Reihenfolge (Empfehlung)
### Phase 1: Basis (2-3 Tage)
- Repository + Docker-Setup
- Auth + Membership von Mitai kopieren
- DB-Migrationen 001-003
- Version.py anpassen
### Phase 2: Kataloge (2 Tage)
- Skills CRUD (Admin)
- Methods CRUD (Admin)
- Frontend Admin-Pages
### Phase 3: Übungen (5-7 Tage)
- Exercises CRUD
- Exercise-Skills M:N
- Exercise-Variants
- Exercise-Media
- Suche + Filter
- Druckansicht
### Phase 4: Trainingsplanung (5-7 Tage)
- Training-Groups CRUD
- Training-Templates/Standards
- Training-Sections
- Training-Units
- Kalenderansicht
- Mobile Durchführungssicht
### Phase 5: Import (3-4 Tage)
- MediaWiki-Parser
- Import-Workflow (Skills, Methods, Exercises)
- Import-Log + Duplikat-Erkennung
### Phase 6: Governance (2-3 Tage)
- Freigabelogik
- Change-Requests (Basis)
- Eigene vs. Vereins-Inhalte
**Geschätzte Gesamtdauer MVP:** 4-5 Wochen
---
## 12. Bewusst nur vorbereitet, nicht umgesetzt (in MVP)
Diese Elemente sollen durch das Datenmodell **nicht verbaut** werden, gehören aber **nicht in MVP**:
**Reifegradmodelle:**
- Skill-Levels pro Modell
- Maturity-Stages
- Target-Descriptions pro Level
**Individuelle Sportler-Entwicklung:**
- Athlete-Profiles
- Skill-Progress-Tracking
- Assessment-History
**Erweiterte Governance:**
- Workflow-basierte Freigabe
- Review-Zyklen
- Versionierung mit Branches
**Community:**
- Shared Content-Pool
- Bewertungen
- Kommentare
**KI:**
- Trainingsplanung
- Übungssuche mit Semantik
- Automatische Programm-Generierung
---
## 13. Offene Punkte / Entscheidungsbedarf
```
🤔 MediaWiki-Parser: Welches Format nutzt das aktuelle Wiki? (Semantic MediaWiki)
🤔 Medien-Upload: Lokal oder S3/Cloud?
🤔 Suche: PostgreSQL Full-Text oder ElasticSearch später?
🤔 Offline: Service Worker + IndexedDB oder nur gute Mobile-UX?
🤔 Druckformat: PDF-Export oder nur HTML-Print?
🤔 Sparten: Schon in MVP oder erst später?
```
---
## 14. Nächste konkrete Schritte
1. **Repository erstellen** auf Gitea: `shinkan-jinkendo`
2. **Basis-Dateien kopieren** aus Mitai:
- `backend/auth.py`, `db.py`, `db_init.py`
- `frontend/src/context/`, `utils/api.js`
3. **Migrationen schreiben** (001-007)
4. **Version.py anpassen**
5. **CLAUDE.md erstellen** für Shinkan
6. **Erste Router implementieren:**
- `skills.py`
- `methods.py`
- `exercises.py`
---
**Version:** 2.0 (komplett überarbeitet)
**Stand:** 21.04.2026
**Autor:** Claude Code (basierend auf Anforderungsdokument)