Compare commits

..

2 Commits

Author SHA1 Message Date
6c7c24e887 Add Jinkendo family design principles and entitlement model docs.
All checks were successful
Deploy Development / deploy (push) Successful in 48s
Test Suite / pytest-backend (push) Successful in 45s
Test Suite / lint-backend (push) Successful in 1s
Test Suite / build-frontend (push) Successful in 15s
Test Suite / k6 /health Baseline (push) Successful in 34s
Test Suite / playwright-tests (push) Successful in 1m35s
Document cross-app architecture patterns, Mitai alignment, and family entitlement standards. Documentation only; no runtime changes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-14 09:12:48 +02:00
3181cc126d Enhance Planning AI Context with Catalog Exercise Hints
All checks were successful
Deploy Development / deploy (push) Successful in 47s
Test Suite / pytest-backend (push) Successful in 44s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 14s
Test Suite / k6 /health Baseline (push) Successful in 35s
Test Suite / playwright-tests (push) Successful in 1m15s
- Introduced support for catalog exercise hints in various functions, including `_build_stage_ai_context`, `try_suggest_ai_stage_step`, and `build_gap_fill_goal_text`, improving the contextual information available for AI suggestions.
- Added a new function `catalog_exercise_hints_block` to consolidate hints retrieval from the catalog context.
- Updated the `PlanningIntentContext` to include catalog exercise hints, ensuring they are part of the API output.
- Implemented tests to verify the inclusion of catalog exercise hints in goal text generation and rematch logic.
- Incremented version numbers and updated changelog to reflect these enhancements.
2026-06-19 12:35:30 +02:00
31 changed files with 2867 additions and 14 deletions

View File

@ -0,0 +1,9 @@
# Designprinzipien — verschoben
Die **Jinkendo-Produktfamilie Designprinzipien** (Index + Shinkan-Serie) liegen nicht mehr hier.
**Neuer Standort (Shinkan-Serie):** [docs/jinkendo-family/design-principles/DESIGN_PRINCIPLES_INDEX.md](../../../docs/jinkendo-family/design-principles/DESIGN_PRINCIPLES_INDEX.md)
**Mitai-Serie:** [mitai-jinkendo/.claude/docs/jinkendo-foundation/design-principles/](file:///c:/Dev/mitai-jinkendo/.claude/docs/jinkendo-foundation/design-principles/README.md)
**Abgleich:** [docs/jinkendo-family/DESIGN_PRINCIPLES_ALIGNMENT.md](../../../docs/jinkendo-family/DESIGN_PRINCIPLES_ALIGNMENT.md)

View File

@ -19,6 +19,8 @@ from planning_exercise_form_context import (
prior_path_steps_before_major,
)
from planning_exercise_semantics import PlanningSemanticBrief, brief_to_summary_dict
from planning_catalog_context import ProgressionPlanningCatalogContext
from planning_prompt_variables import catalog_exercise_hints_block
_logger = logging.getLogger("shinkan.planning_exercise_path_ai_fill")
@ -54,6 +56,7 @@ def _build_stage_ai_context(
step_after: Optional[Mapping[str, Any]] = None,
prior_steps: Optional[Sequence[Mapping[str, Any]]] = None,
start_situation: Optional[str] = None,
catalog_exercise_hints: Optional[str] = None,
) -> ExerciseFormAiPromptContext:
"""KI-Kontext für unbesetzte Roadmap-Stufe (keine Brücke zwischen falschen Array-Indizes)."""
gap = dict(spec.get("gap") or {})
@ -97,6 +100,9 @@ def _build_stage_ai_context(
sketch = (spec.get("sketch") or "").strip()
if sketch and sketch != learning_goal:
goal_parts.extend(["", f"Kontext: {sketch}"])
hints = (catalog_exercise_hints or "").strip()
if hints:
goal_parts.extend(["", "Katalog-Hinweise Übungsanlage:", hints])
goal = "\n".join(goal_parts)
focus_hint = topic if brief.topic_type == "technique" else None
@ -118,6 +124,7 @@ def try_suggest_ai_stage_step(
brief: PlanningSemanticBrief,
spec: Mapping[str, Any],
steps: Sequence[Mapping[str, Any]],
catalog: Optional[ProgressionPlanningCatalogContext] = None,
) -> Optional[Dict[str, Any]]:
"""KI-Vorschlag für leere Roadmap-Stufe."""
major_idx = spec.get("roadmap_major_step_index")
@ -136,6 +143,8 @@ def try_suggest_ai_stage_step(
if not gap.get("learning_goal"):
gap["learning_goal"] = spec.get("title_hint") or spec.get("sketch")
exercise_hints = catalog_exercise_hints_block(cur, catalog) if catalog else ""
ctx = _build_stage_ai_context(
goal_query=goal_query,
brief=brief,
@ -143,6 +152,7 @@ def try_suggest_ai_stage_step(
step_before=step_before,
step_after=step_after,
prior_steps=prior_steps,
catalog_exercise_hints=exercise_hints or None,
)
try:
ai_payload = run_exercise_form_ai_suggestion(cur, ctx=ctx)
@ -189,6 +199,7 @@ def _build_gap_ai_context(
gap: Mapping[str, Any],
title_hint: Optional[str] = None,
sketch_hint: Optional[str] = None,
catalog_exercise_hints: Optional[str] = None,
) -> ExerciseFormAiPromptContext:
topic = (brief.primary_topic or "Technik").strip()
phase = gap.get("expected_phase") or "vertiefung"
@ -206,6 +217,9 @@ def _build_gap_ai_context(
]
if sketch:
goal_parts.extend(["", f"Hinweis: {sketch}"])
hints = (catalog_exercise_hints or "").strip()
if hints:
goal_parts.extend(["", "Katalog-Hinweise Übungsanlage:", hints])
goal = "\n".join(goal_parts)
focus_hint = topic if brief.topic_type == "technique" else None
@ -271,8 +285,10 @@ def try_suggest_ai_bridge_step(
gap: Mapping[str, Any],
title_hint: Optional[str] = None,
sketch_hint: Optional[str] = None,
catalog: Optional[ProgressionPlanningCatalogContext] = None,
) -> Optional[Dict[str, Any]]:
"""Ruft exercise AI suggest auf — kein Speichern in DB."""
exercise_hints = catalog_exercise_hints_block(cur, catalog) if catalog else ""
ctx = _build_gap_ai_context(
goal_query=goal_query,
brief=brief,
@ -281,6 +297,7 @@ def try_suggest_ai_bridge_step(
gap=gap,
title_hint=title_hint,
sketch_hint=sketch_hint,
catalog_exercise_hints=exercise_hints or None,
)
g_plain = strip_html_to_plain(ctx.goal)
if not g_plain.strip() and not (ctx.title or "").strip():
@ -478,6 +495,7 @@ def build_gap_fill_goal_text(
step_a: Optional[Mapping[str, Any]] = None,
step_b: Optional[Mapping[str, Any]] = None,
roadmap_snapshot: Optional[Mapping[str, Any]] = None,
catalog_exercise_hints: Optional[str] = None,
) -> str:
"""Ausführlicher Zieltext für KI-Neuanlage aus Pfad-, Roadmap- und Stufen-Kontext."""
topic = (brief.primary_topic or "Technik").strip()
@ -555,6 +573,9 @@ def build_gap_fill_goal_text(
parts.append(f"Qualitätsprüfung: {spec['rationale']}")
if spec.get("sketch"):
parts.append(f"Skizze: {spec['sketch']}")
hints = (catalog_exercise_hints or "").strip()
if hints:
parts.append(f"Katalog-Hinweise Übungsanlage:\n{hints}")
parts.append(
"Die Übung muss die Stufe didaktisch erfüllen: klare Voraussetzungen, messbares Stufenziel, "
"Bezug zum Gesamtpfad — keine generische Kraftübung ohne Technikbezug. "
@ -571,6 +592,7 @@ def build_gap_fill_offer(
brief: Optional[PlanningSemanticBrief] = None,
proposal: Optional[Mapping[str, Any]] = None,
roadmap_snapshot: Optional[Mapping[str, Any]] = None,
catalog_exercise_hints: Optional[str] = None,
) -> Dict[str, Any]:
source = spec.get("source")
idx = int(spec.get("insert_after_index") or 0)
@ -603,6 +625,7 @@ def build_gap_fill_offer(
step_a=step_a,
step_b=step_b,
roadmap_snapshot=enriched_snapshot or None,
catalog_exercise_hints=catalog_exercise_hints,
)
ctx_preview = enriched_snapshot or None
offer: Dict[str, Any] = {
@ -642,6 +665,7 @@ def apply_gap_fill_after_qa(
max_ai_proposals: int = 3,
auto_insert_proposals: bool = False,
roadmap_snapshot: Optional[Mapping[str, Any]] = None,
catalog: Optional[ProgressionPlanningCatalogContext] = None,
) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]], List[Dict[str, Any]]]:
"""
Erzeugt gap_fill_offers für die UI; optional KI-Vorschläge einfügen.
@ -653,6 +677,7 @@ def apply_gap_fill_after_qa(
out = list(steps)
proposals: List[Dict[str, Any]] = []
offers: List[Dict[str, Any]] = []
exercise_hints = catalog_exercise_hints_block(cur, catalog) if catalog else ""
for spec in specs:
source = spec.get("source")
@ -666,6 +691,7 @@ def apply_gap_fill_after_qa(
brief=brief,
spec=spec,
steps=out,
catalog=catalog,
)
offer = build_gap_fill_offer(
spec=spec,
@ -674,6 +700,7 @@ def apply_gap_fill_after_qa(
brief=brief,
proposal=proposal,
roadmap_snapshot=roadmap_snapshot,
catalog_exercise_hints=exercise_hints or None,
)
offers.append(offer)
if proposal and auto_insert_proposals:
@ -700,6 +727,7 @@ def apply_gap_fill_after_qa(
brief=brief,
proposal=None,
roadmap_snapshot=roadmap_snapshot,
catalog_exercise_hints=exercise_hints or None,
)
offers.append(offer)
continue
@ -719,6 +747,7 @@ def apply_gap_fill_after_qa(
gap=gap,
title_hint=str(spec.get("title_hint") or ""),
sketch_hint=str(spec.get("sketch") or ""),
catalog=catalog,
)
offer = build_gap_fill_offer(
@ -728,6 +757,7 @@ def apply_gap_fill_after_qa(
brief=brief,
proposal=proposal,
roadmap_snapshot=roadmap_snapshot,
catalog_exercise_hints=exercise_hints or None,
)
offers.append(offer)

View File

@ -24,9 +24,11 @@ from planning_catalog_context import (
load_catalog_context_from_graph_row,
merge_catalog_context_into_target,
)
from catalog_prompt_slots import get_rematch_guard_for_catalog
from planning_exercise_profiles import PlanningTargetProfile
from planning_path_qa_pipeline import run_multistage_path_qa
from planning_path_rematch import (
apply_rematch_catalog_guard,
collect_rematch_slot_indices,
filter_rematch_slot_indices,
prune_stripped_after_rematch,
@ -1737,6 +1739,13 @@ def _run_roadmap_rematch_loop(
stripped_off_topic=current_stripped if round_idx == 0 else [],
off_topic_steps=off_topic_before_strip if round_idx == 0 and use_initial_off_topic else [],
)
catalog_context = _resolve_planning_catalog_context(cur, body)
rematch_guard = get_rematch_guard_for_catalog(cur, catalog_context)
slot_indices = apply_rematch_catalog_guard(
slot_indices,
rematch_reasons,
rematch_guard=rematch_guard,
)
if not slot_indices:
break
@ -2191,6 +2200,7 @@ def _run_evaluate_only_path_qa(
max_ai_proposals=0,
auto_insert_proposals=False,
roadmap_snapshot=path_roadmap_snapshot,
catalog=catalog_context,
)
multistage_qa = run_multistage_path_qa(
@ -4294,6 +4304,7 @@ def suggest_progression_path(
max_ai_proposals=0,
auto_insert_proposals=False,
roadmap_snapshot=path_roadmap_snapshot,
catalog=catalog_context,
)
if roadmap_gap_offers:

View File

@ -49,9 +49,10 @@ class PlanningIntentContext:
context_notes: str = ""
topic_type: str = "general"
technique_sibling_excludes: List[str] = field(default_factory=list)
catalog_exercise_hints: Optional[str] = None
def to_api_dict(self) -> Dict[str, Any]:
return {
out = {
"source_query": self.source_query,
"primary_topic": self.primary_topic,
"topic_type": self.topic_type,
@ -61,6 +62,10 @@ class PlanningIntentContext:
"technique_sibling_excludes": self.technique_sibling_excludes[:16],
"context_notes": self.context_notes[:1200] or None,
}
hints = (self.catalog_exercise_hints or "").strip()
if hints:
out["catalog_exercise_hints"] = hints[:2000]
return out
def build_planning_intent_context(
@ -70,6 +75,8 @@ def build_planning_intent_context(
goal_analysis: Optional[Mapping[str, Any]] = None,
extra_context: Optional[str] = None,
primary_topic: Optional[str] = None,
cur=None,
catalog=None,
) -> PlanningIntentContext:
"""Intent aus Anfrage, Zielanalyse und optionalem Kontext — ohne Sonderregeln pro Thema."""
ga = dict(goal_analysis or {})
@ -124,6 +131,12 @@ def build_planning_intent_context(
if line not in path_success:
path_success.insert(0, line)
catalog_hints = ""
if cur is not None and catalog is not None:
from planning_prompt_variables import catalog_exercise_hints_block
catalog_hints = catalog_exercise_hints_block(cur, catalog)
return PlanningIntentContext(
source_query=(goal_query or "").strip(),
primary_topic=topic,
@ -133,6 +146,7 @@ def build_planning_intent_context(
explicit_exclusions=explicit,
technique_sibling_excludes=siblings[:16],
context_notes=combined_notes[:1200],
catalog_exercise_hints=catalog_hints or None,
)

View File

@ -7,6 +7,8 @@ from typing import Any, Dict, List, Mapping, Optional, Sequence, Set, Tuple
from planning_progression_roadmap import ProgressionRoadmapContext, StageSpecArtifact
_UNFILLED_REMATCH_REASON = "Keine passende Übung für Roadmap-Stufe"
def _slot_priority_for_rematch(
body,
@ -103,7 +105,7 @@ def collect_rematch_slot_indices(
if isinstance(item, (list, tuple)) and len(item) >= 2:
idx, spec = item[0], item[1]
midx = getattr(spec, "major_step_index", idx)
_register(int(midx), "Keine passende Übung für Roadmap-Stufe")
_register(int(midx), _UNFILLED_REMATCH_REASON)
elif isinstance(item, dict):
midx = _resolve_major(item)
if midx is not None:
@ -114,6 +116,25 @@ def collect_rematch_slot_indices(
return indices, reasons
def apply_rematch_catalog_guard(
slot_indices: Set[int],
rematch_reasons: Mapping[int, str],
*,
rematch_guard: Optional[str],
) -> Set[int]:
"""
Bei gesetztem rematch_guard (Katalog-Slot): kein Auto-Rematch nur wegen leerer Roadmap-Stufe.
Off-Topic, explizite QS-Hinweise und Stufen-Verfeinerung bleiben aktiv.
"""
if not (rematch_guard or "").strip():
return set(slot_indices)
return {
idx
for idx in slot_indices
if str(rematch_reasons.get(idx) or "").strip() != _UNFILLED_REMATCH_REASON
}
def filter_rematch_slot_indices(
steps: Sequence[Mapping[str, Any]],
slot_indices: Set[int],
@ -372,6 +393,7 @@ def prune_stripped_after_rematch(
__all__ = [
"apply_rematch_catalog_guard",
"collect_rematch_slot_indices",
"filter_rematch_slot_indices",
"prune_stripped_after_rematch",

View File

@ -1244,6 +1244,8 @@ def run_progression_roadmap_pipeline(
resolved.target_state,
),
primary_topic=goal_analysis.primary_topic,
cur=cur,
catalog=catalog,
)
heuristic_specs = build_stage_specs(

View File

@ -34,6 +34,27 @@ _PLANNING_PROMPT_VARIABLE_PROVIDERS: tuple[PlanningPromptVariableProvider, ...]
)
def catalog_exercise_hints_block(
cur,
catalog: Optional[ProgressionPlanningCatalogContext] = None,
*,
slug: Optional[str] = None,
) -> str:
"""Kombinierte hints_on_exercise aus aktivem Katalog-Kontext (Gap-Fill / Intent)."""
if cur is None or catalog is None:
return ""
from catalog_prompt_slots import CATALOG_KINDS, placeholder_key
merged = merge_planning_prompt_variables(cur, {}, catalog=catalog, slug=slug)
lines: list[str] = []
for cfg in CATALOG_KINDS:
key = placeholder_key(cfg.kind, "hints_on_exercise")
text = (merged.get(key) or "").strip()
if text:
lines.append(f"{cfg.label_de}: {text}")
return "\n".join(lines)
def merge_planning_prompt_variables(
cur,
base_variables: Mapping[str, str],
@ -113,6 +134,7 @@ def planning_prompt_placeholder_catalog() -> dict:
__all__ = [
"catalog_exercise_hints_block",
"merge_planning_prompt_variables",
"planning_prompt_placeholder_catalog",
]

View File

@ -83,6 +83,20 @@ def test_strip_off_topic_steps_from_path():
assert [s["exercise_id"] for s in out] == [1, 2, 4]
def test_build_gap_fill_goal_text_includes_catalog_exercise_hints():
from planning_exercise_semantics import build_semantic_brief
brief = build_semantic_brief("Mae Geri")
text = build_gap_fill_goal_text(
goal_query="Mae Geri lernen",
brief=brief,
spec={"source": "roadmap_unfilled", "phase": "grundlage", "title_hint": "Stand"},
catalog_exercise_hints="Primärfokus: Kihon und Partnerübungen mit Technikbezug.",
)
assert "Katalog-Hinweise Übungsanlage" in text
assert "Kihon" in text
def test_build_gap_fill_goal_text_includes_topic():
brief = build_semantic_brief("Mae Geri Perfektion")
text = build_gap_fill_goal_text(

View File

@ -336,3 +336,29 @@ def test_filter_rematch_skips_preserved_slots():
off_topic_steps=[],
)
assert filtered == {1}
def test_apply_rematch_catalog_guard_skips_unfilled_only():
from planning_path_rematch import apply_rematch_catalog_guard
indices = {0, 1, 2}
reasons = {
0: "QS-Tier-1",
1: "Keine passende Übung für Roadmap-Stufe",
2: "Passt nicht zur Haupttechnik",
}
filtered = apply_rematch_catalog_guard(
indices,
reasons,
rematch_guard="Keine leeren Slots erzwingen.",
)
assert filtered == {0, 2}
def test_apply_rematch_catalog_guard_inactive_without_guard():
from planning_path_rematch import apply_rematch_catalog_guard
indices = {1}
reasons = {1: "Keine passende Übung für Roadmap-Stufe"}
assert apply_rematch_catalog_guard(indices, reasons, rematch_guard=None) == {1}
assert apply_rematch_catalog_guard(indices, reasons, rematch_guard="") == {1}

View File

@ -1,8 +1,8 @@
# Shinkan Jinkendo Version Information
APP_VERSION = "0.8.237"
APP_VERSION = "0.8.238"
BUILD_DATE = "2026-05-22"
DB_SCHEMA_VERSION = "20260607094"
DB_SCHEMA_VERSION = "20260607095"
MODULE_VERSIONS = {
"legal_documents": "1.4.0", # Admin: Live-Vorschau pro Abschnitt + modale Vollvorschau (Editor + Dokumentenliste)
@ -53,11 +53,20 @@ MODULE_VERSIONS = {
}
CHANGELOG = [
{
"version": "0.8.238",
"date": "2026-05-22",
"changes": [
"Planungs-KI H1.5: rematch_guard im Auto-Rematch (kein Rematch nur wegen leerer Roadmap-Stufe).",
"hints_on_exercise in Gap-Fill, Übungs-KI-Kontext und intent_context_json (Roadmap-Pipeline).",
"Migration 095: keine Migrations-Seeds in catalog_prompt_slots (Prod-sichere Katalogstruktur).",
],
},
{
"version": "0.8.237",
"date": "2026-05-22",
"changes": [
"Migration 094: catalog_prompt_slots vollständig befüllt (Karate, SV, alle Trainingsstile/Zielgruppen).",
"Migration 094/095: Katalog-Prompt-Slots ohne Migrations-Seeds — Inhalte Admin oder Laufzeit-Fallback.",
"catalog_slot_fallbacks: Namens-Fallback bis Admin-Override — gleiche Qualität wie H1-Registry.",
],
},

View File

@ -1,7 +1,7 @@
# Shinkan Jinkendo Entwicklungsstand & Handover
**Stand:** 2026-05-22 (F15 Graph-Match & getrennte Pfad-QS, lokal nach **0.8.233**)
**App-Version / DB-Schema:** App **`0.8.233`** (Planungs-KI F11F14, Katalog-Kontext); **F15** siehe §2.8 — DB unverändert (`DB_SCHEMA_VERSION`, Migration **088**).
**Stand:** 2026-05-22 (Katalog-Prompt-Slots H2/H1.5, **0.8.238**)
**App-Version / DB-Schema:** App **`0.8.238`**; DB Migration **095** (keine Slot-Seeds; Prod-sichere Katalogstruktur).
Diese Datei ist die **Einstiegs-Doku für neue Chat-Sessions**: Anforderungen im Detail stehen in `.claude/docs/` (siehe unten); hier der **implementierte Stand**, **Medien-Meilenstein** und **sinnvolle nächste Schritte**.
@ -115,7 +115,8 @@ Das Schema ist gegenüber dem Code zurück: Migration **`022_skills_schema_compl
| **F13** | **`planning_catalog_context`** (Fokus/Stil/TT/ZG) im Match + Graph-Artefakt | ✅ **0.8.233** |
| **F14** | **`ProgressionGraphEditor`** — Slot-UI + Planungskontext-Dropdowns | ✅ **0.8.233** |
| **F15** | Unified Slot-Review (Match-Dialog), getrennte Pfad-QS, `findings_stale` | ✅ lokal (nach 0.8.233) |
| **H1** | Katalog-Prompt-Snippets (modulare LLM-Anweisungen) | 🔲 Spec **`docs/architecture/PLANNING_CATALOG_PROMPT_SNIPPETS.md`** |
| **H1H2.1** | Katalog-Prompt-Slots (DB, Resolver, Admin-UI, granulare Prompts) | ✅ **0.8.234238** — Spec **`docs/architecture/PLANNING_CATALOG_PROMPT_SNIPPETS.md`** |
| **H1.5** | `rematch_guard`, `hints_on_exercise` in Rematch/Gap-Fill/Intent | ✅ **0.8.238** |
**Architektur (verbindlich):** Drei Schichten — (1) **Katalog-Dimensionen** (DB, jetzt im Match verdrahtet; **H1:** zusätzlich Prompt-Snippets), (2) **Technik-Disambiguierung** (Code, nur bei `topic_type=technique`), (3) **Didaktik** (Roadmap + LLM-QS, nicht im Vokabular). Progressionsgraph = **Roadmap-first**, **keine Gruppenanalyse**. Bestehender Graph = **leichter Nachfolger-Bias** ab Schritt 2. Trainingsplanung = **eigene Pipeline** (Phase G) — Wiederverwendung der Bausteine, siehe Ist-Doku §16.
@ -148,7 +149,7 @@ Das Schema ist gegenüber dem Code zurück: Migration **`022_skills_schema_compl
5. Phase D — Auto KI-Gap-Fill bei persistent leeren Slots
6. **Trainingsplanung Phase G** — Gruppenkontext-Pack, Scopes `training_section` / `framework_slot` (Ist-Doku §16)
7. Technik-Katalog konfigurierbar (Backlog)
8. **H1** — Katalog-Prompt-Snippets (modulare LLM-Anweisungen)
8. **H1H2.1** — Katalog-Prompt-Slots ✅ · **Prompt-Editor-Überarbeitung** → eigene Session
#### Übungs-KI Formular / Schnellanlage (Stand **0.8.171**)

View File

@ -1,7 +1,7 @@
# Planungs-KI — Katalog-Prompt-Slots (Snippets)
**Stand:** 2026-05-22
**Status:** **H2** umgesetzt (0.8.235) · **H2.1** Admin-UI + granulare Prompts (0.8.236)
**Status:** **H2.1** umgesetzt (0.8.236) · **H1.5** Rematch-Guard + Gap-Fill-Hints (0.8.238) · **Prompt-Editor-Überarbeitung** bewusst ausgelagert
**Bezüge:** `PLANNING_PROGRESSION_GRAPH_KI.md` §4.4 · `AI_PROMPT_TARGET_ARCHITECTURE.md` §2.4 · `planning_catalog_context.py` · `catalog_prompt_slots.py`
---
@ -173,12 +173,12 @@ Hardcodierte `SNIPPET_REGISTRY` — Proof of Concept für `catalog_guidance_bloc
- [x] Slot-Editor an Fokusbereich / Trainingsstil / Zielgruppe / Stilrichtung (`CatalogPromptSlotsEditor`, Stammdaten-Katalog)
- [x] Prompt-Templates mit granularen Platzhaltern (Migration 093)
- [ ] Platzhalter-Hilfe im KI-Prompt-Editor (erweitert)
- [ ] **Prompt-Editor komplett überarbeiten** (Platzhalter-Hilfe, UX) — **eigene Session**
### H1.5
### H1.5 ✓ (0.8.238)
- [ ] `rematch_guard` im Rematch-Loop
- [ ] Intent-Prompts + Gap-Fill: `hints_on_exercise`
- [x] `rematch_guard` im Rematch-Loop (`apply_rematch_catalog_guard`)
- [x] Gap-Fill + Intent: `hints_on_exercise` via `catalog_exercise_hints_block` / `intent_context_json`
### H3 — Trainingsplanung (Phase G)
@ -211,6 +211,7 @@ Hardcodierte `SNIPPET_REGISTRY` — Proof of Concept für `catalog_guidance_bloc
| Datum | Änderung |
|-------|----------|
| 2026-05-22 | **H1.5** (0.8.238): rematch_guard; hints_on_exercise in Gap-Fill/Intent; Migration 095 ohne Seeds |
| 2026-05-22 | **H2.1** (0.8.236): Admin-UI `CatalogPromptSlotsEditor`; Migration 093 granulare Prompt-Templates |
| 2026-05-22 | **H2** (0.8.235): Slot-Typ-Register + `catalog_prompt_slots` DB, granulare Platzhalter, Admin-API |
| 2026-05-22 | Konzept §4§8: zwei Ebenen Slot-Typ vs. Slot-Wert; Platzhalter `{kind}_{slot_key}` |

View File

@ -0,0 +1,358 @@
# Designprinzipien Abgleich Mitai ↔ Shinkan
**Status:** Review / Entscheidungsgrundlage
**Stand:** 2026-07-04
**Zweck:** Widersprüche, bewusste Abweichungen und Implementierungslücken zwischen den Designprinzipien-Serien identifizieren — Basis für **Familien-Entscheidungen** und langfristige Konvergenz von Mitai und Shinkan.
**Quellen:**
| App | Index |
|-----|--------|
| Mitai (Foundation) | [mitai-jinkendo/.claude/docs/jinkendo-foundation/design-principles/README.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/jinkendo-foundation/design-principles/README.md) — 9 Module |
| Shinkan | [design-principles/DESIGN_PRINCIPLES_INDEX.md](./design-principles/DESIGN_PRINCIPLES_INDEX.md) — 15 Module |
---
## 1. Kurzfassung
| Kategorie | Anzahl | Bedeutung |
|-----------|--------|-----------|
| **Familien-Konsens** | 12 Muster | In beiden Serien gleich oder kompatibel — **verbindlich für neue Apps** |
| **Bewusste Produkt-Abweichung** | 8 | Fachlich/Architektur begründet — **nicht angleichen**, aber im Familienmodell verankern |
| **Konzeptuelle Spannung** | 6 | Widersprüche oder gegenläufige Defaults — **Familien-Entscheidung nötig** |
| **Ist vs. Prinzip (Schuld)** | 14+ | Mindestens eine App verletzt eigene oder Schwester-Prinzipien — **Remediation** |
| **Nur Shinkan** | 6 Module | Mandanten-/Domänen-Bausteine ohne Mitai-Pendant |
| **Nur Mitai (reifer)** | 3 Muster | Data Layer, Widget-Dashboard, Universal Import — Shinkan vereinfacht oder fehlt |
**Kernbefund:** Mitai und Shinkan teilen dieselbe **technische Basis** (Auth, Migration, Nav-SSoT, Registry-Denken, Probe→Enforce), divergieren aber strukturell bei **Entitlement-Subjekt** (Profil vs. Verein), **Berechnungsarchitektur** (generischer Data Layer vs. domänenspezifisches Scoring) und **KI-Reife** (Unified Executor vs. schmale Laufzeit).
---
## 2. Familien-Konsens (für neue Produkte übernehmen)
Diese Muster sind in beiden Serien explizit oder implizit tragfähig:
| # | Muster | Mitai | Shinkan |
|---|--------|-------|---------|
| F1 | Server-Sessions + `Depends(require_auth)` | Auth #13 | Auth #12 |
| F2 | `profile_id` aus Session, nie aus Client-Header | Auth #3 | Auth #3 |
| F3 | Auth getrennt von Authorization/Entitlements | Auth #10 | Capabilities + Access Layer |
| F4 | Nummerierte SQL-Migrationen + Tracking beim Container-Start | Migration #15 | Migration #13 |
| F5 | Fail-fast, kein Auto-Rollback | Migration #5 | Migration #2 |
| F6 | `appNav` / zentrale Nav-Config als SSoT | Navigation #1 | Navigation #1 |
| F7 | Admin als eigener Hub/Realm | Navigation #67 | Navigation #2 |
| F8 | DB-konfigurierbare KI-Prompts (nicht hardcoded Prod) | Prompt #2 | AI Runtime #2 |
| F9 | Template vs. Kontext/Daten trennen | Prompt #5 | AI Runtime #4 |
| F10 | Ingest ≠ Interpretation beim Import | Import #2 | Wiki Import #1 |
| F11 | Preview/Dry-Run vor Massenimport | Import #3+ | Wiki Import #2 |
| F12 | 4-Phasen-Rollout Entitlements (Log → Enforce) | Feature #8 | Capability #2 |
**Empfehlung:** Als **`JINKENDO_FOUNDATION_CHECKLIST`** in künftigen Apps verpflichtend; Details pro Modul in den Einzeldokumenten.
---
## 3. Modul-Abgleich (9 vergleichbare Paare)
Legende **Bewertung:**
| Symbol | Bedeutung |
|--------|-----------|
| ✅ | Prinzipien aligned / kompatibel |
| ⚠️ | Teilweise aligned; Lücken in Implementierung oder Doku |
| 🔀 | Bewusste Produkt-Divergenz (kein Bug) |
| ❌ | Widerspruch oder gegenläufiges Konzept — Entscheidung nötig |
| 🏗️ | Ist-Stand verletzt dokumentierte Prinzipien (Architekturschuld) |
---
### 3.1 Prompt Engine (Mitai #1) ↔ AI Prompt Runtime (Shinkan #5)
| Aspekt | Mitai | Shinkan | Bewertung |
|--------|-------|---------|-----------|
| Single Entry Point | `execute_prompt` / Unified System | `ai_prompt_runtime` + verteilte Orchestratoren | ❌ Konzept |
| Prompt-Typen | base / pipeline / workflow | nur slug + Mustache | 🔀 Shinkan bewusst schlanker |
| Platzhalter-Registry | zentral, API-Verträge | Kontext-Arten (`AiPromptContextKind`), kein Registry-Katalog | ⚠️ |
| Data Layer-Anbindung | Layer 1 → Resolver | Domänen-Builder ad hoc | ⚠️ |
| Debug/Preview | ausgereift | Admin-Vorschau, weniger Runtime-Transparenz | ⚠️ |
| Feature-Gating an Execute | teils fehlend (Legacy) | Capability geplant, teils Probe | 🏗️ beide |
**Widersprüche / gegenläufig:**
- Mitai: **Ein Executor** ist Kernprinzip. Shinkan: **kein** vergleichbarer Executor — Planungs-KI umgeht teils die Laufzeit.
- Beide warnen vor **parallelen KI-Pfaden**; beide haben sie noch (Mitai `insights.py`, Shinkan Router-OpenRouter).
**Familien-Entscheidung (Vorschlag):**
| Option | Inhalt |
|--------|--------|
| **Zielbild** | Gemeinsame **`prompt_executor`-Fassade** (Package oder Copy mit Namespace); Shinkan-Kontext-Builder als Plugins |
| **Shinkan-Roadmap** | Planungs-Orchestrierung in Laufzeit ziehen; keine Workflow-Graphs vor Planungs-Kontext-Reife |
| **Nicht kopieren** | Mitai: doppelte Pipeline-Modelle, PLACEHOLDER_MAP-Duplikat, Roh-SQL im Executor |
---
### 3.2 Data Layer (Mitai #2) ↔ Skill Scoring (Shinkan #8)
| Aspekt | Mitai | Shinkan | Bewertung |
|--------|-------|---------|-----------|
| Berechnungs-SSoT | `data_layer/` Layer 0→1→2 | nur `skill_scoring.py` | ❌ Abdeckung |
| Router delegieren | explizites Prinzip #13 | Skill-Router ja; Planung teils nicht | ⚠️ |
| Confidence / data_points | Pflicht-Metadaten | nicht analog | 🔀 Domäne anders |
| Chart/KPI-Anbindung | Layer 2b Adapter | KPI-Dashboard ruft Router-Helfer | ⚠️ |
| Import-Grenze | keine Scores beim Insert | Wiki: explizit kein Scoring beim Insert | ✅ |
**Widerspruch:**
- Mitai postuliert **generische Berechnungsschicht** für die ganze App. Shinkan hat **kein** Data Layer — nur ein **domänenspezifisches** Scoring-Modul. Das ist keine Implementierungslücke allein, sondern **unterschiedliche Architektur-Tiefe**.
**Familien-Entscheidung (Vorschlag):**
| Option | Inhalt |
|--------|--------|
| **Familien-Prinzip** | „Berechnungen in benannter Schicht, nicht in Router/React“ — **Ja** |
| **Implementierung** | Mitai: `data_layer/` bleibt Referenz. Shinkan: Skill Scoring **ist** Layer-1-Vorbild; langfristig **`planning_metrics/`** o. ä. statt Router-SQL |
| **Nicht verallgemeinern** | Mitai-Formeln (TDEE, WHR) — nur Schichtenmodell übernehmen |
---
### 3.3 Feature & Entitlement (Mitai #3) ↔ Capability & Club Features (Shinkan #2)
| Aspekt | Mitai | Shinkan | Bewertung |
|--------|-------|---------|-----------|
| Subjekt | **Profil** + Tier | **Verein** (`club_id`) + Plan | ❌ Scope |
| Auflösungs-API | `check_feature_access` | `check_capability` + `club_features` + `/me/entitlements` | 🔀 |
| Rollout 4 Phasen | ja | ja (Env-Flags) | ✅ |
| Registry | DB `features` + Tiers | Code-Registry → DB Sync | ⚠️ |
| Capabilities vs. Features | Features only | Capabilities **und** Kontingente getrennt | 🔀 Shinkan feiner |
| Widget/Layout-Gating | zentral | Entitlements-API, kein Widget-Layout | ⚠️ |
**Größter Familien-Konflikt:**
Mitai-Dokument #3 „Nicht übernehmen“ Punkt 10: *„Profile as Entitlement-Subject — Multi-App-Familie braucht separates Identity/Subscription-Boundary.“*
Shinkan **ist** die Antwort mit Verein als Subjekt — aber es gibt **kein gemeinsames Familienmodell**, das Profil-Tier **und** Org-Limits kombiniert.
**Familien-Entscheidung (Vorschlag):**
```
Entitlement-Subjekt (familie):
├── account (profile_id) → Tier, persönliche Limits (Mitai)
└── tenant (club_id?) → Org-Plan, Capabilities (Shinkan, optional null)
API: GET /me/entitlements?tenant_id=
Enforcement: eine resolve_entitlement(subject, capability|feature)
```
| App | Remediation |
|-----|-------------|
| Mitai | Org-Scope reservieren; Tier-Drift (#3 Schuld) bereinigen |
| Shinkan | `CLUB_FEATURE_ENFORCE=1` produktiv; Mitai-Legacy `check_feature_access` nicht nutzen (bereits Regel) |
---
### 3.4 Registry / Plugin (Mitai #4) ↔ Rights Registry (Shinkan #3)
| Aspekt | Mitai | Shinkan | Bewertung |
|--------|-------|---------|-----------|
| Registry-first | Platzhalter, Widgets, CSV-Module | Capabilities + Features only | ⚠️ Abdeckung |
| Validierung an Grenze | ja | ja (`register_*` wirft) | ✅ |
| Runtime + DB | Dual (Katalog + DB-Overrides) | Code → DB Upsert | ✅ |
| Dual Registry FE/BE | Widgets + `registerDashboardWidgets` | nicht vorhanden | 🔀 |
| Metadaten-Tiefe | nach Risiko (Matrix in Doc) | schlankere Dataclasses | ✅ |
**Kein Widerspruch** — Shinkan Rights Registry ist **Teilmenge** des Mitai-Meta-Musters.
**Familien-Entscheidung:** Mitai-Registry-Matrix (Platzhalter / UI-Plugin / Import-Modul / Rechte) als **Familien-Taxonomie**; Shinkan erweitert um Import-/Prompt-Registry wenn Wiki-Import generisch wird.
---
### 3.5 Auth & Session (Mitai #5 ↔ Shinkan #4)
| Aspekt | Mitai | Shinkan | Bewertung |
|--------|-------|---------|-----------|
| Session-Modell | opaque token | gleich (shared `auth.py`) | ✅ |
| Depends-Pattern | ja | ja (+ TenantContext) | ✅ |
| IDOR Profile-Header | dokumentierte Schwäche | Shinkan: Session-only betont | ⚠️ prüfen |
| RBAC | `role` admin/user | Portal-Rolle **+** Vereinsrollen | 🔀 |
| Rate Limiting | ja | (Mitai-spezifisch in Router) | ⚠️ |
| Feature-Flags in Session | Legacy-Spalten | Account-Lifecycle separat | 🏗️ Mitai |
**Gegenläufig:** Shinkan **erweitert** Auth um Mandanten — darf Mandantenlogik **nicht** in `auth.py` legen (Shinkan-Prinzip „Nicht übernehmen“).
**Familien-Entscheidung:** Gemeinsames Auth-Modul; **TenantContext** als optionales Add-on-Pattern für mandantenfähige Apps.
---
### 3.6 Universal Import (Mitai #6) ↔ Wiki Import (Shinkan #11)
| Aspekt | Mitai | Shinkan | Bewertung |
|--------|-------|---------|-----------|
| Ingest ≠ Interpretation | ✅ | ✅ | ✅ |
| Modul-Registry | zentral | fehlt (wiki-hardcoded) | ⚠️ |
| SAVEPOINT pro Zeile | ja | nicht dokumentiert | ⚠️ |
| Vorlagen/Mappings | generisch | SMW-Kategorien via Env | 🔀 |
| Feature-Limits | an Import gebunden | Admin-only | ⚠️ |
**Kein Konflikt** — unterschiedliche Reife. Shinkan ist **Spezialfall** des Mitai-Musters.
**Familien-Entscheidung:** Neue Import-Quellen über **Universal-Import-Gerüst** (Mitai); Wiki als `import_type=mediawiki` registrieren.
---
### 3.7 Dashboard Widgets (Mitai #7) ↔ Dashboard KPIs (Shinkan #14)
| Aspekt | Mitai | Shinkan | Bewertung |
|--------|-------|---------|-----------|
| UX-Modell | konfigurierbares Widget-Layout | festes KPI-Aggregat | ❌ UX-Konzept |
| Chatty Client vermeiden | via Widget-Daten | via `/dashboard/kpis` | ✅ Ziel |
| Entitlements | `allowed` pro Widget | TenantContext auf KPIs | ✅ |
| Data Layer | Widgets konsumieren Layer 1 | intern Router-Helfer | ⚠️ |
**Gegenläufig:** Mitai: **Nutzer konfiguriert Dashboard**. Shinkan: **Produkt definiert feste Kacheln** — bewusste MVP-Vereinfachung.
**Familien-Entscheidung:**
| App-Typ | Dashboard-Pattern |
|---------|-------------------|
| Personal Tracking (Mitai) | Widget-Katalog + Layout-JSON |
| Trainer/Verein (Shinkan) | Aggregierte KPI-Endpoints ausreichend; Widget-System optional Phase 2 |
| Neue App | Aggregat-Endpoint **mindestens**; Widget-System wenn Personalisierung nötig |
---
### 3.8 Navigation / IA (Mitai #8 ↔ Shinkan #12)
| Aspekt | Mitai | Shinkan | Bewertung |
|--------|-------|---------|-----------|
| appNav SSoT | ja | ja | ✅ |
| Admin-Hub | Shell + Hub-Gruppen | horizontale `AdminPageNav` | ⚠️ |
| Breakpoint 1024px | explizit | „prüfen“ | ⚠️ |
| Onboarding-Nav | — | reduziert ohne Verein | 🔀 Shinkan |
| adminNav.js SSoT | empfohlen | hardcoded Array in JSX | 🏗️ Shinkan |
| Safe Area PWA | ja | Design-System, weniger explizit | ⚠️ |
**Familien-Entscheidung:** `appNav.js` + **`adminNav.js`** als Pflicht; Shinkan `AdminPageNav` refactoren.
---
### 3.9 Migration & Deploy (Mitai #9 ↔ Shinkan #13)
| Aspekt | Mitai | Shinkan | Bewertung |
|--------|-------|---------|-----------|
| XXX_*.sql + schema_migrations | ✅ | ✅ | ✅ |
| Startup vor App | ✅ | ✅ | ✅ |
| develop/main | ✅ | ✅ | ✅ |
| Feste Ports | ✅ | ✅ | ✅ |
| Immutabler Docker-Build | dokumentiert | nicht im Shinkan-Doc | ⚠️ Doku |
| Health-Check / PG wait | ausführlich | kürzer | ⚠️ Doku |
**Aligned** — Shinkan-Dokument ist **Untermenge**; Implementierung vermutlich gleich (shared Infra).
---
## 4. Nur Shinkan (6 Module) — Einordnung für die Familie
| Modul | Familien-Relevanz | Mitai-Bezug |
|-------|-------------------|------------|
| **Access Layer & Tenant** | **Pflicht** für mandantenfähige Apps | Mitai #3 fordert Org-Boundary — hier ausformuliert |
| **Media Assets & Archiv** | Optional (Content-Apps) | — |
| **Exercise Catalog** | Shinkan-Domäne | — |
| **Training Planning** | Shinkan-Domäne | — |
| **Content Reports (P-13)** | Empfohlen für UGC/Plattform | — |
| **Maturity Models** | Optional (Kompetenz-Apps) | — |
**Kein Widerspruch zu Mitai** — ergänzen das Familienmodell um **Mandant + Content-Governance**.
---
## 5. Querschnitt: Ist-Stand vs. dokumentierte Prinzipien
Gemeinsame **Architekturschuld** (beide Apps verletzen teils eigene „Nicht übernehmen“-Listen):
| Thema | Mitai | Shinkan |
|-------|-------|---------|
| Parallele KI-Pfade | `insights.py` Legacy | OpenRouter direkt in Routern |
| Entitlement Enforcement | teils UI-only / Legacy-Spalten | Env Probe-only |
| Registry-Sync / Duplikat | PLACEHOLDER_MAP + Registry | Capabilities-Sync, kein Prompt-Registry |
| Frontend ohne Backend-Gate | teils | Capabilities Probe |
| Dokumentations-Drift | Tier vs. Enforcement-Docs | Endpoint-Audit unvollständig |
| Monolithische Pages/Client | God Pages, api.js | God Pages, api.js (Roadmap Phase 4) |
| Fehlende JSON-Schema-KI | TODO | TODO (explizit vermeiden) |
---
## 6. Entscheidungs-Matrix (Priorisiert)
| Prio | Entscheidung | Betroffene Apps | Empfohlene Familien-Regel |
|------|--------------|-----------------|---------------------------|
| **P0** | Entitlement-Subjekt: Profil **und** optional Tenant | Mitai, Shinkan, neu | Ein API-Shape `/me/entitlements`; zwei Subjekt-Ebenen |
| **P0** | Kein Client-`profile_id` für AuthZ | alle | Session-only; Tenant via Header + Membership |
| **P1** | KI: ein Executor pro App | Mitai (fertig), Shinkan (Ziel) | `execute_prompt(slug, context_dto)` |
| **P1** | Berechnungs-SSoT-Schicht | Shinkan erweitern | Mindestens ein `*/metrics.py` pro Domäne mit KPIs |
| **P1** | Enforcement produktiv | beide | Phase 4 Enforce in Prod für kritische Features |
| **P2** | Registry-Taxonomie vereinheitlichen | beide | Rechte / Platzhalter / Import / UI-Plugin |
| **P2** | Admin-Nav SSoT | Shinkan | `adminNav.js` wie Mitai |
| **P2** | Import: Universal + Spezialmodule | Shinkan | Wiki als registriertes Modul |
| **P3** | Dashboard: Aggregat vs. Widgets | produktabhängig | Entscheidungsbaum §3.7 |
| **P3** | Shared `auth.py` / `db_init` | beide | Monorepo-Package oder Sync-Disziplin |
---
## 7. Konvergenz-Roadmap (langfristig)
```mermaid
flowchart LR
subgraph foundation [Familien-Foundation]
M9[Migration]
M5[Auth]
F3[Entitlements 2-Ebenen]
R4[Registry Meta]
end
subgraph mitai [Mitai]
DL[Data Layer]
PE[Prompt Engine]
DW[Dashboard Widgets]
end
subgraph shinkan [Shinkan]
AL[Access Layer]
AR[AI Runtime → Executor]
SS[Skill Scoring → Layer 1]
end
M9 --> mitai
M9 --> shinkan
M5 --> mitai
M5 --> shinkan
F3 --> mitai
F3 --> shinkan
R4 --> mitai
R4 --> shinkan
AL -.->|Mandanten-Apps| foundation
PE -.->|Konvergenz| AR
DL -.->|Schichtenmodell| SS
```
| Phase | Mitai | Shinkan |
|-------|-------|---------|
| **Kurz** | Legacy KI-Pfade entfernen; Enforcement-Doku vereinheitlichen | Access-Layer-Audit abschließen; `CAPABILITY_ENFORCE` |
| **Mittel** | Org-Scope in Entitlements vorbereiten | `ai_prompt_runtime` → Unified Executor; Router-Helfer statt KPI-Duplikat |
| **Lang** | SSO/Identity (Vision) | Data-Layer-ähnliche Module für Planung; optional Widget-Dashboard |
---
## 8. Nächste Schritte
1. **Review-Workshop:** Tabelle §6 P0P1 durchgehen und Familien-Regeln verbindlich markieren.
2. ~~**`FAMILY_ENTITLEMENT_MODEL.md`** anlegen (P0)~~ → [FAMILY_ENTITLEMENT_MODEL.md](./FAMILY_ENTITLEMENT_MODEL.md) (Entwurf 2026-07-04)
3. **Shinkan-Index** und **Mitai-Foundation-README** auf dieses Dokument verlinken.
4. **`FAMILY_ENTITLEMENT_MODEL.md`** — Entwurf angelegt (§6 Produkt-Abweichungen, §8 Regeln neue Apps).
5. Pro **P1-Punkt** Issue/Remediation-Eintrag in jeweiliger `SCHULDEN_UND_REMEDIATION` / Mitai-Äquivalent.
---
## 9. Changelog
| Datum | Änderung |
|-------|----------|
| 2026-07-04 | Erstfassung Abgleich Mitai Foundation (9) ↔ Shinkan (15) |

View File

@ -0,0 +1,316 @@
# Familien-Modell: Entitlements & Limits
**Status:** Entwurf / verbindliche Zielrichtung (mit bewussten Produkt-Ausnahmen)
**Stand:** 2026-07-04
**Bezüge:**
- [DESIGN_PRINCIPLES_ALIGNMENT.md](./DESIGN_PRINCIPLES_ALIGNMENT.md) — Abgleich Mitai ↔ Shinkan
- Mitai: [FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/jinkendo-foundation/design-principles/FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md)
- Shinkan: [CAPABILITY_ENTITLEMENT_DESIGN_PRINCIPLES.md](./design-principles/CAPABILITY_ENTITLEMENT_DESIGN_PRINCIPLES.md)
---
## 1. Zweck
Dieses Dokument definiert das **gemeinsame Entitlement-Modell** der Jinkendo-Produktfamilie:
- **Was** für neue Apps und Refactors **Standard** ist
- **Welche Produkt-Profile** welche Scopes nutzen (Account, Tenant, beides, keins)
- **Wie** bewusste Abweichungen dokumentiert werden — Abweichung ist erlaubt, **Undokumentiertheit** nicht
**Nicht enthalten:** Stripe/SSO (`auth.jinkendo.de`), vollständige Billing-Implementierung, app-spezifische Feature-IDs.
---
## 2. Leitgedanke: Vier getrennte Fragen
Jede geschützte Aktion durchläuft konzeptionell **vier unabhängige Prüfungen**. Nicht jede App implementiert alle vier — siehe §6.
| # | Frage | Familien-Begriff | Typische Quelle |
|---|--------|------------------|-----------------|
| **A** | Wer ist eingeloggt? | **Auth** (Identität) | Session → `profile_id` |
| **B** | Darf diese Rolle die **Funktion** ausführen? | **Capability** (Permission) | Rollen-Matrix, `min_account_state` |
| **C** | Ist das **Kontingent** erschöpft? | **Feature / Limit** (Quota) | Plan, Tier, Usage-Zähler |
| **D** | Darf ich **dieses Objekt** lesen/ändern? | **Governance** (Object ACL) | `visibility`, `club_id`, Owner |
```
Request → Auth (A) → [Capability (B)] → [Feature-Limit (C)] → [Governance (D)] → Handler
```
**Familien-Regel:** B, C und D **nicht** in React-Widgets oder Router-Inline-Logik vermischen — jeweils eine Auflösungsfunktion pro Ebene.
**Shinkan-Ergänzung:** Governance ist dort ausgebaut (`TenantContext`, Access Layer); Mitai fokussiert A+B+C auf Profil-Ebene.
---
## 3. Familien-Standard: Zwei Subjekt-Ebenen
Limits und Pläne können an **zwei Subjekte** hängen. Beide sind im Familienmodell **first-class** — Apps wählen, welche sie nutzen (§6).
| Subjekt | ID | Typische Frage | Beispiel |
|---------|-----|----------------|----------|
| **Account** | `profile_id` | Was darf **ich** als Nutzer (Tarif)? | Mitai Free vs. Premium |
| **Tenant** | `tenant_id` (z. B. `club_id`) | Was darf **meine Organisation**? | Shinkan Vereinsplan, KI-Kontingent |
### 3.1 Auflösungs-Reihenfolge (wenn beide Ebenen aktiv)
Für eine Aktion mit Capability `X` und Feature `Y`:
1. **Account-Lifecycle** — z. B. E-Mail verifiziert, Onboarding abgeschlossen
2. **Capability(B)** — Rolle darf Funktion (Account- und/oder Tenant-Rollen)
3. **Feature(C)** — Kontingent am **primären Billing-Subjekt** der App (siehe Produkt-Profil)
4. **Governance(D)** — Objekt sichtbar/bearbeitbar
**AND-Verknüpfung:** Alle aktiven Ebenen müssen passieren. Ausnahmen nur in §6.3 dokumentiert.
### 3.2 Primäres Billing-Subjekt pro App
| Profil | Primäres Subjekt für Limits | Capability-Subjekt |
|--------|----------------------------|-------------------|
| Personal App (Mitai) | **Account** | Account |
| Mandanten-App (Shinkan) | **Tenant** | Account + Tenant-Rolle |
| Hybrid (Zukunft) | konfigurierbar | beide |
---
## 4. Familien-Standard: Capabilities vs. Features
| Konzept | Familien-Definition | Subjekt | Beispiel |
|---------|---------------------|---------|----------|
| **Capability** | Binäre oder rollenbasierte **Erlaubnis** („darf ich?“) | meist Account + Tenant-Kontext | `exercises.ai.suggest` |
| **Feature** | **Kontingent** oder Boolean-Limit („wie oft/noch?“) | Account **oder** Tenant | `ai_calls` / Monat |
| **Verknüpfung** | Capability kann `linked_feature_id` haben | — | KI-Capability → KI-Kontingent |
**Familien-Regel:**
- Capabilities **registry-first** registrieren (Code → DB-Sync, Shinkan-Muster).
- Feature-IDs **nicht** in UI hardcoden — nur aus Entitlements-Response.
- `NULL` Limit = unbegrenzt; `0` = deaktiviert (Mitai-Semantik, familienweit).
---
## 5. Familien-Standard: API & Enforcement
### 5.1 Ziel-API (neue Apps)
Ein **einheitlicher Snapshot** für das Frontend:
```
GET /api/me/entitlements
?tenant_id=<optional>
Response (skizziert):
{
"account": {
"profile_id": 1,
"account_state": "active_member",
"tier_id": "premium", // optional, Account-Apps
"features": { "ai_calls": { "allowed", "used", "limit", "remaining", "reset_at" } },
"capabilities": { "analysis.run": { "allowed": true, "reason": null } }
},
"tenant": { // null wenn App keinen Tenant kennt
"tenant_id": 42,
"tenant_type": "club",
"plan_id": "pro",
"features": { ... },
"capabilities": { ... },
"roles": ["trainer"]
},
"enforcement": {
"capabilities": "enforce|probe",
"features": "enforce|probe"
}
}
```
**Familien-Regel:** UI liest **nur** diesen Snapshot (oder domänenspezifische Teilmenge) — keine parallelen `/subscription/me` + `/features/usage` + Ad-hoc-Checks in neuen Apps.
### 5.2 Ist-API (bestehende Apps — Abweichung dokumentiert)
| App | Endpoint heute | Familien-Ziel |
|-----|----------------|---------------|
| **Mitai** | `/subscription/me`, `/features/usage`, `check_feature_access` | Snapshot schrittweise; Account-Block reicht |
| **Shinkan** | `GET /api/me/entitlements?club_id=` | Tenant-Block + Capabilities; Account-Tier fehlt bewusst |
Migration: **kein Big-Bang** — alte Endpoints als Facade auf Snapshot mappen.
### 5.3 Vier-Phasen-Rollout (familienweit verbindlich)
| Phase | Verhalten | Env-Beispiel |
|-------|-----------|--------------|
| **1** | Cleanup Legacy-Flags | — |
| **2** | **Probe** — JSON-Log, HTTP 200 | `*_ENFORCE=0` |
| **3** | Frontend-Gates aus Entitlements | — |
| **4** | **Enforce** — HTTP 403 | `*_ENFORCE=1` |
**Familien-Regel:** Phase 4 für **neue** kritische Features von Anfang an planbar; Bestands-Apps dürfen in Phase 23 bleiben bis kalibriert.
### 5.4 Enforcement-Priorität
1. **API** — autoritativ (`403`)
2. **Frontend** — UX (Badges, disabled Buttons)
3. **Niemals** — nur UI ohne API-Gate
---
## 6. Produkt-Profile & bewusste Abweichungen
Abweichungen vom Familien-Standard sind **zulässig**, wenn sie in der Tabelle **§6.2** stehen und begründet sind.
### 6.1 Profil-Matrix (Soll)
| Profil | Apps | Account-Limits | Tenant-Limits | Capabilities | Governance (Objekt) |
|--------|------|----------------|---------------|--------------|---------------------|
| **P1 Personal** | Mitai | ✅ primär | ❌ | ✅ Account | minimal / privat |
| **P2 Mandant** | Shinkan | ⚠️ Lifecycle only | ✅ primär | ✅ Account + Tenant-Rollen | ✅ Access Layer |
| **P3 Minimal** | Miken, Ikigai (geplant) | optional | ❌ | optional | minimal |
| **P4 Hybrid** | (Reserve) | ✅ | ✅ | ✅ beide | ✅ |
### 6.2 Registrierter Abweichungs-Katalog
| ID | App | Abweichung vom Familien-Standard | Begründung | Review |
|----|-----|----------------------------------|------------|--------|
| **DEV-01** | Mitai | Kein `tenant`-Block in Entitlements | Persönliche Tracking-App; kein Verein | Beibehalten (P1) |
| **DEV-02** | Mitai | Kein Capability-Katalog (nur Features+Tier) | RBAC = admin/user ausreichend | Optional später `account.*` Capabilities |
| **DEV-03** | Mitai | Mehrere Nutzer-APIs statt einem Snapshot | Historisch gewachsen | Facade → Snapshot (mittelfristig) |
| **DEV-04** | Mitai | Legacy Session-Spalten (`ai_enabled`, …) parallel Features | Migrationsschuld | Bereinigen, nicht in neue Apps |
| **DEV-05** | Shinkan | Kein Account-Tier / `profiles.tier` | Verein zahlt, nicht Trainer | Beibehalten (P2) |
| **DEV-06** | Shinkan | Capabilities **und** Governance (zwei Achsen) | Trainer vs. Objekt-Rechte | Familien-Vorbild für P2/P4 |
| **DEV-07** | Shinkan | `check_feature_access` (Mitai-Legacy) explizit verboten | Falsches Subjekt | Beibehalten |
| **DEV-08** | Shinkan | Enforcement oft Probe-only | Rollout-Sicherheit | → Phase 4 bis Datum X |
| **DEV-09** | Shinkan | Inventar-Features live gezählt | Drift-Vermeidung | Abweichung OK; in P2 dokumentieren |
| **DEV-10** | Beide | Kein atomares Check+Increment | Race bei Parallel-Requests | Familien-Backlog; Workaround dokumentieren |
| **DEV-11** | Neue Apps | dürfen **nur** Account **oder** nur Tenant wählen | MVP | Eintrag hier anlegen vor Launch |
**Neue Abweichung:** Zeile in §6.2 + ggf. ein Satz im App-`CLAUDE.md`.
### 6.3 Dokumentierte Ausnahmen (Bypass)
| Ausnahme | Apps | Regel |
|----------|------|-------|
| Plattform-Admin Audit | Shinkan | Quota-Bypass über Grants, nicht pauschal superadmin |
| Admin ohne Auto-Bypass | Mitai | Admins unterliegen Limits (Produktentscheid) |
| Öffentliche Routen ohne Auth | alle | Kein Entitlement-Check |
---
## 7. Mapping: Familien-Begriff ↔ Implementierung
### 7.1 Mitai (Profil P1)
| Familien | Mitai-Implementierung |
|----------|----------------------|
| Account-Features | `features`, `tier_limits`, `user_feature_usage` |
| Account-Tier | `get_effective_tier()`, `access_grants` |
| Check | `check_feature_access(profile_id, feature_id)` |
| Increment | `increment_feature_usage(profile_id, …)` |
| UI | `UsageBadge`, Widget `allowed` |
### 7.2 Shinkan (Profil P2)
| Familien | Shinkan-Implementierung |
|----------|-------------------------|
| Tenant-Features | `club_plan_limits`, `club_feature_usage`, `club_features.py` |
| Tenant-Plan | `get_effective_club_plan(club_id)` |
| Capabilities | `check_capability`, `capabilities` + `rights_registry` |
| Snapshot | `build_me_entitlements()``GET /me/entitlements` |
| Governance | `TenantContext`, `club_tenancy`**kein** Ersatz für Capabilities |
### 7.3 Gemeinsame Muster (copy-ready)
| Muster | Mitai | Shinkan |
|--------|-------|---------|
| Feature-Registry in DB | ✅ | ✅ (`app='shinkan'`) |
| Plan × Feature Matrix | `tier_limits` | `club_plan_limits` |
| Admin-Override | `user_feature_restrictions` | `club_feature_overrides` |
| Promo/Trial | `access_grants` | `club_access_grants` |
| 4-Phasen-Rollout | ✅ | ✅ |
| Registry-first neue IDs | ⚠️ teils hardcoded | ✅ `rights_registrations/` |
---
## 8. Entscheidungsregeln für neue Produkte
### 8.1 Pflicht (alle Apps mit Auth)
- [ ] Session → `profile_id`; kein Client-Header als Autorität
- [ ] Entitlements-Auflösung **eine Funktion pro Ebene** (Capability, Feature)
- [ ] API-Enforcement vor UI-Gate
- [ ] 4-Phasen-Rollout dokumentiert
- [ ] Produkt-Profil (P1P4) gewählt + Abweichungen in §6.2
### 8.2 Wenn Personal App (P1)
- [ ] Primäres Subjekt = Account
- [ ] `tenant`-Block in API = `null` (DEV-01-Analog)
- [ ] Feature-Registry + Tier-Matrix
### 8.3 Wenn Mandanten-App (P2)
- [ ] Primäres Subjekt = Tenant
- [ ] `TenantContext` + Governance getrennt von Capabilities
- [ ] Capabilities registry-first
- [ ] Account nur Lifecycle (verified, member) — kein Tier nötig (DEV-05-Analog erlaubt)
### 8.4 Wenn Minimal App (P3)
- [ ] Explizit: „keine Limits“ oder nur Boolean-Features — in §6.2 eintragen
- [ ] Kein halbes Mitai-v9c kopieren
---
## 9. Konvergenz-Roadmap (optional, nicht blockierend)
| Schritt | Mitai | Shinkan | Familie |
|---------|-------|---------|---------|
| **Kurz** | Legacy Session-Flags entfernen | `CAPABILITY_ENFORCE` / `CLUB_FEATURE_ENFORCE` Prod | DEV-04, DEV-08 schließen |
| **Mittel** | `/me/entitlements` Account-Block | Snapshot um `tenant`-Typ metadata erweitern | Facade alte APIs |
| **Lang** | Optional `tenant_id` reservieren (null) | Optional Account-Tier für Cross-Sell | Shared package `jinkendo_entitlements` |
| **Vision** | SSO + zentraler Billing | Vereins-Abo Stripe | `CENTRAL_SUBSCRIPTION_SYSTEM` |
**Wichtig:** Konvergenz ist **empfohlen**, nicht Pflicht — solange §6.2 aktuell bleibt.
---
## 10. Anti-Patterns (familienweit verboten)
1. Tier- oder Plan-Namen in React-Komponenten hardcoden
2. Limit-Logik nur im Frontend
3. Shinkan-Vereinslimits über Mitai `check_feature_access(profile_id)`
4. Capability-Check durch Governance ersetzen (oder umgekehrt)
5. Neue Feature-IDs nur in SQL-Migration ohne Registry
6. Enforcement Phase 4 „vergessen“ bei paid Features ohne dokumentierte Probe-Phase
7. Undokumentierte Produkt-Abweichung (nicht in §6.2)
---
## 11. Offene Familien-Entscheidungen (Backlog)
| ID | Frage | Optionen | Default wenn unentschieden |
|----|-------|----------|----------------------------|
| **FD-01** | Atomares check+increment | DB-Lock / Transaction / Queue | Status quo + Retry-Hinweis in Doku |
| **FD-02** | Shared Python-Modul | Monorepo-Paket vs. Copy+Sync | Copy+Sync mit gleicher API-Shape |
| **FD-03** | Capability-Namespace global | `jinkendo.*` vs. app-prefix | `{app}.{domain}.{action}` |
| **FD-04** | Mitai bekommt Capability-Layer? | ja/nein/später | nein (DEV-02) bis Bedarf |
| **FD-05** | Ein `features.app` für alle Apps | gemeinsame DB vs. pro Deploy | pro Deploy (heute) |
---
## 12. Verwandte Dokumente
| Dokument | Inhalt |
|----------|--------|
| [DESIGN_PRINCIPLES_ALIGNMENT.md](./DESIGN_PRINCIPLES_ALIGNMENT.md) | Vollständiger Mitai ↔ Shinkan Abgleich |
| [design-principles/CAPABILITY_ENTITLEMENT_DESIGN_PRINCIPLES.md](./design-principles/CAPABILITY_ENTITLEMENT_DESIGN_PRINCIPLES.md) | Shinkan Ist-Prinzipien |
| [ACCESS_LAYER_DESIGN_PRINCIPLES.md](./design-principles/ACCESS_LAYER_DESIGN_PRINCIPLES.md) | Governance (Ebene D) |
| Mitai Foundation #3 | Feature & Entitlement Ist Mitai |
| Shinkan `CLUB_MEMBERSHIP_AND_FEATURES.v1.md` | Vereins-Abo Detail |
| Shinkan `CAPABILITY_CATALOG.v1.md` | Capability-IDs |
---
## 13. Changelog
| Datum | Änderung |
|-------|----------|
| 2026-07-04 | Entwurf: Familien-Standard, Produkt-Profile P1P4, Abweichungs-Katalog DEV-0111 |

View File

@ -0,0 +1,48 @@
# Jinkendo Produktfamilie Dokumentation
**Zweck:** Querschnitts-Dokumentation, die **über einzelne Apps hinaus** gilt (Mitai, Shinkan, künftige Schwester-Produkte).
**Stand:** 2026-07-04
---
## Inhalt
| Verzeichnis | Zweck |
|-------------|--------|
| [design-principles/](./design-principles/) | Extrahierte **Designprinzipien** pro Modul — Foundation für neue Apps und Familien-Review |
---
## Designprinzipien
**Einstieg Shinkan:** [design-principles/DESIGN_PRINCIPLES_INDEX.md](./design-principles/DESIGN_PRINCIPLES_INDEX.md)
**Einstieg Mitai (Foundation):** [mitai-jinkendo/.claude/docs/jinkendo-foundation/design-principles/README.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/jinkendo-foundation/design-principles/README.md)
**Abgleich & Entscheidungen:** [DESIGN_PRINCIPLES_ALIGNMENT.md](./DESIGN_PRINCIPLES_ALIGNMENT.md) — Widersprüche, Abweichungen, Familien-Entscheidungs-Matrix
Die Serie dokumentiert:
- **Mitai** (9 Module) — Referenzimplementierung unter `mitai-jinkendo/.claude/docs/jinkendo-foundation/`
- **Shinkan** (15 Module) — in [design-principles/](./design-principles/)
Geplanter nächster Schritt: **FD-***-Entscheidungen im [FAMILY_ENTITLEMENT_MODEL.md](./FAMILY_ENTITLEMENT_MODEL.md) durcharbeiten; Enforcement Phase 4 wo vorgesehen.
| Dokument | Inhalt |
|----------|--------|
| [DESIGN_PRINCIPLES_ALIGNMENT.md](./DESIGN_PRINCIPLES_ALIGNMENT.md) | Mitai ↔ Shinkan Abgleich |
| [FAMILY_ENTITLEMENT_MODEL.md](./FAMILY_ENTITLEMENT_MODEL.md) | **Familien-Standard** Entitlements + Produkt-Abweichungen |
---
## Bezug zu App-spezifischer Doku
| Ebene | Ort (Beispiel Shinkan) |
|-------|-------------------------|
| **Familie** (Prinzipien) | `docs/jinkendo-family/` |
| **App-Architektur** | `docs/architecture/` |
| **Technische Specs** | `.claude/docs/technical/` |
| **Agent-Regeln** | `.claude/rules/`, `CLAUDE.md` |
Implementierungsdetails und Domänen-Specs bleiben in den jeweiligen App-Repositories; Designprinzipien beschreiben **übertragbare Muster** und **bewusste Lücken**.

View File

@ -0,0 +1,170 @@
# Access Layer & Tenant Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Modul „Access Layer & Tenant Governance“ — keine Shinkan-Gesamtarchitektur, keine Kampfsport-Domänenlogik
**Serie:** Designprinzipien für Produktfamilie · Shinkan Dokument 1 von 15
**Mitai-Vergleich:** kein direktes Gegenstück (Mitai ist profil-zentriert, kein Vereins-Mandant)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| TenantContext | `backend/tenant_context.py` |
| Governance-Helfer | `backend/club_tenancy.py` |
| Listenfilter SQL | `library_content_visibility_sql()` in `tenant_context.py` |
| Endpoint-Audit | `.claude/docs/working/ACCESS_LAYER_ENDPOINT_AUDIT.md` |
| Cursor-Regel | `.cursor/rules/access-layer.mdc` |
| Heuristik-Check | `backend/scripts/check_access_layer_hints.py` |
| Normative Spec | `.claude/docs/technical/ACCESS_LAYER_AND_GOVERNANCE_PLAN.md` |
---
## Modul
**Access Layer & Tenant Governance**
Zentraler Querschnitt für Mandanten-Kontext (`club_id`), Sichtbarkeit (`private`/`club`/`official`) und einheitliche Les-/Schreibregeln für Bibliotheksartefakte (Übungen, Medien, Rahmenprogramme, Vorlagen, Progressionsgraphen).
---
## Fachliche Verantwortung
1. **TenantContext pro HTTP-Request** — Auflösung aus Session + Header `X-Active-Club-Id` + Profilfeld `active_club_id`.
2. **Datenisolierung**`club_id` als Grenze für vereinsgeteilte Inhalte; Cross-Verein ausgeschlossen.
3. **Einheitliche Sichtbarkeits-Semantik** — gleiche Enums und Prüflogik über alle Bibliotheksmodule.
4. **Governance-Transitionen** — Regeln beim Wechsel `private``club``official` und beim Löschen.
5. **Listenfilter** — SQL-Baustein statt „SELECT *“ in jedem Router.
### Administrierte Konfigurationen
| Konfiguration | Speicherort | Inhalt |
|---------------|-------------|--------|
| Aktiver Verein | `profiles.active_club_id` | Persistierter UI-Kontext |
| Request-Override | Header `X-Active-Club-Id` | Client-seitiger Mandantenwechsel |
| Sichtbarkeit | Spalte `visibility` je Objekt | `private`, `club`, `official` |
| Vereinszuordnung | Spalte `club_id` | Pflicht bei `club`-Inhalten |
### Bewusst nicht hardcodiert
- Welche Objekte welchen Verein haben (Daten)
- Individuelle Freigabeentscheidungen (Workflow)
### Hardcodiert (Code)
- Enum-Werte und Leseregeln in `club_tenancy.py` / `library_content_visibility_sql`
- Plattform-Admin-Ausnahmen (`is_platform_admin`, `is_superadmin`)
- Rollencodes für Schreib-/Löschregeln (`club_admin`, `trainer`, …)
---
## Designprinzipien
### 1. Ein Mandant pro Request (`TenantContext`)
| | |
|---|---|
| **Prinzip** | `Depends(get_tenant_context)` liefert `profile_id`, `global_role`, `effective_club_id`, Mitgliedschaften — einmal pro Request. |
| **Begründung** | Kein verteiltes „Rates“ aus Headers; konsistente Filter in allen Routern. |
| **Quelle** | `tenant_context.py`; `ACCESS_LAYER_AND_GOVERNANCE_PLAN.md` §2 |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Nicht alle Endpoints migriert; Audit-Tabelle zeigt Restbestand mit nur `require_auth`. |
### 2. `club_id` als Datenisolierungsgrenze
| | |
|---|---|
| **Prinzip** | Vereinsgeteilte Inhalte sind nur für aktive Mitglieder des Objekt-`club_id` lesbar — nie Cross-Verein. |
| **Begründung** | Mandantenfähigkeit für Vereinsplattform; Compliance bei geteilten Trainingsinhalten. |
| **Quelle** | `library_content_visibility_sql()`; Tests `test_access_layer*.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | `division`-Verschärfung noch nicht durchgängig; reserviert im Plan. |
### 3. Einheitliche Visibility-Semantik
| | |
|---|---|
| **Prinzip** | `private` \| `club` \| `official` mit gleicher Bedeutung für Übungen, Medien, Rahmen, Module, Graphen. |
| **Begründung** | Nutzer und Trainer verstehen ein Freigabemodell; UI-Feld „Freigabelevel“ durchgängig. |
| **Quelle** | `club_tenancy.py`; `FACHLICHE_NUTZERFUNKTIONEN.md` §4.7 |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | `community`-Stufe nur dokumentiert, nicht implementiert. |
### 4. Zentraler SQL-Filter für Bibliothekslisten
| | |
|---|---|
| **Prinzip** | Listen nutzen `library_content_visibility_sql(alias, profile_id, role, effective_club_id)` — nicht handgeschriebene WHERE-Kopien. |
| **Begründung** | Drift-Vermeidung; ein Fix gilt für alle Kataloge. |
| **Quelle** | `tenant_context.py`; Router `exercises.py`, `training_framework_programs.py`, … |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Einzelne Legacy-Queries können noch abweichen. |
### 5. Governance-Transitionen explizit prüfen
| | |
|---|---|
| **Prinzip** | Wechsel von `visibility`/`club_id` über `assert_library_content_governance_transition` + `assert_valid_governance_visibility`. |
| **Begründung** | „Privat → Verein teilen“ und „official herabstufen“ sind sicherheitsrelevante Aktionen. |
| **Quelle** | `club_tenancy.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Nicht jedes Modul ruft Transition-Helper bei PATCH auf. |
### 6. Löschregeln nach Visibility-Stufe
| | |
|---|---|
| **Prinzip** | `assert_library_content_deletable`: privat → Ersteller/Vereinsadmin-Kontext; club → Vereinsadmin; official → Plattform-Admin. |
| **Begründung** | Schutz vor versehentlichem Löschen fremder oder offizieller Inhalte. |
| **Quelle** | `club_tenancy.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Medien-Lifecycle hat zusätzliche Stufen (Papierkorb) — Schnittmenge beachten. |
### 7. Aktiver Verein: Header + Profil synchron
| | |
|---|---|
| **Prinzip** | Frontend sendet `X-Active-Club-Id`; Backend validiert gegen Mitgliedschaft; Profil speichert `active_club_id`. |
| **Begründung** | Einheitlicher Mandanten-Kontext über API und UI. |
| **Quelle** | `frontend/src/api/client.js` (`mergeActiveClubHeader`); `profiles` Router |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Onboarding-Nutzer ohne Verein: eingeschränkter Nav-Modus. |
### 8. Plattform-Admin als Audit-Pfad, nicht als Bypass
| | |
|---|---|
| **Prinzip** | Plattform-Admins sehen fremde `club`-Inhalte nur mit expliziter Regel (Mitgliedschaft oder Audit-Ausnahme in SQL). |
| **Begründung** | Superuser-Zugriff ohne Mandanten-Leak in normalen Trainer-Flows. |
| **Quelle** | `library_content_visibility_sql``club_ok_plat`-Zweig |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Feinheiten zwischen `admin` und `superadmin` (z. B. `official`, Legal Hold) separat geregelt. |
### 9. Endpoint-Audit als lebendes Inventar
| | |
|---|---|
| **Prinzip** | Jeder sicherheitsrelevante Endpoint-Eintrag in `ACCESS_LAYER_ENDPOINT_AUDIT.md`; PR-Checkliste verlangt Update. |
| **Begründung** | Sichtbarkeit des Migrationsstands; kein stilles Ausweichen auf `require_auth` allein. |
| **Quelle** | `.claude/docs/working/ACCESS_LAYER_ENDPOINT_AUDIT.md`; `check_access_layer_hints.py` |
| **Tragfähigkeit** | **hoch** (prozessual) |
| **Einschränkung** | CI-Strict-Modus optional, nicht überall aktiv. |
---
## Nicht übernehmen
1. **Endpoints nur mit `require_auth`** bei tenant-sensitiven Daten — führt zu IDOR und fehlenden Listenfiltern.
2. **Visibility-Logik pro Router duplizieren** — historische Drift zwischen Übungen und Planung.
3. **`division` vor stabiler Vereins-Isolation** — Reihenfolge im Plan: erst Stufe C, dann D.
4. **Community-Freigabe ohne additive Felder** — würde `club`-Isolation brechen.
5. **Client-seitige Mandantenfilter ohne Server-Enforcement** — UI-Hiding reicht nicht.
---
## Verwandte Dokumentation
- [ACCESS_LAYER_AND_GOVERNANCE_PLAN.md](../../../.claude/docs/technical/ACCESS_LAYER_AND_GOVERNANCE_PLAN.md)
- [MULTI_TENANCY_RBAC_ARCHITECTURE.md](../../../.claude/docs/technical/MULTI_TENANCY_RBAC_ARCHITECTURE.md)
- [DESIGN_PRINCIPLES_INDEX.md](./DESIGN_PRINCIPLES_INDEX.md)

View File

@ -0,0 +1,140 @@
# AI Prompt Runtime Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Modul „AI Prompt Runtime“ — Shinkan-KI-Schicht, keine Planungs-Gesamtarchitektur
**Serie:** Designprinzipien für Produktfamilie · Shinkan Dokument 5 von 15
**Mitai-Vergleich:** [PROMPT_ENGINE_DESIGN_PRINCIPLES.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/technical/PROMPT_ENGINE_DESIGN_PRINCIPLES.md) (#1)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| Laufzeit | `backend/ai_prompt_runtime.py`, `backend/prompt_resolver.py` |
| Domänen-Orchestrierung | `backend/exercise_ai.py`, `backend/planning_exercise_*.py` |
| OpenRouter | `backend/openrouter_chat.py` |
| Admin | `backend/routers/ai_prompts_admin.py` |
| Zielbild | `.claude/docs/technical/AI_PROMPT_TARGET_ARCHITECTURE.md` |
| Job-Kontext | `backend/ai_prompt_job.py`, `backend/ai_prompt_context.py` |
---
## Modul
**AI Prompt Runtime**
Schmale Ausführungsschicht für admin-konfigurierbare Prompts in `ai_prompts`: Laden, Mustache-Rendering, Kontext-Arten, OpenRouter-Aufruf. **Kein** vollständiges Unified Prompt System wie Mitai (keine Workflows/Pipelines in Produktion).
---
## Fachliche Verantwortung
1. **Prompt-Laden aus DB**`load_ai_prompt_row`, `load_and_render_ai_prompt`
2. **Platzhalter-Ersetzung** — Mustache `{{key}}` via `prompt_resolver.py`
3. **Kontext-Arten**`AiPromptContextKind` trennt Übungs-KI vs. Planungs-KI
4. **Domänen-Builder**`exercise_ai`, Planungs-Pipelines bauen Variablen-Maps
5. **Admin CRUD + Preview** — ohne LLM in Preview-Pfaden wo vorgesehen
---
## Designprinzipien
### 1. Eine Laufzeit-Fassade für DB-Prompts
| | |
|---|---|
| **Prinzip** | Produktive Aufrufe laden Slugs über `ai_prompt_runtime` — nicht Roh-SQL auf `ai_prompts` in Routern. |
| **Begründung** | Einheitliches inactive-Handling, Modell-Feld, Render-Metadaten. |
| **Quelle** | `AI_PROMPT_TARGET_ARCHITECTURE.md` §2.1; `ai_prompt_runtime.py` |
| **Tragfähigkeit** | **hoch** (Zielrichtung) |
| **Einschränkung** | Planungs-KI hat noch verteilte Orchestratoren; kein einzelner `execute_prompt` wie Mitai. |
### 2. Konfigurierbare Bibliothek in `ai_prompts`
| | |
|---|---|
| **Prinzip** | Template-Texte in DB; Admins ändern ohne Deploy (`ai_prompts_admin`). |
| **Begründung** | Gleiches Familien-Muster wie Mitai Prompt-Bibliothek. |
| **Quelle** | Migration 069+; Admin-UI |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Keine Pipeline/Workflow-Typen; Slugs hardcoded in `context_kind_for_slug`. |
### 3. Kontext-Namespaces statt globaler Platzhalter-Soup
| | |
|---|---|
| **Prinzip** | `AiPromptContextKind` (z. B. `exercise_form_ai`, `planning_exercise_search`) begrenzt erlaubte Builder. |
| **Begründung** | Planungs-Kontext wächst ohne Kollision mit Übungs-Keys. |
| **Quelle** | `AI_PROMPT_TARGET_ARCHITECTURE.md` §2.3 |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Noch keine zentrale Platzhalter-Registry wie Mitai — Mustache ad hoc pro Builder. |
### 4. Trennung Template vs. Domänen-Kontext
| | |
|---|---|
| **Prinzip** | UI/Router liefern Pydantic-DTOs → Builder erzeugen `variables`-Map → `render_mustache_template`. |
| **Begründung** | Prompt-Autoren ändern Text, nicht Python in Routern. |
| **Quelle** | `prompt_resolver.py`; `ExerciseFormAiPromptContext` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Große Planungs-Kontexte noch nicht vollständig über DTOs. |
### 5. Transport (OpenRouter) getrennt von Semantik
| | |
|---|---|
| **Prinzip** | `openrouter_chat.py` für HTTP; Validierung/JSON-Parsing in Domänen-Schicht. |
| **Begründung** | Modellwechsel ohne Router-Anpassung. |
| **Quelle** | `AI_PROMPT_TARGET_ARCHITECTURE.md` §2.2 |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Modell teils global Env, teils Spalte `openrouter_model` — Konvergenz offen. |
### 6. Reset-to-default für System-Prompts
| | |
|---|---|
| **Prinzip** | `default_template` + Admin-Reset — kein vollständiges Versionsmodell. |
| **Begründung** | Familien-Muster aus Mitai; Schutz vor Fehlkonfiguration. |
| **Quelle** | Migration 069 |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Keine Historie benutzerdefinierter Änderungen. |
### 7. Admin-only Schreiben, authentifiziertes Ausführen
| | |
|---|---|
| **Prinzip** | Prompt-CRUD nur Admin; Ausführung mit Capability + Feature-Kontingent. |
| **Begründung** | Systemkonfiguration vs. Nutzung; Kostenkontrolle. |
| **Quelle** | `ai_prompts_admin.py`; `exercises.ai.suggest` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Enforcement teils noch Probe-Phase. |
### 8. Skill-Retrieval orthogonal zu Prompts
| | |
|---|---|
| **Prinzip** | `ai_skill_retrieval_profiles` steuert Katalog für `{{skills_catalog}}` — unabhängig vom Prompt-Text. |
| **Begründung** | Anweisung vs. Kontextfenster trennbar konfigurierbar. |
| **Quelle** | `AI_PROMPT_TARGET_ARCHITECTURE.md` §3.3 |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
---
## Nicht übernehmen (Shinkan-Ist / Mitai-Vermeidung)
1. **Direkte OpenRouter-Calls in Routern** ohne Laufzeit-Schicht — historische Schuld, abbauen.
2. **Hardcodierte Prompt-Strings in Produktion** — nur Fallback/Dev.
3. **Mitai-Workflow-Graph vorreifen** — Shinkan braucht erst Planungs-Kontext-Reife.
4. **Globale Platzhalter-Map ohne Namespace** — Mitai-Lektion `PLACEHOLDER_MAP`-Duplikat.
5. **Fehlende JSON-Schema-Validierung** bei `output_format=json` — Mitai-TODO übernehmen vermeiden.
---
## Verwandte Dokumentation
- [AI_PROMPT_TARGET_ARCHITECTURE.md](../../../.claude/docs/technical/AI_PROMPT_TARGET_ARCHITECTURE.md)
- [AI_PROMPT_SYSTEM_SPEC.md](../../../.claude/docs/technical/AI_PROMPT_SYSTEM_SPEC.md)
- [PLANNING_PROGRESSION_GRAPH_KI.md](../../architecture/PLANNING_PROGRESSION_GRAPH_KI.md)
- [DESIGN_PRINCIPLES_INDEX.md](./DESIGN_PRINCIPLES_INDEX.md)

View File

@ -0,0 +1,114 @@
# Auth & Session Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Modul „Auth & Session“ — gemeinsame Mitai-Basis in Shinkan
**Serie:** Designprinzipien für Produktfamilie · Shinkan Dokument 4 von 15
**Mitai-Vergleich:** [AUTH_SESSION_DESIGN_PRINCIPLES.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/technical/AUTH_SESSION_DESIGN_PRINCIPLES.md) (#5)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| Auth-Kern | `backend/auth.py` |
| Router | `backend/routers/auth.py`, `profiles.py` |
| Frontend | `frontend/src/context/AuthContext.jsx`, `frontend/src/api/client.js` |
| Account-Lifecycle | `backend/account_lifecycle.py` |
---
## Modul
**Auth & Session**
Token-basierte Server-Sessions (`sessions`-Tabelle), bcrypt-Passwörter, FastAPI-Dependencies `require_auth` / `require_admin`. Geteilter Code mit Mitai (App-Familie).
---
## Fachliche Verantwortung
1. **Login/Logout/Session-Lebensdauer**
2. **Passwort-Hashing** (bcrypt, Legacy-SHA256-Upgrade)
3. **Auth-Dependencies** für Router
4. **Account-States** (Verifizierung, Onboarding-Gates)
---
## Designprinzipien
### 1. Server-Side Sessions mit Token
| | |
|---|---|
| **Prinzip** | `X-Auth-Token` Header → Lookup in `sessions` mit Ablaufzeit. |
| **Begründung** | Widerrufbar; kein JWT-Drift zwischen Apps. |
| **Quelle** | `auth.py` `get_session`, `require_auth` |
| **Tragfähigkeit** | **hoch** (Familien-Standard) |
| **Einschränkung** | Kein Refresh-Token-Rotation-Modell. |
### 2. `require_auth` als separater Depends-Parameter
| | |
|---|---|
| **Prinzip** | `session: dict = Depends(require_auth)` — nie in Header-Default eingebettet. |
| **Begründung** | Bekannter FastAPI-Footgun führt zu ungeschützten Endpoints. |
| **Quelle** | `CLAUDE.md` Kritische Regeln |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Code-Review/Lint erzwingt das nicht automatisch. |
### 3. Profile-ID immer aus Session
| | |
|---|---|
| **Prinzip** | `profile_id` aus `session['profile_id']`, nie aus Client-Header als Autorität. |
| **Begründung** | IDOR-Vermeidung. |
| **Quelle** | Architektur-Regeln; Shinkan ergänzt `TenantContext.profile_id` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Mitai-Dokument nennt Profile-Header-Schwäche — in Shinkan prüfen ob analog. |
### 4. bcrypt für alle Passwort-Operationen
| | |
|---|---|
| **Prinzip** | `hash_pin` / `verify_pin` mit bcrypt; SHA256 nur Legacy-Verify + Upgrade. |
| **Begründung** | Familien-konsistente Kryptografie. |
| **Quelle** | `auth.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 5. Portal-Rollen vs. Vereinsrollen trennen
| | |
|---|---|
| **Prinzip** | `profiles.role` (admin/superadmin/user) ≠ `club_member_roles` im Verein. |
| **Begründung** | Shinkan-Mandantenmodell; Plattform-Admin ≠ Vereins-Trainer. |
| **Quelle** | `club_tenancy.py`; `TenantContext.global_role` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | UI muss beide Ebenen korrekt anzeigen. |
### 6. Account-Lifecycle als Capability-Voraussetzung
| | |
|---|---|
| **Prinzip** | `min_account_state` auf Capabilities (z. B. verifiziertes Mitglied). |
| **Begründung** | Gates vor sensiblen Aktionen ohne Sonderchecks in Routern. |
| **Quelle** | `account_lifecycle.py`; `capabilities.py` |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Nicht alle Flows nutzen Lifecycle einheitlich. |
---
## Nicht übernehmen
1. **Auth-Parameter in Header-Defaults vermischen** — dokumentierter Anti-Pattern.
2. **Client-gesteuerte `profile_id`** für Autorisierung.
3. **Shinkan-spezifische Mandantenlogik in `auth.py`** — gehört in `tenant_context.py`.
---
## Verwandte Dokumentation
- [ACCESS_LAYER_DESIGN_PRINCIPLES.md](./ACCESS_LAYER_DESIGN_PRINCIPLES.md)
- Mitai: [AUTH_SESSION_DESIGN_PRINCIPLES.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/technical/AUTH_SESSION_DESIGN_PRINCIPLES.md)
- [DESIGN_PRINCIPLES_INDEX.md](./DESIGN_PRINCIPLES_INDEX.md)

View File

@ -0,0 +1,125 @@
# Capability & Club Features Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Modul „Capabilities & Vereins-Feature-Kontingente“ — nicht Billing/Stripe
**Serie:** Designprinzipien für Produktfamilie · Shinkan Dokument 2 von 15
**Mitai-Vergleich:** [FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/technical/FEATURE_ENTITLEMENT_DESIGN_PRINCIPLES.md) (#3)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| Capabilities | `backend/capabilities.py` |
| Vereins-Features | `backend/club_features.py` |
| Entitlements-API | `backend/entitlements.py`, `backend/routers/me_entitlements.py` |
| Quota-Bypass | `backend/club_quota_bypass.py` |
| Spez | `CAPABILITY_CATALOG.v1.md`, `CLUB_MEMBERSHIP_AND_FEATURES.v1.md` |
---
## Modul
**Capability & Club Feature Entitlements**
Zwei Schichten: **Capabilities** (darf Nutzer X im Verein Y?) und **Club Features** (Kontingente/Limits pro Verein, Subjekt `club_id`). Zusammenführung in `GET /api/me/entitlements`.
---
## Fachliche Verantwortung
1. **Capability-Checks**`check_capability`, `probe_capability`, `require_capability` mit Env `CAPABILITY_ENFORCE`.
2. **Vereins-Kontingente**`probe_club_feature_access`, `consume_club_feature_with_usage` mit Env `CLUB_FEATURE_ENFORCE`.
3. **Entitlements-Snapshot** — Frontend erhält `capabilities` + `features` + Plan für UI-Gating ohne Tier-Logik in Widgets.
4. **Account-Lifecycle**`min_account_state` blockiert Capabilities vor Verifizierung.
### Unterschied zu Mitai
| Aspekt | Mitai | Shinkan |
|--------|-------|---------|
| Limit-Subjekt | Profil / Subscription | **Verein** (`club_id`) |
| Rollen | Tier + Features | Vereinsrollen + Portal-Rolle |
| Legacy | `check_feature_access` (001) | Explizit **nicht** für Shinkan-Limits nutzen |
---
## Designprinzipien
### 1. Eine Entitlements-API für das Frontend
| | |
|---|---|
| **Prinzip** | `GET /api/me/entitlements?club_id=` liefert Capabilities-Map + Feature-Kontingente + Plan. |
| **Begründung** | Keine Tier-Logik in React-Komponenten; ein Roundtrip pro Mandantenwechsel. |
| **Quelle** | `entitlements.py`, `me_entitlements.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Nicht alle UI-Stellen nutzen Entitlements konsequent. |
### 2. 4-Phasen-Rollout (Probe → Enforce)
| | |
|---|---|
| **Prinzip** | Phase 2: JSON-Log ohne Block; Phase 3+: `CAPABILITY_ENFORCE=1` / `CLUB_FEATURE_ENFORCE=1` → HTTP 403. |
| **Begründung** | Sicheres Einführen ohne Produktions-Crash; Audit vor Hard-Block. |
| **Quelle** | `capabilities.py`, `club_features.py`; Mitai-Vorbild in Spec |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Env-Flags müssen pro Umgebung bewusst gesetzt werden. |
### 3. Capabilities verknüpft mit Features
| | |
|---|---|
| **Prinzip** | Capability kann `linked_feature_id` haben — Kontingent-Check vor Ausführung. |
| **Begründung** | Recht und Limit bleiben getrennt modelliert aber gemeinsam enforcebar. |
| **Quelle** | `capabilities`-Tabelle; `check_capability` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Nicht jede Capability hat linked Feature. |
### 4. Enforcement an der API, nicht in der UI
| | |
|---|---|
| **Prinzip** | Router rufen `require_capability` / `probe_club_feature_access` — UI blendet nur vor. |
| **Begründung** | API ist Source of Truth; UI-Gating allein ist umgehbar. |
| **Quelle** | `exercise_ai.py`, Planungs-KI-Router |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Teilweise noch Probe-only in Prod. |
### 5. Bestands-Features als Live-Zählung
| | |
|---|---|
| **Prinzip** | Inventar-Features (`exercises`, `training_groups`, …) zählen live in DB, nicht nur `club_feature_usage`. |
| **Begründung** | Keine Drift zwischen tatsächlichem Bestand und Usage-Tabelle. |
| **Quelle** | `_INVENTORY_FEATURES` in `club_features.py` |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Performance bei großen Vereinen — ggf. Cache nötig. |
### 6. Quota-Bypass für Plattform-Rollen
| | |
|---|---|
| **Prinzip** | Konfigurierbare Bypass-Capabilities (`domain=quota_bypass`) für Support/Admin ohne harte Limits. |
| **Begründung** | Betrieb und Demos ohne Plan-Upgrade. |
| **Quelle** | `club_quota_bypass.py`; `entitlements.py` |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Missbrauchsrisiko — nur dokumentierte Grants. |
---
## Nicht übernehmen
1. **Mitai `auth.check_feature_access` für Shinkan-Vereinslimits** — profil-zentriert, falscher Subjekt-Scope.
2. **Tier-Logik in Frontend-Widgets** — gehört in Entitlements-Response.
3. **Enforcement ohne Probe-Phase** — bricht bestehende Vereine ohne Vorwarnung.
4. **Capabilities ohne DB-Sync aus Registry** — siehe Rights-Registry-Dokument.
---
## Verwandte Dokumentation
- [CAPABILITY_CATALOG.v1.md](../../../.claude/docs/technical/CAPABILITY_CATALOG.v1.md)
- [CLUB_MEMBERSHIP_AND_FEATURES.v1.md](../../../.claude/docs/technical/CLUB_MEMBERSHIP_AND_FEATURES.v1.md)
- [RIGHTS_REGISTRY_DESIGN_PRINCIPLES.md](./RIGHTS_REGISTRY_DESIGN_PRINCIPLES.md)
- [DESIGN_PRINCIPLES_INDEX.md](./DESIGN_PRINCIPLES_INDEX.md)

View File

@ -0,0 +1,117 @@
# Content Reports (P-13) Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Modul „Content Reports“ — Meldeverfahren, Posteingang, Legal Hold
**Serie:** Designprinzipien für Produktfamilie · Shinkan Dokument 10 von 15
**Mitai-Vergleich:** — (Compliance-spezifisch)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| API | `backend/routers/content_reports.py` |
| Legal Hold | `backend/media_legal_hold.py` |
| Inbox-Integration | `GET /api/me/inbox/content-reports` |
| Frontend | `InboxPage.jsx` |
| Migration | 052, 053 |
---
## Modul
**Content Reports & Compliance (P-13)**
Meldeverfahren für problematische Inhalte (Medien, Übungen), Admin-Posteingang mit Statusworkflow, Priorisierung sensibler Gründe, Anbindung Legal Hold und Medien-Audit.
---
## Designprinzipien
### 1. Eine Tabelle, ein Workflow — keine separate Admin-Queue
| | |
|---|---|
| **Prinzip** | `content_reports` + bestehende Inbox-UI für Änderungsanfragen und Meldungen. |
| **Begründung** | Admin-Arbeit an einem Ort; weniger Navigations-Fragmentierung. |
| **Quelle** | `content_reports.py` Docstring |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Zwei Vorgangstypen in einer UI — klare Typ-Kennzeichnung nötig. |
### 2. Melden optional ohne Auth (eingeschränkt)
| | |
|---|---|
| **Prinzip** | Anonym/offline Meldung für `official`-Medien erlaubt; sonst Auth empfohlen. |
| **Begründung** | DSA-Anforderungen; öffentliche Plattform-Inhalte meldbar. |
| **Quelle** | Router-Berechtigungen |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Missbrauchsschutz (Rate Limit) prüfen. |
### 3. Priorität bei sensiblen Gründen
| | |
|---|---|
| **Prinzip** | `minors`, `illegal_content`, `youth_protection` → HIGH_PRIORITY automatisch. |
| **Begründung** | SLA und Admin-Aufmerksamkeit fachlich korrekt. |
| **Quelle** | `HIGH_PRIORITY_REASONS` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 4. Rollengetrennte Sicht (Plattform vs. Verein)
| | |
|---|---|
| **Prinzip** | Plattform-Admin: alle; Club-Admin: nur Vereinsmedien-Meldungen. |
| **Begründung** | Mandanten-Grenze auch im Compliance-Kontext. |
| **Quelle** | Router-Listenfilter |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 5. Legal Hold nur Superadmin aus Meldung
| | |
|---|---|
| **Prinzip** | Mapping `report_reason``legal_hold reason_code`; `set_legal_hold` superadmin-geschützt. |
| **Begründung** | Hochrisiko-Aktion; Anschluss P-11. |
| **Quelle** | `_REASON_TO_HOLD_CODE`; `media_legal_hold.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 6. Audit-Spur bei Medien-Meldungen
| | |
|---|---|
| **Prinzip** | `media_asset_audit_log` Event `content_report_filed` bei media_asset-Bezug. |
| **Begründung** | Lifecycle-Entscheidungen nachvollziehbar. |
| **Quelle** | Migration 053; `write_audit_log_entry` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 7. E-Mail best-effort, kein Hard-Fail
| | |
|---|---|
| **Prinzip** | Bestätigung an Melder + Admin-Benachrichtigung; SMTP-Fehler blockieren Speichern nicht. |
| **Begründung** | Meldung geht nicht verloren wenn Mail down. |
| **Quelle** | Router-Implementierung |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Admins müssen Posteingang auch ohne Mail prüfen. |
---
## Nicht übernehmen
1. **Separate Compliance-Queue-App** — Inbox-Reuse ist bewusst.
2. **Legal Hold durch Club-Admin** — Superadmin-only.
3. **Meldungen ohne Statusworkflow/Archiv** — Wiedereröffnen muss möglich sein.
4. **Fehlende Verknüpfung Medien-Lifecycle** — Hold muss Purge blockieren.
---
## Verwandte Dokumentation
- [MEDIA_ASSETS_DESIGN_PRINCIPLES.md](./MEDIA_ASSETS_DESIGN_PRINCIPLES.md)
- [ACCESS_LAYER_DESIGN_PRINCIPLES.md](./ACCESS_LAYER_DESIGN_PRINCIPLES.md)
- [DESIGN_PRINCIPLES_INDEX.md](./DESIGN_PRINCIPLES_INDEX.md)

View File

@ -0,0 +1,105 @@
# Dashboard KPIs Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Modul „Dashboard KPI Aggregation“ — vereinfacht vs. Mitai Widgets
**Serie:** Designprinzipien für Produktfamilie · Shinkan Dokument 14 von 15
**Mitai-Vergleich:** [DASHBOARD_WIDGETS_DESIGN_PRINCIPLES.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/technical/DASHBOARD_WIDGETS_DESIGN_PRINCIPLES.md) (#7, vereinfacht)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| API | `backend/routers/dashboard.py``GET /api/dashboard/kpis` |
| Frontend | Dashboard/Übersicht-Page |
| Refaktor-Kontext | `docs/architecture/SCHULDEN_UND_REMEDIATION.md` A3, B1 |
---
## Modul
**Dashboard KPI Aggregation**
Ein Backend-Roundtrip liefert Übungs-KPIs, YTD-Einheiten, Trainings-Home (nächste Termine, Vermerke, offene Rückschau) — Ersatz für mehrere parallele Client-Listen-Calls.
---
## Designprinzipien
### 1. Aggregierter Endpoint statt Chatty Client
| | |
|---|---|
| **Prinzip** | `GET /dashboard/kpis` ruft intern `list_exercises_like_get` + `list_training_units` mit gleichen Filtern wie zuvor im UI. |
| **Begründung** | Weniger Latenz; eine TenantContext-Auflösung; Refaktor Phase 1 Dashboard. |
| **Quelle** | `dashboard.py`; SCHULDEN A3/B1 |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Noch keine konfigurierbaren Widgets wie Mitai. |
### 2. Gleiche Filtersemantik wie Einzel-Endpoints
| | |
|---|---|
| **Prinzip** | KPI-Zählungen nutzen dieselben Helfer wie `/exercises` und `/training-units` — keine zweite Query-Logik. |
| **Begründung** | Zahlen auf Dashboard = Zahlen in Fachmodulen. |
| **Quelle** | Import aus `exercises`, `training_planning` Routern |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Interne Funktionsaufrufe statt HTTP — Kopplung an Router-Helfer. |
### 3. TenantContext für Mandanten-KPIs
| | |
|---|---|
| **Prinzip** | `Depends(get_tenant_context)` — assigned_to_me, created_by_me respektieren Verein/Rolle. |
| **Begründung** | Keine globalen KPIs für Trainer fremder Vereine. |
| **Quelle** | `get_dashboard_kpis` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 4. Festes Dashboard-Layout (kein Widget-Katalog)
| | |
|---|---|
| **Prinzip** | Shinkan-Übersicht zeigt definierte Kacheln — nicht nutzerkonfigurierbares Layout-JSON. |
| **Begründung** | MVP-Fokus Trainer-Verein; weniger Komplexität als Mitai. |
| **Quelle** | Produktentscheidung vs. Mitai #7 |
| **Tragfähigkeit** | **mittel** (bewusste Vereinfachung) |
| **Einschränkung** | Erweiterung braucht Backend+Frontend-Change, nicht Admin-Config. |
### 5. Profil nicht redundant laden
| | |
|---|---|
| **Prinzip** | Dashboard soll Auth-Profil nutzen — kein zweites `/profiles/me` nach Login+Reload (E2E Test 8). |
| **Begründung** | Architekturschuld A3 explizit adressiert. |
| **Quelle** | `tests/dev-smoke-test.spec.js`; Roadmap |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Frontend-Umsetzung muss mitziehen. |
### 6. Slice-Logik für Trainings-Home im Backend
| | |
|---|---|
| **Prinzip** | `_slice_training_home_notes` filtert Einheiten mit Vermerken — max. N Stück serverseitig. |
| **Begründung** | Kleiner Payload; klare Semantik. |
| **Quelle** | `dashboard.py` |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Grenzwert hardcoded — ggf. Query-Param später. |
---
## Nicht übernehmen
1. **Drei parallele fast gleiche `listTrainingUnits`-Calls** im Client — behoben durch KPI-Endpoint.
2. **Mitai Widget-Dual-Registry vorreifen** ohne Produktbedarf — Over-Engineering für Shinkan MVP.
3. **KPI-Berechnung im Frontend** aus Volllisten — skaliert nicht.
4. **Dashboard ohne Tenant-Filter** — Mandanten-Leak.
---
## Verwandte Dokumentation
- [docs/architecture/SCHULDEN_UND_REMEDIATION.md](../../architecture/SCHULDEN_UND_REMEDIATION.md)
- Mitai: [DASHBOARD_WIDGETS_DESIGN_PRINCIPLES.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/technical/DASHBOARD_WIDGETS_DESIGN_PRINCIPLES.md)
- [DESIGN_PRINCIPLES_INDEX.md](./DESIGN_PRINCIPLES_INDEX.md)

View File

@ -0,0 +1,143 @@
# Designprinzipien Index (Jinkendo Produktfamilie)
**Status:** Arbeitspapier / Übergabe
**Stand:** 2026-07-04
**Zweck:** Zentraler Einstieg für **tragfähige Designprinzipien** der Jinkendo-Produktfamilie — Shinkan-Serie (15 Module), Abgleich mit Mitai (9 Module), Basis für Schwester-Apps.
**Nicht enthalten:** App-Gesamtarchitektur, domänenspezifische Fachlogik im Detail, vollständige API-Referenz.
**Ablage (Shinkan-Serie):** `docs/jinkendo-family/design-principles/*_DESIGN_PRINCIPLES.md`
**Übergeordnet:** [docs/jinkendo-family/README.md](../README.md)
**Mitai-Serie:** [mitai-jinkendo/.claude/docs/jinkendo-foundation/design-principles/](file:///c:/Dev/mitai-jinkendo/.claude/docs/jinkendo-foundation/design-principles/README.md)
**Abgleich Mitai ↔ Shinkan:** [DESIGN_PRINCIPLES_ALIGNMENT.md](../DESIGN_PRINCIPLES_ALIGNMENT.md)
---
## Wofür diese Serie?
Shinkan implementiert wiederkehrende **Querschnittsmuster** (Mandanten-Zugriff, Capabilities, Medien-Archiv, Planungsdomäne, KI-Laufzeit, Import, Navigation, Deploy) sowie **domänenspezifische Bausteine** (Übungskatalog, Fähigkeiten-Scoring, Trainingsplanung, Compliance-Meldungen). Die 15 Dokumente destillieren daraus:
- **Was** übertragbar ist (Prinzip + Begründung + Tragfähigkeit)
- **Was** bewusst nicht kopiert werden soll („Nicht übernehmen“)
- **Wo** im Code nachgeschaut werden kann (Pfade, Specs)
- **Mitai-Abgleich** — welches Schwester-Dokument vergleichbar ist
Jedes Dokument ist **eigenständig lesbar**; dieser Index ordnet Abhängigkeiten, Lese-Reihenfolge und den geplanten Familien-Review.
---
## Dokumente (15/15)
| # | Modul | Datei | Kernidee (1 Satz) | Mitai-Vergleich |
|---|-------|-------|-------------------|-----------------|
| 1 | Access Layer & Tenant | [ACCESS_LAYER_DESIGN_PRINCIPLES.md](./ACCESS_LAYER_DESIGN_PRINCIPLES.md) | Ein `TenantContext` pro Request; einheitliche `visibility`/`club_id`-Semantik für Bibliotheksartefakte. | — (Shinkan-spezifisch) |
| 2 | Capability & Club Features | [CAPABILITY_ENTITLEMENT_DESIGN_PRINCIPLES.md](./CAPABILITY_ENTITLEMENT_DESIGN_PRINCIPLES.md) | Capabilities + Vereins-Kontingente; `GET /me/entitlements`; 4-Phasen-Rollout mit Env-Flags. | #3 Feature & Entitlement |
| 3 | Rights Registry | [RIGHTS_REGISTRY_DESIGN_PRINCIPLES.md](./RIGHTS_REGISTRY_DESIGN_PRINCIPLES.md) | Module registrieren Capabilities/Features bei Startup — kein vollständiger Vorab-Katalog in Migrationen. | #4 Registry / Plugin |
| 4 | Auth & Session | [AUTH_SESSION_DESIGN_PRINCIPLES.md](./AUTH_SESSION_DESIGN_PRINCIPLES.md) | Server-Sessions, `require_auth` als Depends; gemeinsame Mitai-Basis. | #5 Auth & Session |
| 5 | AI Prompt Runtime | [AI_PROMPT_RUNTIME_DESIGN_PRINCIPLES.md](./AI_PROMPT_RUNTIME_DESIGN_PRINCIPLES.md) | Schmale Laufzeit (`ai_prompt_runtime`); DB-Templates + Mustache; Kontext-Arten pro Domäne. | #1 Prompt Engine |
| 6 | Media Assets & Archiv | [MEDIA_ASSETS_DESIGN_PRINCIPLES.md](./MEDIA_ASSETS_DESIGN_PRINCIPLES.md) | Physisches Asset einmal, mehrfach verknüpft; Lifecycle, Legal Hold, Inline-Rich-Text. | — |
| 7 | Exercise Catalog | [EXERCISE_CATALOG_DESIGN_PRINCIPLES.md](./EXERCISE_CATALOG_DESIGN_PRINCIPLES.md) | Übung als Kernobjekt; Varianten, Governance, Progressionsgraph, Kombinationsübungen. | — |
| 8 | Skill Scoring | [SKILL_SCORING_DESIGN_PRINCIPLES.md](./SKILL_SCORING_DESIGN_PRINCIPLES.md) | Regelbasiertes gewichtetes Profil; Peer-Vergleich nur unter gleichem Artefakttyp. | #2 Data Layer (teilweise) |
| 9 | Training Planning | [TRAINING_PLANNING_DESIGN_PRINCIPLES.md](./TRAINING_PLANNING_DESIGN_PRINCIPLES.md) | Einheiten mit Phasen/Streams; Rahmen-Bibliothek + Module; Coach/Durchführung getrennt. | — |
| 10 | Content Reports (P-13) | [CONTENT_REPORTS_DESIGN_PRINCIPLES.md](./CONTENT_REPORTS_DESIGN_PRINCIPLES.md) | Melde-Workflow in Posteingang; Priorität sensibler Gründe; Legal-Hold-Anschluss. | — |
| 11 | Wiki Import | [WIKI_IMPORT_DESIGN_PRINCIPLES.md](./WIKI_IMPORT_DESIGN_PRINCIPLES.md) | SMW-API-Ingest + Mapper; Preview/Dry-Run; Duplikat-Tracking — kein Raw-Wiki in DB. | #6 Universal Import |
| 12 | Navigation / IA | [NAVIGATION_IA_DESIGN_PRINCIPLES.md](./NAVIGATION_IA_DESIGN_PRINCIPLES.md) | `appNav.js` als SSoT; Admin-Hub horizontal; Onboarding-Nav ohne Verein. | #8 Navigation / IA |
| 13 | Migration & Deploy | [MIGRATION_DEPLOY_DESIGN_PRINCIPLES.md](./MIGRATION_DEPLOY_DESIGN_PRINCIPLES.md) | `XXX_*.sql` beim Container-Start; develop/main → Dev/Prod; fail-fast. | #9 Migration & Deploy |
| 14 | Dashboard KPIs | [DASHBOARD_KPI_DESIGN_PRINCIPLES.md](./DASHBOARD_KPI_DESIGN_PRINCIPLES.md) | Aggregierter `/dashboard/kpis`-Roundtrip statt mehrerer Listen-Calls. | #7 Dashboard Widgets (vereinfacht) |
| 15 | Maturity Models | [MATURITY_MODELS_DESIGN_PRINCIPLES.md](./MATURITY_MODELS_DESIGN_PRINCIPLES.md) | Kontextsensitive Matrix-Auflösung; Export/Import-Stack für Admin-Portabilität. | — |
---
## Empfohlene Lesereihenfolge
### Schnellüberblick (45 Min)
1. [ACCESS_LAYER_DESIGN_PRINCIPLES.md](./ACCESS_LAYER_DESIGN_PRINCIPLES.md) — Shinkan-Kernunterscheidung zu Mitai
2. [RIGHTS_REGISTRY_DESIGN_PRINCIPLES.md](./RIGHTS_REGISTRY_DESIGN_PRINCIPLES.md) — Meta-Muster für Erweiterbarkeit
3. [MIGRATION_DEPLOY_DESIGN_PRINCIPLES.md](./MIGRATION_DEPLOY_DESIGN_PRINCIPLES.md) — Familien-Basis
### Vollständige Implementierung (neues Produkt)
```
Foundation: (13) Migration & Deploy → (4) Auth → (1) Access Layer → (2) Capabilities → (3) Registry
Domäne: (7) Exercise Catalog → (6) Media → (9) Training Planning → (8) Skill Scoring
Erweiterung: (5) AI Prompt Runtime → (11) Wiki Import → (15) Maturity Models
Compliance: (10) Content Reports
Oberfläche: (12) Navigation → (14) Dashboard KPIs
```
### Nur Familien-Review (Mitai ↔ Shinkan)
| Mitai-Dokument | Shinkan-Gegenstück | Review-Fokus |
|----------------|-------------------|--------------|
| #1 Prompt Engine | #5 AI Prompt Runtime | Executor-Reife, Registry, Workflows |
| #2 Data Layer | #8 Skill Scoring | Berechnungs-SSoT vs. Router-Duplikat |
| #3 Feature & Entitlement | #2 Capability & Club Features | Subjekt: Profil vs. Verein |
| #4 Registry | #3 Rights Registry | Registrierungsmuster |
| #5 Auth | #4 Auth & Session | Gemeinsamer Code, IDOR-Risiken |
| #6 Universal Import | #11 Wiki Import | Ingest ≠ Interpretation |
| #7 Dashboard Widgets | #14 Dashboard KPIs | Konfigurierbarkeit vs. Aggregation |
| #8 Navigation | #12 Navigation | appNav-Pattern |
| #9 Migration & Deploy | #13 Migration & Deploy | Gleiches Startup-Muster |
---
## Querschnittsthemen (über alle Docs)
| Thema | Primär | Ergänzend |
|-------|--------|-----------|
| Mandanten-Isolation (`club_id`) | #1 Access Layer | #6 Media, #7 Exercise, #9 Planning |
| Sichtbarkeit `private`/`club`/`official` | #1 Access Layer | #6 Media, #7 Exercise |
| Capability-Gating | #2 Entitlement | #3 Registry, #5 AI Runtime |
| Validierung an der Grenze | #3 Registry | #6 Inline-Media, #11 Import-Mapper |
| Single Source of Truth (Berechnung) | #8 Skill Scoring | #5 AI Kontext-Builder |
| Dual Registry (Code + DB) | #3 Rights Registry | #2 Capabilities in DB |
| Bekannte Lücken dokumentieren | alle „Nicht übernehmen“ | Endpoint-Audit, Architekturschuld |
---
## Verwandte normative Docs (Shinkan-spezifisch)
| Thema | Agent-Guide / Spec |
|-------|-------------------|
| Zugriffsschicht | [ACCESS_LAYER_AND_GOVERNANCE_PLAN.md](../../../.claude/docs/technical/ACCESS_LAYER_AND_GOVERNANCE_PLAN.md), [ACCESS_LAYER_ENDPOINT_AUDIT.md](../../../.claude/docs/working/ACCESS_LAYER_ENDPOINT_AUDIT.md) |
| Capabilities | [CAPABILITY_CATALOG.v1.md](../../../.claude/docs/technical/CAPABILITY_CATALOG.v1.md) |
| Vereins-Features | [CLUB_MEMBERSHIP_AND_FEATURES.v1.md](../../../.claude/docs/technical/CLUB_MEMBERSHIP_AND_FEATURES.v1.md) |
| Medien | [MEDIA_ASSETS_AND_ARCHIVE_SPEC.md](../../../.claude/docs/technical/MEDIA_ASSETS_AND_ARCHIVE_SPEC.md) |
| KI-Zielbild | [AI_PROMPT_TARGET_ARCHITECTURE.md](../../../.claude/docs/technical/AI_PROMPT_TARGET_ARCHITECTURE.md) |
| Planung Streams | [PARALLEL_TRAINING_STREAMS_SPEC.md](../../../.claude/docs/technical/PARALLEL_TRAINING_STREAMS_SPEC.md) |
| Skill Scoring | [SKILL_SCORING_SPEC.md](../../../.claude/docs/technical/SKILL_SCORING_SPEC.md) |
| Architektur-Schuld | [docs/architecture/SCHULDEN_UND_REMEDIATION.md](../../architecture/SCHULDEN_UND_REMEDIATION.md) |
---
## Übergabe-Checkliste (Familien-Review)
```
[ ] Pro Modul: Prinzipien vs. Mitai-Gegenstück abgleichen
[ ] Architekturschuld pro Modul in SCHULDEN_UND_REMEDIATION / „Nicht übernehmen“ verknüpfen
[ ] Gemeinsame Familien-Prinzipien aus Übereinstimmungen ableiten
[ ] Abweichungen bewusst dokumentieren (z. B. Vereins- vs. Profil-Entitlements)
[ ] Shared Code (auth.py, db_init) — eine Quelle oder Fork-Drift?
```
---
## Pflege
| Aktion | Wo |
|--------|-----|
| Neues Querschnittsmodul extrahiert | Neues `*_DESIGN_PRINCIPLES.md` + Zeile in Tabelle oben |
| Shinkan-Implementierung ändert Muster | Betroffenes Einzeldokument + ggf. Querschnittstabelle |
| Mitai-Review abgeschlossen | Abschnitt „Familien-Prinzipien“ (separates Doc, Backlog) |
---
## Changelog Index
| Datum | Änderung |
|-------|----------|
| 2026-07-04 | Verweis auf [FAMILY_ENTITLEMENT_MODEL.md](../FAMILY_ENTITLEMENT_MODEL.md) |
| 2026-07-04 | Verweis auf [DESIGN_PRINCIPLES_ALIGNMENT.md](../DESIGN_PRINCIPLES_ALIGNMENT.md) |
| 2026-07-04 | Shinkan-Serie nach `docs/jinkendo-family/design-principles/` verschoben (Familien-Foundation) |
| 2026-07-04 | Index angelegt; Serie 115 aus Shinkan-Ist-Stand extrahiert |

View File

@ -0,0 +1,128 @@
# Exercise Catalog Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Modul „Exercise Catalog“ — Kernobjekt Übung, Varianten, Graphen, Kombination
**Serie:** Designprinzipien für Produktfamilie · Shinkan Dokument 7 von 15
**Mitai-Vergleich:** — (domänenspezifisch)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| API | `backend/routers/exercises.py`, `exercise_progression_graphs.py` |
| Rich-Text | `backend/exercise_rich_text.py` |
| KI | `backend/exercise_ai.py` |
| Frontend | `frontend/src/pages/Exercises*.jsx`, Tab-Formular |
| Specs | `EXERCISES_ARCHITECTURE.md`, `EXERCISES_API_SPEC.md`, Kombinations-Spec |
---
## Modul
**Exercise Catalog**
Shinkans Kernobjekt: Übungen mit mehrdimensionaler Einordnung (Skills, Fokus, Stile), Varianten, Progressionsgraphen, Kombinationsübungen (`method_archetype`, Stationen), Governance und Medien-Anbindung.
---
## Designprinzipien
### 1. Übung als zentrales Aggregate Root
| | |
|---|---|
| **Prinzip** | Varianten, Medien, Skills, Graph-Knoten hängen an `exercises.id` — Owner/Governance auf Eltern-Übung. |
| **Begründung** | Eine Freigabe- und Lösch-Semantik; Varianten ohne eigenen Owner. |
| **Quelle** | `FACHLICHE_NUTZERFUNKTIONEN.md` §4.1, §4.7 |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Große Monolith-Router/Seiten — Refaktor-Roadmap. |
### 2. Tab-Formular statt Scroll-Monolith
| | |
|---|---|
| **Prinzip** | Register: Stammdaten · Anleitung · Einordnung · Kombination · Varianten · Medien — Varianten/Medien erst nach erstem Save. |
| **Begründung** | UX für komplexe Objekte; klare Abhängigkeiten (IDs für Medien/Varianten). |
| **Quelle** | Nutzerfunktionen §4.1 |
| **Tragfähigkeit** | **hoch** (UI-Muster) |
| **Einschränkung** | Frontend-God-Page-Schuld dokumentiert. |
### 3. Mehrdimensionale Filter-SSoT
| | |
|---|---|
| **Prinzip** | Suche/Filter über Skills, Fokus, Stil, Zielgruppe, Status, Freigabelevel — Backend-Query + gespeicherte Präferenzen. |
| **Begründung** | Trainer finden Inhalte in großen Vereins-Katalogen. |
| **Quelle** | `SEARCH_FILTER_SPEC.md`; `exercises.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Performance schwere Listen — Baseline/Roadmap. |
### 4. Varianten mit Voraussetzungskette
| | |
|---|---|
| **Prinzip** | `exercise_variants` mit Reihenfolge, optional `prerequisite_variant_id`. |
| **Begründung** | Didaktische Abstufung innerhalb einer Übung. |
| **Quelle** | Migration 030; Planung nutzt Varianten-ID pro Eintrag |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 5. Progressionsgraph als gerichtete Übungs-Beziehungen
| | |
|---|---|
| **Prinzip** | Knoten = Übungen/Varianten; Kanten = „weiter“-Beziehungen; eigener Router + UI in Übungswelt. |
| **Begründung** | Didaktik und Planungs-KI nutzen denselben Graph. |
| **Quelle** | `exercise_progression_graphs.py`; `PLANNING_PROGRESSION_GRAPH_KI.md` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Graph-Editor-Komplexität; KI-Artefakte separat. |
### 6. Kombinationsübungen als Sonderform im gleichen Katalog
| | |
|---|---|
| **Prinzip** | `exercise_type=combination` mit Stationen, `method_archetype`, optionalem `method_profile`. |
| **Begründung** | In Planung wie normale Übung; Coach zeigt Stations-Layer. |
| **Quelle** | Migration 056/057; Kombinations-Spec V2 |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Archetyp-Stufen B/C noch ausbaubar. |
### 7. Governance integriert (nicht separates CMS)
| | |
|---|---|
| **Prinzip** | `visibility`, `status` (draft/review/…), Access-Layer-Lösch/Transition-Regeln. |
| **Begründung** | Trainer-Workflow ohne externes Freigabe-Tool. |
| **Quelle** | `club_tenancy.py`; Content Change Requests → Posteingang |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Formales Review-Workflow noch leichtgewichtig. |
### 8. Rich-Text-Felder mit Inline-Medien
| | |
|---|---|
| **Prinzip** | Einheitliche Platzhalter/Render für `summary`, `goal`, `execution`, … |
| **Begründung** | Medienreicher Inhalt ohne iframe-Split. |
| **Quelle** | `exercise_rich_text.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
---
## Nicht übernehmen
1. **Varianten mit eigenem Owner/Freigabe** — widerspricht Domänenmodell.
2. **Übungsliste ohne Tenant-Filter** — Access-Layer-Pflicht.
3. **KI-generierte Übungen ohne Governance-Felder** — immer draft/private Default.
4. **Progressionsgraph-Logik im Frontend allein** — Server validiert Kanten.
---
## Verwandte Dokumentation
- [EXERCISES_ARCHITECTURE.md](../../../.claude/docs/technical/EXERCISES_ARCHITECTURE.md)
- [MEDIA_ASSETS_DESIGN_PRINCIPLES.md](./MEDIA_ASSETS_DESIGN_PRINCIPLES.md)
- [SKILL_SCORING_DESIGN_PRINCIPLES.md](./SKILL_SCORING_DESIGN_PRINCIPLES.md)
- [DESIGN_PRINCIPLES_INDEX.md](./DESIGN_PRINCIPLES_INDEX.md)

View File

@ -0,0 +1,117 @@
# Maturity Models Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Modul „Maturity Models / Fähigkeitsmatrix“ — kontextsensitive Auflösung
**Serie:** Designprinzipien für Produktfamilie · Shinkan Dokument 15 von 15
**Mitai-Vergleich:** — (domänenspezifisch)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| API | `backend/routers/maturity_models.py`, `matrix_editor.py`, `matrix_stack_bundle.py` |
| Admin-UI | `/admin/maturity-models` |
| Import | Wiki-Import Typ Modelle; Matrix-Stack Export/Import |
| Spec | `.claude/docs/technical/SKILLS_MATRIX_SPEC.md` |
---
## Modul
**Maturity Models & Matrix Stack**
Matrixbasierte Reifegradmodelle mit Stufen und Zelltexten; kontextsensitive Auflösung über Bindings (Fokusbereich, Stilrichtung, Zielgruppe); Admin-Export/Import einzelner Modelle und Komplett-Stack.
---
## Designprinzipien
### 1. Kontext-Bindings M:N (leer = überall)
| | |
|---|---|
| **Prinzip** | Modell verknüpft mit Fokus/Stil/Zielgruppe; leere Bindings = global gültig. |
| **Begründung** | Ein Stack deckt mehrere Trainingskontexte ab. |
| **Quelle** | `maturity_models.py` `_attach_context` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Auflösungs-Priorität bei mehreren Treffern dokumentieren. |
### 2. Resolve-API für Laufzeit-Nutzung
| | |
|---|---|
| **Prinzip** | Authentifizierte Nutzer listen/auflösen; Admin-only für Roh-ID-GET in Admin-UI. |
| **Begründung** | Trainer sehen passende Matrix; Rohdaten-Edit geschützt. |
| **Quelle** | Router-Docstring; Rollen-Checks |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 3. Matrix-Editor als separates Admin-Tool
| | |
|---|---|
| **Prinzip** | `matrix_editor` Router für Zellbearbeitung — nicht im Trainer-Flow. |
| **Begründung** | Komplexe UI; Plattform-Redaktionsaufgabe. |
| **Quelle** | Admin-Nav „Fähigkeitsmatrix“ |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Frontend-Komplexität — eigene Schuld-Kategorie. |
### 4. Stack-Bundle Export/Import
| | |
|---|---|
| **Prinzip** | `matrix_stack_bundle` — Komplett-Stack zwischen Umgebungen (Dev→Prod, Backup). |
| **Begründung** | Analog Prompt Import/Export — Konfiguration versionierbar außerhalb DB. |
| **Quelle** | Admin-Werkzeuge; Wiki-Import ergänzt |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Kein Diff/Merge wie Mitai Prompt-Import. |
### 5. Plattform-Admin-Schreibschutz
| | |
|---|---|
| **Prinzip** | Schreiben nur `admin`/`superadmin`; Lesen breiter für authentifizierte Nutzer (Resolve). |
| **Begründung** | Offizielle Kompetenzrahmen zentral gepflegt. |
| **Quelle** | `_require_admin` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 6. Integration Wiki-Import für Modelle
| | |
|---|---|
| **Prinzip** | SMW-Kategorie Modelle → Import-Pfad neben Übungen/Skills. |
| **Begründung** | Bestehende Wissensbasis karatetrainer.net nutzen. |
| **Quelle** | `import_wiki.py` `CATEGORY_MODELS` |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Gap-Analyse SMW — nicht alle Wiki-Felder gemappt. |
### 7. Orthogonal zu Skill Scoring
| | |
|---|---|
| **Prinzip** | Matrix = beschreibende Stufen; Skill Scoring = gewichtete Übungs-Aggregation — getrennte Module. |
| **Begründung** | Keine Vermischung von Kompetenz-Raster und Trainings-KPI. |
| **Quelle** | Domänen-Trennung in Specs |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | UI kann beides nebenan zeigen — klare Labels nötig. |
---
## Nicht übernehmen
1. **Matrix-Zellen in Übungs-Score-Formel mischen** — ohne fachliche Spec.
2. **Trainer-Edit globaler offizieller Matrizen** — Admin-only.
3. **Import ohne Stack-Integrität** — Bundle-Validierung beachten.
4. **Resolve ohne Kontext-Parameter** wenn Mehrdeutigkeit — falsche Matrix.
---
## Verwandte Dokumentation
- [SKILLS_MATRIX_SPEC.md](../../../.claude/docs/technical/SKILLS_MATRIX_SPEC.md)
- [WIKI_IMPORT_DESIGN_PRINCIPLES.md](./WIKI_IMPORT_DESIGN_PRINCIPLES.md)
- [SKILL_SCORING_DESIGN_PRINCIPLES.md](./SKILL_SCORING_DESIGN_PRINCIPLES.md)
- [DESIGN_PRINCIPLES_INDEX.md](./DESIGN_PRINCIPLES_INDEX.md)

View File

@ -0,0 +1,119 @@
# Media Assets & Archiv Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Modul „Media Assets & Archiv“ — physische Medien, Lifecycle, Inline
**Serie:** Designprinzipien für Produktfamilie · Shinkan Dokument 6 von 15
**Mitai-Vergleich:** — (Mitai hat kein vergleichbares Medien-Archiv)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| API | `backend/routers/media_assets.py`, `platform_media_storage.py` |
| Speicher | `backend/media_storage.py`, `MEDIA_ROOT` |
| Rechte/Audit | `backend/media_rights.py`, `media_legal_hold.py` |
| Inline Rich-Text | `backend/exercise_rich_text.py` |
| Retention-Job | `backend/scripts/media_retention_job.py` |
| Spec | `.claude/docs/technical/MEDIA_ASSETS_AND_ARCHIVE_SPEC.md` |
---
## Modul
**Media Assets & Archiv**
Zentrale Verwaltung physischer Dateien (`media_assets`), Verknüpfung zu Übungen (`exercise_media`), mehrstufiger Lifecycle (Papierkorb, Legal Hold), Inline-Einbettung in Rich-Text.
---
## Designprinzipien
### 1. Physisches Asset einmal, mehrfach verknüpft
| | |
|---|---|
| **Prinzip** | Datei in `media_assets`; Übungen referenzieren via `exercise_media.media_asset_id`. |
| **Begründung** | Keine Dubletten auf Platte; Wiederverwendung im Archiv. |
| **Quelle** | `MEDIA_ASSETS_AND_ARCHIVE_SPEC.md` §1 |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Legacy-Pfade ohne Asset-ID können noch existieren. |
### 2. Gleiche Visibility-Semantik wie Übungen
| | |
|---|---|
| **Prinzip** | `private`/`club`/`official` + `club_id` — Access Layer für Download und Liste. |
| **Begründung** | Ein Freigabemodell für alle Bibliotheksartefakte. |
| **Quelle** | Spec §4; `media_rights.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Promotion Übung→official muss Assets mithheben — UI-Dialog Pflicht. |
### 3. Lifecycle getrennt von Übungs-Verknüpfung
| | |
|---|---|
| **Prinzip** | Verknüpfung in Übung lösen ≠ Asset physisch löschen; Papierkorb-Stufen separat. |
| **Begründung** | Trainer dürfen Link entfernen ohne Archiv-Löschrecht. |
| **Quelle** | Spec §5 |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Retention-Job muss in Betrieb überwacht werden. |
### 4. Legal Hold blockiert automatisierten Lifecycle
| | |
|---|---|
| **Prinzip** | `legal_hold` schützt Asset vor Purge; Anbindung an Content Reports (Superadmin). |
| **Begründung** | Compliance bei Meldungen (P-11/P-13). |
| **Quelle** | `media_legal_hold.py`; `content_reports.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 5. Inline-Medien: kanonisches Markup + Validierung
| | |
|---|---|
| **Prinzip** | `{{exerciseMedia:id}}``<span data-shinkan-exercise-media="id">`; IDs müssen zur Übung gehören. |
| **Begründung** | Ein Render-Pfad; keine broken References nach Medien-Löschung. |
| **Quelle** | `exercise_rich_text.py`; Spec §11 |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Beim Erst-Anlegen der Übung keine Inline-Refs (Chicken-Egg). |
### 6. Speicher-Abstraktion (local + konfigurierbarer Root)
| | |
|---|---|
| **Prinzip** | `get_effective_media_root()` + `library/…`-Pfadkonvention; kein hardcodierter `/app/media` in Routern. |
| **Begründung** | NAS/externer Speicher vorbereitet. |
| **Quelle** | `media_storage.py`; `platform_media_storage` |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | S3-Backend noch nicht vollständig. |
### 7. Audit-Log für sensitive Aktionen
| | |
|---|---|
| **Prinzip** | `media_asset_audit_log` bei Meldungen, Hold, kritischen Lifecycle-Events. |
| **Begründung** | Nachvollziehbarkeit für Admins und Compliance. |
| **Quelle** | `media_rights.write_audit_log_entry` |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Nicht jede Admin-Aktion geloggt. |
---
## Nicht übernehmen
1. **Download nur mit Übungs-ID ohne Asset-Governance** — Seitenkanal-Risiko.
2. **Copyright leer bei `official`** — Spec verbietet das fachlich.
3. **Physisches Löschen bei Referenzanzahl > 0** — Spec §5.3.
4. **Embed-URLs durch Lifecycle-Purge** — Embeds haben anderen Lebenszyklus.
---
## Verwandte Dokumentation
- [MEDIA_ASSETS_AND_ARCHIVE_SPEC.md](../../../.claude/docs/technical/MEDIA_ASSETS_AND_ARCHIVE_SPEC.md)
- [ACCESS_LAYER_DESIGN_PRINCIPLES.md](./ACCESS_LAYER_DESIGN_PRINCIPLES.md)
- [CONTENT_REPORTS_DESIGN_PRINCIPLES.md](./CONTENT_REPORTS_DESIGN_PRINCIPLES.md)
- [DESIGN_PRINCIPLES_INDEX.md](./DESIGN_PRINCIPLES_INDEX.md)

View File

@ -0,0 +1,117 @@
# Migration & Deploy Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Modul „Migration & Deploy“ — Schema-Evolution, Container-Start
**Serie:** Designprinzipien für Produktfamilie · Shinkan Dokument 13 von 15
**Mitai-Vergleich:** [MIGRATION_DEPLOY_DESIGN_PRINCIPLES.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/technical/MIGRATION_DEPLOY_DESIGN_PRINCIPLES.md) (#9)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| DB-Init | `backend/db_init.py` |
| Migrationen | `backend/migrations/XXX_*.sql` |
| Version | `backend/version.py` (`DB_SCHEMA_VERSION`, `MODULE_VERSIONS`) |
| Docker | `docker-compose.yml`, `docker-compose.dev-env.yml` |
| Deploy | develop → dev.shinkan · main → shinkan (Pi) |
---
## Modul
**Migration & Deploy**
Nummerierte SQL-Migrationen beim Container-Start, Tracking in `schema_migrations`, Git-Branch → Umgebung, fail-fast ohne Auto-Rollback.
---
## Designprinzipien
### 1. Nummerierte Migrationen `XXX_*.sql`
| | |
|---|---|
| **Prinzip** | Nur nummerierte Dateien in `backend/migrations/`; lexikographische Reihenfolge. |
| **Begründung** | Familien-Standard Mitai/Shinkan; vorhersagbare Anwendung. |
| **Quelle** | `db_init.py`; `CLAUDE.md` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Manuelle Nummern-Kollisionen vermeiden — Team-Disziplin. |
### 2. Startup vor App — Migrationen blockieren Start bei Fehler
| | |
|---|---|
| **Prinzip** | `db_init.py` wartet auf Postgres, wendet fehlende Migrationen an, dann FastAPI. |
| **Begründung** | Keine App mit veraltetem Schema. |
| **Quelle** | Container-Entrypoint / startup |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Kein automatisches Rollback — manuelle Recovery. |
### 3. `schema_migrations` Tracking-Tabelle
| | |
|---|---|
| **Prinzip** | Jede angewendete Datei wird persistiert; Wiederholung überspringt Bekannte. |
| **Begründung** | Idempotenz über Deploys hinweg. |
| **Quelle** | `ensure_migration_table`, `get_applied_migrations` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Geänderte Migration nach Apply — nicht neu ausführen (neue Nummer). |
### 4. `DB_SCHEMA_VERSION` als dokumentierter Stand
| | |
|---|---|
| **Prinzip** | `version.py` führt Schema-Version; MODULE_VERSIONS für Subsysteme. |
| **Begründung** | Support und Handover wissen erwarteten Stand. |
| **Quelle** | `backend/version.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Manuell pflegen bei Migration — Drift möglich. |
### 5. develop/main → Dev/Prod mit festen Ports
| | |
|---|---|
| **Prinzip** | Dev 3098/8098 · Prod 3003/8003 — nie ändern ohne explizite Freigabe. |
| **Begründung** | Deploy-Infrastruktur auf Pi/Synology stabil. |
| **Quelle** | `CLAUDE.md` Deployment |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 6. Neue Spalten nur via Migration
| | |
|---|---|
| **Prinzip** | Kein ad-hoc ALTER in Routern; Coding Rules. |
| **Begründung** | Reproduzierbare Umgebungen. |
| **Quelle** | `.claude/rules/CODING_RULES.md` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 7. IF NOT EXISTS / defensive SQL wo sinnvoll
| | |
|---|---|
| **Prinzip** | Migrationen tolerant bei Wiederanlauf in Dev — aber Tracking verhindert Doppel-Apply. |
| **Begründung** | Recovery in Entwicklung erleichtern. |
| **Quelle** | Mitai-Migrations-Muster |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Nicht alles idempotent — komplexe Migrationen brauchen Transaktion. |
---
## Nicht übernehmen
1. **Manuelle psql-Schritte in Prod** ohne nummerierte Migration im Repo.
2. **Schema-Drift nur in schema.sql** ohne Migration — Init vs. Upgrade verwechseln.
3. **Auto-Rollback bei fehlgeschlagener Migration** — fail-fast, manuell fixen.
4. **Port-Änderung ohne Infra-Update** — bricht Fritz!Box/NAS-Routing.
---
## Verwandte Dokumentation
- [DATABASE_SCHEMA.md](../../../.claude/docs/technical/DATABASE_SCHEMA.md)
- Mitai: [MIGRATION_DEPLOY_DESIGN_PRINCIPLES.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/technical/MIGRATION_DEPLOY_DESIGN_PRINCIPLES.md)
- [DESIGN_PRINCIPLES_INDEX.md](./DESIGN_PRINCIPLES_INDEX.md)

View File

@ -0,0 +1,107 @@
# Navigation / IA Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Modul „Navigation & Information Architecture“
**Serie:** Designprinzipien für Produktfamilie · Shinkan Dokument 12 von 15
**Mitai-Vergleich:** [NAVIGATION_IA_DESIGN_PRINCIPLES.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/technical/NAVIGATION_IA_DESIGN_PRINCIPLES.md) (#8)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| Hauptnav | `frontend/src/config/appNav.js` |
| Admin-Nav | `frontend/src/components/AdminPageNav.jsx` |
| Shells | `RequireAdmin`, App-Layout in `App.jsx` |
| Return-Kontext | `.claude/docs/technical/NAV_RETURN_CONTEXT_SPEC.md` |
| Styles | `frontend/src/app.css` (`.admin-top-nav`, Bottom-Nav) |
---
## Modul
**Navigation / IA**
Single Source of Truth für Hauptnavigation (Mobile Bottom + Desktop Sidebar), separater Admin-Hub, Onboarding-Nav ohne Vereinsfeatures, rollen- und kontextabhängige Einblendung (Posteingang, Admin).
---
## Designprinzipien
### 1. `appNav.js` als SSoT für Hauptnavigation
| | |
|---|---|
| **Prinzip** | `getMainNavItems(isAdmin, opts)` liefert Route, Label, Icon — eine Liste für Mobile und Desktop. |
| **Begründung** | Gleiches Familien-Muster wie Mitai `appNav`; keine divergierenden Nav-Arrays. |
| **Quelle** | `appNav.js` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Tiefe Unterrouten (Übung bearbeiten) nicht in Top-Nav — Shell/Back. |
### 2. Admin als separater Hub
| | |
|---|---|
| **Prinzip** | `/admin/*` mit horizontaler `AdminPageNav` — Plattform-Werkzeuge gebündelt. |
| **Begründung** | Trainer-Nav bleibt schlank; Admin-IA skaliert unabhängig. |
| **Quelle** | `AdminPageNav.jsx` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Admin-Nav hardcoded Array — kein `adminNav.js` SSoT wie Mitai ideal. |
### 3. Onboarding-Nav reduziert
| | |
|---|---|
| **Prinzip** | `getOnboardingNavItems()` — nur Verein + Einstellungen ohne Übungen/Planung. |
| **Begründung** | Nutzer ohne Vereinsmitgliedschaft nicht in leere Bereiche führen. |
| **Quelle** | `appNav.js` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 4. Kontextabhängige Items (Posteingang)
| | |
|---|---|
| **Prinzip** | `showInbox` Flag steuert Posteingang-Eintrag — Berechtigung aus Entitlements/Rolle. |
| **Begründung** | Kein toter Nav-Link für Trainer ohne Inbox-Recht. |
| **Quelle** | `baseItems({ showInbox })` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Logik zur `showInbox`-Setzung in App.jsx pflegen. |
### 5. Responsive: Bottom-Nav Mobile, Sidebar Desktop
| | |
|---|---|
| **Prinzip** | Gleiche Items, unterschiedliche Präsentation; CSS-Variablen für Abstände. |
| **Begründung** | PWA-typisches Muster; 80px Bottom-Padding für Nav. |
| **Quelle** | `app.css`; Design-System in `CLAUDE.md` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Breakpoint-Konsistenz mit Mitai (1024px) prüfen beim Familien-Review. |
### 6. Return-Kontext für tiefe Bearbeitung
| | |
|---|---|
| **Prinzip** | Spez `NAV_RETURN_CONTEXT_SPEC` — zurück zur Herkunftsliste mit Filter-State. |
| **Begründung** | Übungs-Editor aus Suche/Planung ohne Navigations-Verlust. |
| **Quelle** | Return-Context Spec |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Nicht alle Flows implementiert. |
---
## Nicht übernehmen
1. **Zwei unterschiedliche Nav-Arrays** für Mobile vs. Desktop.
2. **Admin-Routen in Haupt-Bottom-Nav** mischen (außer ein Admin-Einstieg).
3. **Hardcodierte Nav in jeder Page** — zentral in `appNav.js`.
4. **Fehlender Onboarding-Gate** — volle Nav ohne Verein verwirrt.
---
## Verwandte Dokumentation
- [NAV_RETURN_CONTEXT_SPEC.md](../../../.claude/docs/technical/NAV_RETURN_CONTEXT_SPEC.md)
- Mitai: [NAVIGATION_IA_DESIGN_PRINCIPLES.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/technical/NAVIGATION_IA_DESIGN_PRINCIPLES.md)
- [DESIGN_PRINCIPLES_INDEX.md](./DESIGN_PRINCIPLES_INDEX.md)

View File

@ -0,0 +1,114 @@
# Rights Registry Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Modul „Rights Registry“ — Capabilities & Features zur Laufzeit registrieren
**Serie:** Designprinzipien für Produktfamilie · Shinkan Dokument 3 von 15
**Mitai-Vergleich:** [REGISTRY_PLUGIN_DESIGN_PRINCIPLES.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/technical/REGISTRY_PLUGIN_DESIGN_PRINCIPLES.md) (#4)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| Registry-Kern | `backend/rights_registry.py` |
| Modul-Registrierungen | `backend/rights_registrations/` (`exercises.py`, `planning.py`, `platform.py`, `club_creation.py`) |
| Startup-Sync | Import in `backend/main.py` |
| Tests | `backend/tests/test_rights_registry.py` |
---
## Modul
**Rights Registry (Registry-first für Capabilities & Features)**
Module deklarieren bei Implementierung, welche Rechte und Kontingente sie anbieten. Beim App-Start werden Definitionen in die DB synchronisiert (`capabilities`, `features`, Default-Grants).
---
## Fachliche Verantwortung
1. **Runtime-Registrierung**`register_capability()`, `register_feature()` vor DB-Sync.
2. **Modul-Ownership** — Jedes Feature/Capability trägt `module`-Feld für Admin-Filter „Rollen & Rechte“.
3. **Default Club Grants** — Rollen → Capability-Mapping bei Erst-Sync.
4. **Kein vollständiger Vorab-Katalog in SQL-Migration** — nur was Module wirklich liefern.
---
## Designprinzipien
### 1. Registry-first statt Migrations-Monolith
| | |
|---|---|
| **Prinzip** | Neue Rechte erscheinen durch Code-Registrierung + Startup-Upsert — nicht durch manuelle 079-Katalog-Migration pro Feature. |
| **Begründung** | Modul und Recht entstehen zusammen; weniger vergessene Katalog-Einträge. |
| **Quelle** | `rights_registry.py`; Docstring; `rights_registrations/` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Erste Basismigration seedet noch initiale Zeilen. |
### 2. Modul-Datei pro Domäne
| | |
|---|---|
| **Prinzip** | `rights_registrations/exercises.py` registriert nur Übungs-Rechte; Planung/Platform analog. |
| **Begründung** | Ownership klar; Merge-Konflikte lokalisiert. |
| **Quelle** | `rights_registrations/__init__.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Import-Reihenfolge muss in `main.py` garantiert sein. |
### 3. Frozen Dataclass-Definitionen
| | |
|---|---|
| **Prinzip** | `CapabilityRegistration` / `FeatureRegistration` als immutable `@dataclass(frozen=True)`. |
| **Begründung** | Keine nachträgliche Mutation nach Registrierung. |
| **Quelle** | `rights_registry.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 4. Validierung an der Registrierungsgrenze
| | |
|---|---|
| **Prinzip** | `register_*` wirft bei fehlendem `id` oder `module`. |
| **Begründung** | Fehler beim Import/Startup, nicht erst im Admin-UI. |
| **Quelle** | `rights_registry.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Keine Schema-Validierung für `limit_type`/`reset_period` zur Compile-Zeit. |
### 5. DB als persistierter Katalog, Code als SSoT für neue IDs
| | |
|---|---|
| **Prinzip** | Startup `sync_rights_registry_to_db()` upsertet aus In-Memory-Registry. |
| **Begründung** | Admin-UI liest DB; Entwickler erweitern Code-Registry. |
| **Quelle** | `rights_registry.py`; `main.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Deaktivierte Capabilities in DB vs. fehlende im Code — Reconcile-Policy dokumentieren. |
### 6. Default Grants als Code-Daten
| | |
|---|---|
| **Prinzip** | `default_club_grants: (role_code, capability_id)` pro Capability. |
| **Begründung** | Neue Module bringen sinnvolle Standard-Rollen mit. |
| **Quelle** | `rights_registrations/exercises.py` |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Admin-Overrides in DB können bei Re-Sync überschrieben werden — ON CONFLICT-Verhalten beachten. |
---
## Nicht übernehmen
1. **Capabilities nur in SQL-Migration pflegen** — driftet vom implementierten Modul weg.
2. **Registrierung ohne Endpoint-Verdrahtung** — Spec: „nur Rechte mit echter Endpoint-Verdrahtung“.
3. **Zweite Registry-Philosophie** für Custom Roles — gleiche Capability-IDs wiederverwenden (Plan Stufe E).
---
## Verwandte Dokumentation
- [CAPABILITY_ENTITLEMENT_DESIGN_PRINCIPLES.md](./CAPABILITY_ENTITLEMENT_DESIGN_PRINCIPLES.md)
- [CAPABILITY_CATALOG.v1.md](../../../.claude/docs/technical/CAPABILITY_CATALOG.v1.md)
- [DESIGN_PRINCIPLES_INDEX.md](./DESIGN_PRINCIPLES_INDEX.md)

View File

@ -0,0 +1,107 @@
# Skill Scoring Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Modul „Skill Scoring & Profile“ — gewichtete Fähigkeiten-KPIs
**Serie:** Designprinzipien für Produktfamilie · Shinkan Dokument 8 von 15
**Mitai-Vergleich:** [DATA_LAYER_DESIGN_PRINCIPLES.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/technical/DATA_LAYER_DESIGN_PRINCIPLES.md) (#2, analog: Berechnungs-SSoT)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| Kern | `backend/skill_scoring.py` |
| Profile-API | `backend/routers/skill_profiles.py` |
| Planungs-Vorschläge | Planung-Router + Fähigkeiten-Seite |
| Spec | `.claude/docs/technical/SKILL_SCORING_SPEC.md` |
---
## Modul
**Skill Scoring & Profiles**
Regelbasierte Aggregation von `exercise_skills` über Artefakte (Module, Rahmenprogramme, Pläne, Graphen) zu gewichteten Profilen mit Peer-Vergleich innerhalb desselben Artefakttyps.
---
## Designprinzipien
### 1. Berechnung in einer Schicht (`skill_scoring.py`)
| | |
|---|---|
| **Prinzip** | Scores, Gewichte, Peer-Perzentile — nicht in React oder Router-SQL duplizieren. |
| **Begründung** | Analog Mitai Data Layer: Charts, Listen-KPIs, Planungs-Vorschläge nutzen dieselbe Logik. |
| **Quelle** | `SKILL_SCORING_SPEC.md`; `skill_scoring.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Einzelne UI-Fallbacks können noch vereinfacht rechnen. |
### 2. Gewichtung aus Trainings-Signalen
| | |
|---|---|
| **Prinzip** | Dauer, Vorkommen, Intensität (`niedrig`/`mittel`/`hoch`), Stufen-Spanne — explizite Multiplikatoren. |
| **Begründung** | Nachvollziehbares Ranking ohne Black-Box-ML. |
| **Quelle** | `_INTENSITY_MULT`, `_level_range_multiplier` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | `is_primary` / `development_contribution` bewusst ignoriert. |
### 3. Peer-Vergleich nur unter gleichem Artefakttyp
| | |
|---|---|
| **Prinzip** | Modul vs. Modul, Rahmen vs. Rahmen — nie Modul vs. Plan gemischt. |
| **Begründung** | Fachlich sinnvoller Vergleich; vermeidet irreführende Prozentwerte. |
| **Quelle** | Phase 3 Lieferung; Nutzerfunktionen §4.2 |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | UI muss Typ-Kontext klar labeln. |
### 4. Sichtbarkeits-filterte Peer-Menge
| | |
|---|---|
| **Prinzip** | Peer-Pool = nur für Nutzer sichtbare Artefakte (Access Layer). |
| **Begründung** | Keine Leaks über Scores fremder Vereins-Inhalte. |
| **Quelle** | `skill_scoring.py` + Tenant-Filter in Aufrufern |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Performance bei großen Pools. |
### 5. Planungs-Vorschläge aus Profil-Delta
| | |
|---|---|
| **Prinzip** | Fähigkeiten-Schwerpunkte → sortierte Vorschläge für Module/Rahmen/Regressionspfade. |
| **Begründung** | Schließt Loop zwischen Katalog und Planung. |
| **Quelle** | Fähigkeiten-Seite Phase 3 |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | KI-Suche über Volltext — Backlog. |
### 6. Default-Minuten für fehlende Dauer
| | |
|---|---|
| **Prinzip** | `DEFAULT_ITEM_MINUTES` / `GRAPH_DEFAULT_ITEM_MINUTES` als explizite Konstanten. |
| **Begründung** | Deterministische Scores bei unvollständigen Planungsdaten. |
| **Quelle** | `skill_scoring.py` |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Fachlich kalibrierbar — dokumentieren statt verstecken. |
---
## Nicht übernehmen
1. **Score-Berechnung im Frontend** für Listen-KPIs.
2. **Peer-Vergleich über Artefakttypen hinweg** — irreführend.
3. **ML-Black-Box statt regelbasierter Gewichte** — ohne explizite Produktentscheidung.
4. **Ignorieren der Tenant-Sichtbarkeit** im Peer-Pool.
---
## Verwandte Dokumentation
- [SKILL_SCORING_SPEC.md](../../../.claude/docs/technical/SKILL_SCORING_SPEC.md)
- [EXERCISE_CATALOG_DESIGN_PRINCIPLES.md](./EXERCISE_CATALOG_DESIGN_PRINCIPLES.md)
- [TRAINING_PLANNING_DESIGN_PRINCIPLES.md](./TRAINING_PLANNING_DESIGN_PRINCIPLES.md)
- [DESIGN_PRINCIPLES_INDEX.md](./DESIGN_PRINCIPLES_INDEX.md)

View File

@ -0,0 +1,129 @@
# Training Planning Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Modul „Training Planning“ — Einheiten, Phasen, Rahmen, Coach
**Serie:** Designprinzipien für Produktfamilie · Shinkan Dokument 9 von 15
**Mitai-Vergleich:** — (domänenspezifisch)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| Kalender-Einheiten | `backend/routers/training_planning.py` |
| Module | `backend/routers/training_modules.py` |
| Rahmen | `backend/routers/training_framework_programs.py` |
| Phasen/Streams | Migration 063; `PARALLEL_TRAINING_STREAMS_SPEC.md` |
| Frontend | `TrainingPlanningPage`, `TrainingCoachPage`, `TrainingUnitRunPage` |
| Utils | `frontend/src/utils/trainingPlanUtils.js` |
---
## Modul
**Training Planning & Frameworks**
Planbare Trainingseinheiten mit Sektionen, **Phasen** (Ganzgruppe/Parallel) und **Streams**, Bibliotheks-**Rahmenprogramme** (Ziele/Slots), **Trainingsmodule**, Materialisierung aus Slots, Durchführungs- und Coaching-Ansichten.
---
## Designprinzipien
### 1. Einheit als planbares Aggregate
| | |
|---|---|
| **Prinzip** | `training_units` + `training_unit_sections` + Items; Kopf: Gruppe, Datum, Trainer, Status. |
| **Begründung** | Klare Grenze Kalender vs. Bibliothek. |
| **Quelle** | Domain Model; `training_planning.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Große Router-Datei — Refaktor-Schuld. |
### 2. Phasen/Streams als explizites Modell (nicht Marker-Sektionen)
| | |
|---|---|
| **Prinzip** | `training_unit_phases` + `training_unit_parallel_streams`; Sektionen an Phase oder Stream gebunden. |
| **Begründung** | Breakout-Trainings fachlich korrekt; Coach/Rejoin-Logik. |
| **Quelle** | `PARALLEL_TRAINING_STREAMS_SPEC.md` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Legacy-Einheiten → Default-Ganzgruppenphase; Vorlagen-Phasen teils offen. |
### 3. API: verschachtelte `phases` + flache `sections`
| | |
|---|---|
| **Prinzip** | GET liefert beides; PUT akzeptiert `phases` atomar; höchstens eines von phases/sections/exercises pro Request. |
| **Begründung** | Frontend normalisiert; Server validiert CHECK-Regeln. |
| **Quelle** | Spec §4; Planning-Router |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Server-Spiegelung neuer Abschnitte in phases — Handover offen. |
### 4. Rahmen-Bibliothek: Slot = Blueprint-Unit
| | |
|---|---|
| **Prinzip** | `framework_slot_id` auf Blueprint-`training_units`; Materialisierung → Kalender-Einheit für Gruppe. |
| **Begründung** | Wiederverwendbare Programme ohne Duplikat-Logik pro Slot-Typ. |
| **Quelle** | Migration 035037 |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | UI „Aus Rahmen übernehmen“ nicht flächendeckend. |
### 5. Trainingsmodule als wiederverwendbare Übungsfolgen
| | |
|---|---|
| **Prinzip** | Bibliotheks-Objekt mit Skill-Profil; Übernahme in geplante Einheit. |
| **Begründung** | Trainer-Bausteine zwischen Einzelübung und Rahmen. |
| **Quelle** | `training_modules.py`; Skill Scoring Phase 3 |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 6. Drei Durchführungsmodi getrennt
| | |
|---|---|
| **Prinzip** | Planung (edit) · Plan & Ablauf (run) · Coaching (step timeline, Stream-Picks, Nachbereitung). |
| **Begründung** | Unterschiedliche UX und Payloads; Coach speichert → Run-Ansicht. |
| **Quelle** | Nutzerfunktionen §4.4; `TrainingCoachPage` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Stream-Tabs in Run-Ansicht optional offen. |
### 7. Governance über Gruppe/Verein, keine neuen Mandanten-Entitäten
| | |
|---|---|
| **Prinzip** | Einheit → `training_group` → Verein; Access Layer für Bibliotheks-Rahmen/Module. |
| **Begründung** | Planung erbt Organisations-Kontext. |
| **Quelle** | `PARALLEL_TRAINING_STREAMS_SPEC.md` §4 |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Stream-Trainer-Zuweisung UI unvollständig. |
### 8. Kombinationsübungen in Planung transparent
| | |
|---|---|
| **Prinzip** | Items ohne Variante; Coach zeigt Stations-Kandidaten + Archetyp-Hinweise. |
| **Begründung** | Gleiche Item-Schicht für Standard- und Kombi-Übungen. |
| **Quelle** | Migration 057; Kombinations-Spec Anhang A |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Archetyp-Stufen B/C ausbaubar. |
---
## Nicht übernehmen
1. **Parallele Phasen als reine UI-Konvention ohne DB-Phasen** — Minimalvariante verworfen.
2. **Rahmen-Slots als separate Exercise-Join-Tabelle** — Legacy `training_framework_slot_exercises` abgelöst.
3. **Planungs-KI direkt in Router-Strings** — AI Prompt Runtime nutzen.
4. **Blueprint-Einheiten in Kalenderlisten** — Filter `framework_slot_id IS NOT NULL`.
---
## Verwandte Dokumentation
- [PARALLEL_TRAINING_STREAMS_SPEC.md](../../../.claude/docs/technical/PARALLEL_TRAINING_STREAMS_SPEC.md)
- [TRAINING_FRAMEWORK_SPEC.md](../../../.claude/docs/technical/TRAINING_FRAMEWORK_SPEC.md)
- [SKILL_SCORING_DESIGN_PRINCIPLES.md](./SKILL_SCORING_DESIGN_PRINCIPLES.md)
- [DESIGN_PRINCIPLES_INDEX.md](./DESIGN_PRINCIPLES_INDEX.md)

View File

@ -0,0 +1,118 @@
# Wiki Import Designprinzipien (Extraktion)
**Status:** Analyse / Arbeitspapier
**Stand:** 2026-07-04
**Geltungsbereich:** Modul „MediaWiki Import“ — SMW-Ingest, Mapping, Tracking
**Serie:** Designprinzipien für Produktfamilie · Shinkan Dokument 11 von 15
**Mitai-Vergleich:** [UNIVERSAL_IMPORT_DESIGN_PRINCIPLES.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/technical/UNIVERSAL_IMPORT_DESIGN_PRINCIPLES.md) (#6)
**Kernkomponenten:**
| Bereich | Pfade |
|---------|-------|
| Router | `backend/routers/import_wiki.py`, `import_wiki_admin.py` |
| Client | `backend/smw_client.py` |
| Mapper | `backend/smw_mapper.py` |
| Tracking | `wiki_import_log`, `wiki_import_references` |
| Spec | `.claude/docs/technical/MEDIAWIKI_IMPORT_SPEC.md` |
---
## Modul
**Wiki Import (Semantic MediaWiki)**
Import von Übungen, Fähigkeiten, Methoden und Reifegradmodellen aus externem Wiki via API — Preview, Dry-Run, Duplikat-Erkennung, Admin-only.
---
## Designprinzipien
### 1. Ingest ≠ Interpretation
| | |
|---|---|
| **Prinzip** | `SmwClient` holt Rohdaten; `smw_mapper` mappt auf Shinkan-Modelle — getrennte Schichten. |
| **Begründung** | Analog Mitai Import: Transport/Parser ≠ Domänen-Insert. |
| **Quelle** | `import_wiki.py`; Mitai Universal Import |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Keine generische Import-Registry wie Mitai CSV — wiki-spezifisch. |
### 2. Preview und Dry-Run vor Execute
| | |
|---|---|
| **Prinzip** | `/preview` zeigt Kandidaten; `dry_run=true` ohne DB-Schreiben. |
| **Begründung** | Admin sieht Auswirkungen; sichere Iteration. |
| **Quelle** | `ImportExecuteRequest` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 3. Duplikat-Tracking über Wiki-Referenzen
| | |
|---|---|
| **Prinzip** | `wiki_import_references` speichert Wiki-Titel ↔ Shinkan-ID für Re-Import. |
| **Begründung** | Idempotenz und Update statt blindem Duplicate. |
| **Quelle** | Domain Model Import-Tabellen |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Gap-Analyse in `SMW_IMPORTER_GAP_ANALYSIS.md` beachten. |
### 4. Import-Typ als expliziter Parameter
| | |
|---|---|
| **Prinzip** | `import_type`: `exercise` \| `skill` \| `method` \| Modelle — eigener Mapper-Pfad. |
| **Begründung** | Klare Verantwortung pro Ziel-Entität. |
| **Quelle** | `map_wiki_to_*` in `smw_mapper.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | Kein Plug-in-Registry-Pattern wie Mitai Module-Registry. |
### 5. Superadmin/Admin-only Execute
| | |
|---|---|
| **Prinzip** | `require_admin` auf Execute — Massenimport ist Plattform-Risiko. |
| **Begründung** | Governance und Datenqualität. |
| **Quelle** | `import_wiki.py` |
| **Tragfähigkeit** | **hoch** |
| **Einschränkung** | — |
### 6. Kategorie aus Env mit Fallback
| | |
|---|---|
| **Prinzip** | `MEDIAWIKI_CATEGORY_*` Env-Variablen; leere Query → Default je Typ. |
| **Begründung** | Wiki-Struktur konfigurierbar ohne Code-Deploy. |
| **Quelle** | `CATEGORY_EXERCISES` etc. |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Hardcoded Wiki-URL in Doku — Umgebungsspezifisch halten. |
### 7. Background Tasks für lange Imports
| | |
|---|---|
| **Prinzip** | FastAPI `BackgroundTasks` für Execute — HTTP nicht blockieren. |
| **Begründung** | Große Kategorien ohne Timeout. |
| **Quelle** | Execute-Endpoint |
| **Tragfähigkeit** | **mittel** |
| **Einschränkung** | Kein Job-Status-Polling-UI wie Mitai — Log-Tabelle nutzen. |
---
## Nicht übernehmen
1. **Rohe Wiki-HTML ungemappt in DB** — immer Mapper.
2. **Import ohne Log/Re-Import-Referenz** — Duplikat-Chaos.
3. **Trainer-self-service Wiki-Import** — Admin-only.
4. **Skill-Scoring beim Insert** — Scores gehören in `skill_scoring`-Schicht.
---
## Verwandte Dokumentation
- [MEDIAWIKI_IMPORT_SPEC.md](../../../.claude/docs/technical/MEDIAWIKI_IMPORT_SPEC.md)
- [EXERCISE_CATALOG_DESIGN_PRINCIPLES.md](./EXERCISE_CATALOG_DESIGN_PRINCIPLES.md)
- Mitai: [UNIVERSAL_IMPORT_DESIGN_PRINCIPLES.md](file:///c:/Dev/mitai-jinkendo/.claude/docs/technical/UNIVERSAL_IMPORT_DESIGN_PRINCIPLES.md)
- [DESIGN_PRINCIPLES_INDEX.md](./DESIGN_PRINCIPLES_INDEX.md)