mitai-jinkendo/.claude/docs/working/SHINKAN_PROJECT_SETUP.md
Lars 2453da0da1
All checks were successful
Deploy Development / deploy (push) Successful in 55s
Build Test / pytest-backend (push) Successful in 8s
Build Test / lint-backend (push) Successful in 0s
Build Test / build-frontend (push) Successful in 17s
feat: add body_history_viz widget and enhance configuration handling
- Introduced the `body_history_viz` widget to the dashboard, allowing users to visualize body history data.
- Updated widget configuration to include `body_history_viz` in the allowed widgets and added validation for its configuration.
- Enhanced the widget catalog with details for the new `body_history_viz` entry.
- Added tests to ensure proper validation of the `body_history_viz` widget configuration.
- Updated application version to reflect the addition of the new widget.
2026-04-22 07:00:24 +02:00

1203 lines
32 KiB
Markdown
Raw 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.

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