Compare commits

...

2 Commits

Author SHA1 Message Date
aa7e1626ea AP1.9b: Scope-Breadcrumb modus-sensitiv für Planen, Ausführen und Kontrolle.
Some checks failed
Test Suite / lint-backend (push) Waiting to run
Test Suite / compose-smoke (push) Waiting to run
Test Suite / k6 /api/health Baseline (push) Blocked by required conditions
Test Suite / playwright-smoke (push) Blocked by required conditions
Deploy Development / deploy (push) Successful in 42s
Test Suite / pytest-backend (push) Has been cancelled
Portfolio- und Vorhaben-Klicks bleiben im aktiven Modus; Objekt-Routen leiten auf passende Plan-/Work-Hubs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-09 11:14:33 +02:00
afb07f70b9 docs: Plan-Modus-Design und ADP AP1.10 (Archetypen, Entity Field System).
Festlegung Vorhaben als Wurzel, Plan-Outline, Modal/DnD, Gate-Graph und Roadmap AP1.9b–AP1.13.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-09 11:13:54 +02:00
8 changed files with 672 additions and 27 deletions

View File

@ -1,3 +1,3 @@
APP_VERSION = "0.16.3-ap1.9a" APP_VERSION = "0.16.4-ap1.9b"
DB_SCHEMA_VERSION = "014" DB_SCHEMA_VERSION = "014"
APP_NAME = "jinkendo-kairo" APP_NAME = "jinkendo-kairo"

View File

@ -0,0 +1,212 @@
# ADP — AP1.10 Initiative-Archetypen & Entity Field System v0.1
**Status:** vorgeschlagen (PO-Freigabe ausstehend)
**Stand:** 2026-07-09
**Autor:** Product/Architektur (PO-Session Planen)
**Bezug:** Vision v0.2, Canonical OM v0.2, `ADP_Recursive_Containers_and_Execution_Granularity_v0.1.md`, `Kairo_Plan_Mode_Design_v0.1.md`
**Auslöser:** Planen braucht beschreibbare Vorhaben/Container; parallele „Unabhängigkeit“ von Objekten erzeugt Navigations- und Daten-Inkonsistenz
---
## Problem
1. **Initiative** hat heute nur `title`, `goal`, `status`, `priority`, `owner_actor_id` — unzureichend für Programm-, Produkt- oder Transformations-Vorhaben (Vision, Zielzustand, Typ-spezifische Attribute).
2. **Dynamische Felder** fehlen zentral; Ad-hoc-JSONB pro Entität würde Retrieval, Indexierung und Agent-Zugriff fragmentieren.
3. **Hierarchie vs. Unabhängigkeit:** Alles operative hängt fachlich an einem Vorhaben, aber UI und Scope suggerierten teils losgelöste Welten — Planen wird unzuverlässig.
4. **Archetypen** (Vorhabentypen) sind nicht modelliert; Vorlagen für Felder und UI können nicht tenant-konfigurierbar werden.
Ohne Entscheidung drohen: hardcodierte Formularfelder, nicht auswertbare Metadaten, erneute Omnibus-CRUD-Seiten.
---
## Betroffene Regeln
| Dokument | Regel |
|----------|--------|
| Vision v0.2 | Initiative = Programm/Vorhaben; Plan vs. Ist getrennt |
| Canonical OM v0.2 | Project optional rekursiv; Action = Arbeitspaket; Gates orthogonal |
| Tenant Invariants | Keine hardcodierte Fachkonfiguration; Mandantenfähigkeit |
| ADP Recursive Containers | `container_kind` = Label; kein eigener Stream-Typ |
| ADP AP1.9 | Modal/Detail für Pflege; keine Inline-CRUD-Wand |
| Principle Gate | Neues OM-Schema nur mit ADP |
---
## PO-Arbeitsentscheidungen (2026-07-09)
| # | Frage | Entscheidung |
|---|--------|--------------|
| D1 | Archetyp nur Initiative oder auch Project? | **Initiative verbindlich**; Project-Templates **Phase 2** (optional `project_archetype_key`) |
| D2 | `goal` vs. `vision` | **`goal`** = Kurzbeschreibung (12 Sätze, bestehend); **`vision`** = ausführliches Zielbild (neu, TEXT) |
| D3 | Flache Vorhaben ohne Project? | **Ja** — Actions dürfen direkt unter Initiative hängen (`project_id` NULL); Plan-Baum zeigt Initiative → Actions |
| D4 | Graph-Inhalt | **Phase 1:** Gates + Dependencies; Project→Gate-Zuordnung in Detail/Liste; **Phase 2:** Project-Knoten im Graph optional |
---
## Optionen (Felder & Archetypen)
| Option | Kurz | Pro | Contra |
|--------|------|-----|--------|
| **A** | Nur mehr Spalten auf `initiatives` | Schnell, indexiert | Keine Typ-Vorlagen; kein Wiederverwendungsmodell für Project |
| **B** | Freies JSONB `metadata` pro Tabelle | Flexibel | Schwer auswertbar; kein Schema-Gate |
| **C** | **Zweischichtig: Standardspalten + zentrales EFS** | Index + Typ-Vorlagen + Agent-API | Migration + Registry-Aufwand |
**Empfehlung: Option C**
---
## Entscheidung (Option C)
### 1. Vorhaben als Wurzel (verbindlich)
Jede operative Entität hat **`initiative_id NOT NULL`** (bereits Schema für Action, Project, Backlog, RoadmapItem).
| Konzept | Regel |
|---------|--------|
| „Unabhängigkeit“ | Nur **Querschnitts-Ansichten** (Ausführen, Cockpit), nie orphan-Objekte |
| Deep Links | `/actions/:id` etc. leiten Scope aus Objekt ab |
| Planen | Scope-pflichtig auf mindestens ein Vorhaben |
### 2. Schicht A — Standardfelder (spaltenbasiert, indexiert)
**Migration `015_initiative_archetypes.sql`** (nummeriert, reproduzierbar):
```sql
-- initiatives (Erweiterung)
ALTER TABLE initiatives ADD COLUMN IF NOT EXISTS vision TEXT NOT NULL DEFAULT '';
ALTER TABLE initiatives ADD COLUMN IF NOT EXISTS target_state_summary TEXT NOT NULL DEFAULT '';
ALTER TABLE initiatives ADD COLUMN IF NOT EXISTS archetype_key VARCHAR(64) NOT NULL DEFAULT 'initiative.generic';
CREATE INDEX IF NOT EXISTS idx_initiatives_archetype ON initiatives(tenant_id, archetype_key);
CREATE INDEX IF NOT EXISTS idx_initiatives_status ON initiatives(tenant_id, status);
-- title bereits vorhanden; goal bleibt
```
**Project (optional Phase 1b):** nur `sort_order` Index falls noch fehlt; `archetype_key` deferred.
Standardfelder pro Typ sind **Pflicht für Listen, Filter, Steering, Breadcrumb-Titel** — nie aus EFS für Hot Paths.
### 3. Schicht B — Entity Field System (EFS)
Zentrale Mandanten-Registry (analog Feature/Capability Registry — **keine** Router-DDL):
| Tabelle | Zweck |
|---------|--------|
| `entity_archetypes` | `key`, `entity_type`, `label`, `description`, `is_system` |
| `field_definitions` | `archetype_key`, `field_key`, `field_type`, `label`, `required`, `searchable`, `sort_order`, `validation_json` |
| `field_values` | `tenant_id`, `entity_type`, `entity_id`, `field_key`, typed columns OR `value_json` + `value_text` Denormalisierung für searchable |
**Feldtypen (v1):** `text`, `longtext`, `number`, `boolean`, `date`, `enum`, `actor_ref`, `url`
**API (v1):**
```text
GET /api/entity-archetypes?entity_type=initiative
GET /api/initiatives/{id}/field-definitions — effektive Definition (Archetyp + Tenant-Overrides später)
GET /api/initiatives/{id}/fields — Werte
PATCH /api/initiatives/{id}/fields — partial update, validiert gegen Definition
```
Gleiche Oberfläche später für `project`, `action`**ein** Service `backend/entity_fields/` (Scope Lock: keine parallele Logik in Routern).
**Retrieval-Strategie:**
| Pfad | Quelle |
|------|--------|
| Listen, Cockpit, Scope-Titel | Spalten Schicht A |
| Detail-Modal, Export, Agent-Kontext | Schicht A + lazy EFS |
| Volltext/Suche auf dynamischen Feldern | nur `searchable=true`; optional GIN auf `value_text`**nicht** MVP-Blocker |
### 4. Archetypen (Initial-Seed, system)
| `archetype_key` | Label | Zusätzliche Standardfelder | Typische EFS-Felder (Seed) |
|-----------------|-------|----------------------------|----------------------------|
| `initiative.generic` | Allgemeines Vorhaben | vision optional | — |
| `initiative.program` | Programm / Mega-Vorhaben | vision, target_state_summary | stakeholder_map, success_criteria |
| `initiative.product` | Produkt / Release | vision, target_state_summary | release_theme, metrics |
Weitere Archetypen nur via Seed/Admin — **nicht** hardcoded im Frontend.
### 5. Frontend-Konsequenz
- Initiative bearbeiten: **Modal** (Plan-Outline oder `/initiatives` Katalog), rendert Schema aus API
- Keine typ-spezifischen React-Formulare hardcoded — **FieldRenderer** aus Definitionen
- Archetyp-Wahl bei Anlage (Dropdown aus Registry)
---
## Scope Lock
| Verboten bis ADP-Freigabe | Erlaubt |
|---------------------------|---------|
| Ad-hoc JSONB-Spalten auf OM-Tabellen für Fachfelder | AP1.9b Scope-Breadcrumb |
| Hardcodierte Vorhabentyp-Forms im Frontend | AP1.12 Plan-Outline (mit bestehenden Feldern) |
| Mitai/Shinkan Domänenlogik kopieren | Referenz-Pattern für Registry |
| Verboten nach Freigabe | Erlaubt |
|------------------------|---------|
| Felddefinitionen in Routern | `backend/entity_fields/` + nummerierte Migration |
| Dynamische Felder in Steering-Heuristiken ohne ADP-Erweiterung | Standardspalten in Steering |
---
## Implementierungspakete
```text
AP1.10a Migration Standardfelder + archetype_key; API read/write Initiative inkl. vision
AP1.10b EFS Tabellen + Registry-Sync + field_definitions Seed
AP1.10c API fields + Validierung + Initiative Modal (FieldRenderer minimal)
AP1.10d Project sort_order API + Plan-Reorder (siehe Plan Mode Design)
```
**Version-Ziel:** `0.17.0-ap1.10a``0.17.x-ap1.10c`
---
## Risiko
| Risiko | Mitigation |
|--------|------------|
| EFS-Overengineering | MVP: 3 System-Archetypen; searchable=false default |
| Performance dynamische Felder | Hot path nur Spalten; EFS lazy |
| Migration bestehender Initiativen | Default `initiative.generic`; leere vision |
| Tenant-Custom-Fields zu früh | Phase 2: Tenant-Overrides auf field_definitions |
---
## Rückbaubarkeit
- Archetyp-Spalte nullable machen / Default behalten
- EFS-Tabellen droppbar ohne OM-Kern zu zerstören
- FieldRenderer isoliert; Fallback auf feste Standardfelder
---
## Auswirkung auf Roadmap
| Paket | Beziehung |
|-------|-----------|
| AP1.9b | Scope-Breadcrumb kontextsensitiv — parallel, kein Blocker |
| AP1.12 | Plan-Outline nutzt 10a Standardfelder; 10c für Modal-Schema |
| AP1.13 | Gate-Graph unabhängig von EFS |
| AP1.5d | Tasks im Plan-Baum nach 12 |
**Nächstes Code nach AP1.9b/c:** AP1.10a (Standardfelder) vor AP1.11/13.
---
## PO-Freigabe
- [ ] Option C (Zweischichtig + EFS) angenommen
- [ ] Archetyp-Seed (generic, program, product) OK
- [ ] D1D4 Entscheidungen bestätigt
- [ ] `backend/entity_fields/` Scope Lock OK
---
## Referenzen
- `docs/product/Kairo_Plan_Mode_Design_v0.1.md`
- `docs/product/Kairo_PM_Frontend_UI_Concept_v0.1.md`
- `docs/architecture/ADP_Recursive_Containers_and_Execution_Granularity_v0.1.md`
- `docs/reference/design-principles/mitai/REGISTRY_PLUGIN_DESIGN_PRINCIPLES.md` (Pattern, kein Scope)

View File

@ -69,7 +69,25 @@ Siehe `ADP_Recursive_Containers_and_Execution_Granularity_v0.1.md`.
Siehe `Kairo_PM_Frontend_UI_Concept_v0.1.md`, `ADP_AP1_9_PM_Work_Modes_Frontend_IA_v0.1.md`. Siehe `Kairo_PM_Frontend_UI_Concept_v0.1.md`, `ADP_AP1_9_PM_Work_Modes_Frontend_IA_v0.1.md`.
**Reihenfolge Code:** AP1.9a (Shell) → 9b9e (Modus-Inhalte); AP1.5d parallel nach 9b wo sinnvoll. **Reihenfolge Code:** AP1.9a (Shell) ✓ → 9b9e; AP1.10 + AP1.12 (Planen); AP1.5d parallel nach 9b.
---
## 1.4 PO-Entscheidung 2026-07-09 — Planen ausbauen & Vorhaben als Wurzel
**Auslöser:** Planen braucht Outline, Modal-Edit, Archetypen/Felder, Gate-Graph; Breadcrumb noch nicht modus-sensitiv.
| Entscheidung | |
|--------------|--|
| **Vorhaben = Wurzel** für alle Plan-Objekte | vorgeschlagen |
| Standardfelder (indexiert) + **Entity Field System** zentral | vorgeschlagen |
| Plan-**Outline** statt loser Untertabs | vorgeschlagen |
| Gate-**Graph-Editor** (Mitai-Pattern, Kairo-Semantik) | vorgeschlagen |
| Modal-Edit + DnD (Desktop) / ↑↓ (Mobile) | vorgeschlagen |
Siehe `Kairo_Plan_Mode_Design_v0.1.md`, `ADP_AP1_10_Initiative_Archetypes_and_Entity_Field_System_v0.1.md`.
**Reihenfolge Code:** AP1.9b → AP1.12 → AP1.10 → AP1.5d → AP1.13.
--- ---
@ -86,9 +104,10 @@ Phase F Gate-Backend AP1.4 + AP1.4b ✓ (Backend); UI minimal
Phase G Ist-Hierarchie AP1.5 ✓ Phase G Ist-Hierarchie AP1.5 ✓
Phase G2 Rekursive Container AP1.5c5d ✓ 5c / → 5d nach AP1.6 Phase G2 Rekursive Container AP1.5c5d ✓ 5c / → 5d nach AP1.6
Phase H Plan/Ist-Verknüpfung AP1.6 ✓ Phase H Plan/Ist-Verknüpfung AP1.6 ✓
Phase H2 PM Work Modes IA AP1.9 ← **NÄCHSTES CODE** (PO 2026-07-08) Phase H2 PM Work Modes IA AP1.9 ✓ 9a / → 9b9e
Phase H3 Rekursive Tasks AP1.5d nach AP1.9b Phase H3 Plan Outline & Archetypes AP1.1012 ← **NÄCHSTES DESIGN+CODE** (PO 2026-07-09)
Phase I Gate-Graph AP1.4d4e nach AP1.9d Phase H4 Rekursive Tasks AP1.5d nach AP1.12d
Phase I Gate-Graph AP1.4d + AP1.13 nach AP1.12
Phase J Portfolio & Kontext AP1.8 geplant Phase J Portfolio & Kontext AP1.8 geplant
Phase K Agent Interface AP1.7 geplant (unverändert) Phase K Agent Interface AP1.7 geplant (unverändert)
Phase L Validation AP0.10d (laufend PO) parallel Phase L Validation AP0.10d (laufend PO) parallel
@ -112,7 +131,9 @@ Phase L Validation AP0.10d (laufend PO) parallel
| AP1.4b | 0.13.1-ap1.4b | Gate-Checkliste Backend + Detail-Route | | AP1.4b | 0.13.1-ap1.4b | Gate-Checkliste Backend + Detail-Route |
| AP1.5c | 0.14.1-ap1.5c | Rekursive Projects | | AP1.5c | 0.14.1-ap1.5c | Rekursive Projects |
| AP1.6 | 0.15.0-ap1.6 | Plan/Ist, Journey, Gate-Beiträge | | AP1.6 | 0.15.0-ap1.6 | Plan/Ist, Journey, Gate-Beiträge |
| AP1.5e | 0.15.1-ap1.5e | Projekt-Detail, Lifecycle-Chip (Übergang — ersetzt durch AP1.9) | | AP1.5e | 0.15.1-ap1.5e | Projekt-Detail (Übergang) |
| AP1.9a | 0.16.x-ap1.9a | PM Work Modes Shell, Scope, Redirects |
| DOC Plan | 2026-07-09 | Plan Mode Design v0.1, ADP AP1.10 |
| DOC PM UI | 2026-07-08 | PM Frontend UI Concept v0.1, ADP AP1.9 | | DOC PM UI | 2026-07-08 | PM Frontend UI Concept v0.1, ADP AP1.9 |
| DOC PO | 2026-07-06 | ADP Product Layering & IA-Reset | | DOC PO | 2026-07-06 | ADP Product Layering & IA-Reset |
| DOC Container | 2026-07-06 | ADP Recursive Containers & Execution Granularity | | DOC Container | 2026-07-06 | ADP Recursive Containers & Execution Granularity |
@ -176,23 +197,48 @@ Backlog/Action/Project/Task → RoadmapItem; Decision-Spur; Journey-Timeline.
--- ---
### AP1.9 — PM Work Modes & Frontend IA Reset ← **NÄCHSTES CODE** ### AP1.9 — PM Work Modes & Frontend IA Reset ✓ (9a) / → 9b9e
**Ziel:** App-weite Arbeitsmodi statt Vorhaben-Tab-Omnibus; Querschnitt für PM-Use-Cases. **Ziel:** App-weite Arbeitsmodi statt Vorhaben-Tab-Omnibus.
| Teil | Scope | Status |
|------|--------|--------|
| **9a** | Shell, Routen, Scope, Redirects, Objekt-Routen | ✓ |
| **9b** | Scope-Breadcrumb modus-sensitiv | offen |
| **9c** | Cockpit + Ausführen polish | offen |
| **9d** | Kontrolle | offen |
| **9e** | Plan-Tabs vorläufig (→ AP1.12) | teilweise |
| **9f** | Team | offen |
**ADP:** `ADP_AP1_9_PM_Work_Modes_Frontend_IA_v0.1.md`
---
### AP1.10 — Initiative-Archetypen & Entity Field System ← **NÄCHSTES (mit 9b/12)**
| Teil | Scope | | Teil | Scope |
|------|--------| |------|--------|
| **9a** | App-Shell, Routen `/cockpit`, `/work`, `/plan`, `/control`, `/team`, Scope-Provider, Redirects | | **10a** | Standardfelder + `archetype_key` |
| **9b** | Cockpit + Ausführen/Heute (AP-Querschnitt) | | **10b** | EFS Registry + Seeds |
| **9c** | Kontrolle: Snapshot, Journey, Plan-Ist-Aggregate | | **10c** | Field API + Modal FieldRenderer |
| **9d** | Planen: Struktur, Gates, Inbox (Migration von Initiative-Tabs) |
| **9e** | Team: Workload, Zuweisungsübersicht |
**ADP:** `ADP_AP1_9_PM_Work_Modes_Frontend_IA_v0.1.md` **ADP:** `ADP_AP1_10_Initiative_Archetypes_and_Entity_Field_System_v0.1.md`
**UI Concept:** `Kairo_PM_Frontend_UI_Concept_v0.1.md`
**Version-Ziel:** `0.16.0-ap1.9a` (Shell), dann inkrementell
**Explizit nicht:** Weitere Features unter `InitiativeExecutionPage` / `InitiativeSubNav`. ---
### AP1.12 — Plan-Modus Outline & Interaktion
| Teil | Scope |
|------|--------|
| **12ad** | Outline, Modal, Reorder, Arbeit-Knoten |
**Design:** `Kairo_Plan_Mode_Design_v0.1.md`
---
### AP1.13 — Gate Map Editor
Graph-UI für Gate-Dependencies (Mitai-Pattern). **Nach AP1.4d + AP1.12.**
--- ---
@ -209,7 +255,7 @@ Backlog/Action/Project/Task → RoadmapItem; Decision-Spur; Journey-Timeline.
| **Kein** nested Action (Default) | | **Kein** nested Action (Default) |
**ADP:** `ADP_Recursive_Containers_and_Execution_Granularity_v0.1.md` **ADP:** `ADP_Recursive_Containers_and_Execution_Granularity_v0.1.md`
**Nach AP1.9b** (Tasks füllen `/work`, IA bleibt) **Nach AP1.12d** (Tasks im Plan-Baum + `/work`)
**Version:** `0.16.x-ap1.5d` **Version:** `0.16.x-ap1.5d`
--- ---

View File

@ -115,9 +115,11 @@ Planen ist **scope-pflichtig auf mindestens ein Vorhaben** (Struktur hängt an I
**Nicht hier:** Tagesausführung, Blocker-Status aller APs, Team-Workload. **Nicht hier:** Tagesausführung, Blocker-Status aller APs, Team-Workload.
**Route:** `/plan` (+ `/plan/structure`, `/plan/gates`, `/plan/inbox`) **Route:** `/plan` (+ Outline-Knoten; Legacy `/plan/structure`, `/plan/gates`, `/plan/inbox`)
**Migration:** Heutige Tabs `plan`, `inbox` und Projektbaum aus `execution` **wandern hierher**. **Design (2026-07-09):** `Kairo_Plan_Mode_Design_v0.1.md` — Outline, Modal, DnD, Gate-Graph.
**Migration:** Heutige Plan-Untertabs → AP1.12 Outline.
--- ---

View File

@ -0,0 +1,235 @@
# Kairo — Plan-Modus Design v0.1
**Status:** PO-Arbeitsentwurf (Entscheidung ausstehend)
**Stand:** 2026-07-09
**Bezug:** `Kairo_PM_Frontend_UI_Concept_v0.1.md` §4.3, `ADP_AP1_10_Initiative_Archetypes_and_Entity_Field_System_v0.1.md`
**Auslöser:** Planen soll von Tab-Fragmenten zu durchgängiger Programmgestaltung werden — bis Struktur, Gates, Eingang, Arbeitspakete und Tasks
---
## 1. Leitfrage
**Wie soll das Programm aufgebaut sein — von der Vorhabens-Identität bis zur ausführbaren Granularität?**
Planen beantwortet **Struktur- und Zielfragen**. Es committet **keine Tagesausführung** (das ist Ausführen) und **kein Lagebild** (das ist Kontrolle).
---
## 2. Grundsatz: Vorhaben als Wurzel
```text
/plan?initiative={id}&project={optional}
Initiative (Wurzel — immer im Scope)
├── Profil — Archetyp, Standard- + dynamische Felder
├── Struktur — Project-Baum (rekursiv)
├── Zielzustände — Gates / RoadmapItems (Liste + Graph)
├── Eingang — Backlog (triage → convert)
└── Arbeit — Actions (+ Tasks ab AP1.5d) im Plan-Kontext
```
**Flache Vorhaben:** Actions ohne `project_id` erscheinen als direkte Kinder der Initiative im Plan-Baum.
**Commit-Grenze Plan → Ist:**
| Objekt | In Plan | Commit-Aktion |
|--------|---------|---------------|
| BacklogItem | Ja | Convert → Action |
| Project / Gate | Ja | sofort „Struktur“ (kein separater Commit) |
| Action | Sichtbar | Anlage = committet |
| Task | Sichtbar (AP1.5d) | Anlage unter Action |
---
## 3. IA: Von Tabs zur Plan-Outline
### 3.1 Heute (AP1.9a)
```text
/plan/structure | /plan/gates | /plan/inbox — drei lose Untertabs
```
### 3.2 Ziel (AP1.12)
**Eine Planungsseite** mit linker **Outline** (Baum) und rechtem **Kontextbereich** (Desktop) bzw. **Drill-down** (Mobile).
```text
┌──────────────────────────────────────────────────────────────┐
│ Modus: Planen Scope: Portfolio Vorhaben X [Projekt Y] │
├──────────────────┬───────────────────────────────────────────┤
│ OUTLINE │ KONTEXT │
│ ▼ Vorhaben X │ [Profil-Karte / Mini-Snapshot] │
│ ▼ Struktur │ oder │
│ Phase 1 │ [Liste der Kinder des gewählten Knotens] │
│ Phase 2 │ oder │
│ Zielzustände │ [Graph-Ansicht Gates] │
│ Eingang (3) │ │
│ Arbeit (12) │ │
└──────────────────┴───────────────────────────────────────────┘
```
**Routen (evolutionär):**
| Route | Bedeutung |
|-------|-----------|
| `/plan` | Portfolio: „Vorhaben ohne Struktur“, „Gates ohne Kriterien“ (Einstieg) |
| `/plan?initiative=` | Outline für ein Vorhaben |
| `/plan?initiative=&node=structure\|gates\|inbox\|work` | Outline-Fokus (Query, kein Pflicht-Split) |
| `/gates/:id`, `/projects/:id` | Objekt-Modal / Deep Link (bestehend AP1.9) |
Untertabs `/plan/structure` etc. bleiben als **Deep-Link-Aliase** mit Redirect auf `/plan?initiative=&node=…` bis Entfernung in AP1.12.
---
## 4. Interaktion
### 4.1 Bearbeiten — Modal (verbindlich)
| Objekt | Trigger | Modal-Inhalt |
|--------|---------|----------------|
| Initiative | Outline „Profil“ / Stift-Icon | Standardfelder + EFS (AP1.10) |
| Project | Klick / Stift | Titel, Status, container_kind, Gate-Link, Parent |
| Gate | Klick / Stift | RoadmapItem + Kriterien (bestehend, polish) |
| Backlog | Klick | Triage-Felder, Gate-Link, Convert-Button |
| Action | Klick | ActionForm (bestehend) — oder Link zu `/actions/:id` |
| Task | Klick (AP1.5d) | TaskForm |
**Regel (UI Concept P4):** Kein dauerhaftes Inline-Formular in der Outline.
### 4.2 Reihenfolge
| Plattform | Mechanismus | Gilt für |
|-----------|-------------|----------|
| Desktop (≥1024px) | Drag & Drop innerhalb gleicher Elternebene | Projects, Backlog (sort_order), Gates (optional Phase 2) |
| Mobile / Touch | ↑ / ↓ Buttons pro Zeile | gleich |
**API:** `PATCH` mit `sort_order` oder dediziertes `POST …/reorder` — idempotent, tenant-scoped.
### 4.3 Anlegen
„+“ am **elterlichen Knoten** in der Outline (nicht globaler FAB ohne Kontext).
---
## 5. Zielzustände — Graph-Editor
### 5.1 Zwei Ansichten
| Ansicht | Wann | UI |
|---------|------|-----|
| **Liste** | Flache Vorhaben, wenige Gates | `RoadmapPlanSection` (evolviert) |
| **Graph** | Komplexe Abhängigkeiten, Parallel-Gates | **GateMapEditor** (neu) |
Umschalter: „Liste | Graph“ im Knoten Zielzustände — Default **Liste** wenn ≤5 Gates, sonst letzter User-Choice (localStorage pro Initiative).
### 5.2 Graph-Editor (AP1.13) — Mitai-Pattern, Kairo-Semantik
**Referenz (Pattern only):** Mitai `WorkflowEditorPage` — Canvas, Zoom, Pan, Snap-to-grid.
**Kairo-Scope (kein Workflow):**
| Element | Semantik |
|---------|----------|
| Knoten | RoadmapItem (Gate, Meilenstein, Reifegrad) |
| Kanten | `roadmap_item_dependencies` (sequential / parallel / optional) |
| Kein | Lifecycle-Workflow, keine Prompt-Knoten, keine Mitai-Domäne |
**Phase 1:** Gates + Kanten CRUD im Graph
**Phase 2:** Project→Gate-Bezug als Badge am Knoten oder Filter-Layer
**Verify / Kriterien:** Weiterhin Detail-Modal / `/gates/:id` — nicht im Graph inline CRUD-Wand
### 5.3 Backend
Baut auf AP1.4d (Graph Engine read models) auf — UI AP1.13 **nach** 4d oder parallel wenn read APIs vorhanden.
---
## 6. Ebenen bis Workpackage & Task
| Ebene | Typ | Plan-Outline-Knoten | Tiefe |
|-------|-----|---------------------|-------|
| 0 | Initiative | Wurzel | 1 |
| 1 | Project | rekursiv | max. 5 (bestehend) |
| 2 | RoadmapItem | Zielzustände (Graph/Liste) | parallel zur Struktur |
| 3 | BacklogItem | Eingang | flach unter Initiative |
| 4 | Action | Arbeit | unter Project **oder** Initiative |
| 5 | Task | (AP1.5d) | unter Action, UI max. ~3 |
**Plan-Baum „Arbeit“:** Zeigt committete Actions + Tasks (read-heavy); Anlage öffnet Modal. Filter: optional nur „ohne Project“ / „unter gewähltem Project“ (Scope `?project=`).
---
## 7. Scope-Breadcrumb (AP1.9b — Zuverlässigkeit)
**Problem:** Klick auf Vorhaben im Breadcrumb führt immer nach `/control/status` — in Planen falsch.
**Regel:** Mittlerer Breadcrumb-Klick ist **modus-sensitiv**:
| Aktiver Modus | Klick „Vorhaben X“ |
|---------------|-------------------|
| `/plan/*` | `/plan?initiative=X` |
| `/control/*` | `/control/status?initiative=X` |
| `/work/*` | `/work/today?initiative=X` |
| Objekt-Route | passender Modus aus Objekttyp (`/projects/` → Plan, `/actions/` → Work) |
Portfolio-Klick: Scope leeren, Modus beibehalten.
**Technik:** `ProgramScopeBar` liest `useLocation` + Modus-Registry; kein hardcoded `/control/status`.
---
## 8. Implementierungspakete
```text
AP1.9b Scope-Breadcrumb modus-sensitiv; Scope-Sync bei Deep Links härten
AP1.12a Plan-Outline Shell (Desktop Split / Mobile Drill-down)
AP1.12b Modal-Edit für Project, Backlog, Initiative-Profil (Standardfelder)
AP1.12c Reorder: sort_order API + DnD (Desktop) + ↑↓ (Mobile)
AP1.12d Outline-Knoten „Arbeit“ (Actions listen, Link zu Detail)
AP1.13a GateMapEditor read-only (Layout aus Dependencies)
AP1.13b GateMapEditor edit (Knoten/Kanten CRUD)
AP1.5d Tasks in Outline-Knoten „Arbeit“
AP1.10 Archetyp + EFS für Initiative-Profil-Modal (parallel ab 10a)
```
**Empfohlene Reihenfolge:**
```text
9b → 12a → 12b → 10a/10c (Profil) → 12c → 12d → 5d → 13a → 13b
```
---
## 9. Nicht-Ziele (Scope Lock)
- Kein Sprint-/Capacity-Planning in Planen (später Team-Modus-Erweiterung)
- Kein Inline-CRUD aller Gates in der Outline-Liste
- Kein Mitai-Workflow-Clone
- Kein Steering pro Project-Ebene (ADP Recursive Containers)
---
## 10. Erfolgskriterien (PO)
1. PO kann ein Vorhaben wählen und **in einer Ansicht** Struktur, Gates, Eingang und Arbeit sehen.
2. Bearbeitung läuft **nur im Modal** — Outline bleibt übersichtlich.
3. Project-Reihenfolge per DnD (Desktop) änderbar.
4. Gates mit Abhängigkeiten im **Graph** darstellbar (AP1.13).
5. Breadcrumb-Klick auf Vorhaben bleibt im Modus Planen.
---
## 11. PO-Freigabe
- [ ] Outline statt drei Tabs (AP1.12) angenommen
- [ ] Modal-Edit + DnD/↑↓ OK
- [ ] GateMapEditor (Mitai-Pattern) Scope OK
- [ ] AP1.9b Breadcrumb-Regel OK
---
## Referenzen
- `docs/architecture/ADP_AP1_10_Initiative_Archetypes_and_Entity_Field_System_v0.1.md`
- `docs/architecture/ADP_AP1_9_PM_Work_Modes_Frontend_IA_v0.1.md`
- `docs/reference/design-principles/mitai/PROMPT_ENGINE_DESIGN_PRINCIPLES.md` (WorkflowEditor-Referenz)

View File

@ -1,8 +1,13 @@
import { Link } from 'react-router-dom' import { Link, useLocation } from 'react-router-dom'
import { useProgramScope } from '../context/ProgramScopeContext.jsx' import { useProgramScope } from '../context/ProgramScopeContext.jsx'
import { initiativeCatalogPath, scopedPath } from '../utils/routes.js' import { initiativeCatalogPath, projectPath, scopedPath } from '../utils/routes.js'
import {
resolveInitiativeHub,
resolvePortfolioHub,
} from '../utils/scopeNavigation.js'
export function ProgramScopeBar() { export function ProgramScopeBar() {
const location = useLocation()
const { const {
initiativeId, initiativeId,
projectId, projectId,
@ -12,12 +17,17 @@ export function ProgramScopeBar() {
setScope, setScope,
} = useProgramScope() } = useProgramScope()
const portfolioTo = resolvePortfolioHub(location.pathname)
const initiativeTo = initiativeId
? resolveInitiativeHub(location.pathname, initiativeId, scopedPath)
: null
return ( return (
<div className="program-scope-bar" aria-label="Programm-Scope"> <div className="program-scope-bar" aria-label="Programm-Scope">
<span className="program-scope-bar__label">Scope</span> <span className="program-scope-bar__label">Scope</span>
<nav className="program-scope-bar__trail"> <nav className="program-scope-bar__trail">
<Link <Link
to={scopedPath('/cockpit')} to={portfolioTo}
className={ className={
'program-scope-bar__crumb' + 'program-scope-bar__crumb' +
(!initiativeId ? ' program-scope-bar__crumb--active' : '') (!initiativeId ? ' program-scope-bar__crumb--active' : '')
@ -26,13 +36,13 @@ export function ProgramScopeBar() {
> >
Portfolio Portfolio
</Link> </Link>
{initiativeId && ( {initiativeId && initiativeTo && (
<> <>
<span className="program-scope-bar__sep" aria-hidden="true"> <span className="program-scope-bar__sep" aria-hidden="true">
</span> </span>
<Link <Link
to={scopedPath('/control/status', { initiativeId })} to={initiativeTo}
className={ className={
'program-scope-bar__crumb' + 'program-scope-bar__crumb' +
(!projectId ? ' program-scope-bar__crumb--active' : '') (!projectId ? ' program-scope-bar__crumb--active' : '')
@ -48,9 +58,12 @@ export function ProgramScopeBar() {
<span className="program-scope-bar__sep" aria-hidden="true"> <span className="program-scope-bar__sep" aria-hidden="true">
</span> </span>
<span className="program-scope-bar__crumb program-scope-bar__crumb--active"> <Link
to={projectPath(projectId)}
className="program-scope-bar__crumb program-scope-bar__crumb--active"
>
{projectTitle || 'Projekt'} {projectTitle || 'Projekt'}
</span> </Link>
</> </>
)} )}
</nav> </nav>

View File

@ -0,0 +1,91 @@
/**
* Modus-sensitive Scope-Navigation (AP1.9b).
* Breadcrumb-Ziele hängen vom aktiven Modus / Pfad ab nicht immer Kontrolle.
*/
const MODE_DEFAULTS = {
cockpit: { portfolioHub: '/cockpit', initiativeHub: '/cockpit' },
work: { portfolioHub: '/work/today', initiativeHub: '/work/today' },
plan: { portfolioHub: '/plan/structure', initiativeHub: '/plan/structure' },
control: { portfolioHub: '/control/status', initiativeHub: '/control/status' },
team: { portfolioHub: '/team', initiativeHub: '/team' },
}
/**
* @param {string} pathname
* @returns {'cockpit'|'work'|'plan'|'control'|'team'}
*/
export function resolveAppMode(pathname) {
const path = pathname || '/'
if (path.startsWith('/actions') || path.startsWith('/work')) return 'work'
if (path.startsWith('/projects') || path.startsWith('/gates') || path.startsWith('/plan')) {
return 'plan'
}
if (path.startsWith('/control')) return 'control'
if (path.startsWith('/team')) return 'team'
if (path.startsWith('/cockpit') || path.startsWith('/workspace')) return 'cockpit'
if (path.startsWith('/initiatives')) return 'control'
return 'cockpit'
}
/**
* Basis-Pfad für Portfolio-Klick (Scope leeren, Modus beibehalten).
* @param {string} pathname
*/
export function resolvePortfolioHub(pathname) {
const mode = resolveAppMode(pathname)
const defaults = MODE_DEFAULTS[mode]
if (mode === 'plan' && pathname.startsWith('/plan/')) {
const sub = pathname.match(/^(\/plan\/[^/?]+)/)
if (sub) return sub[1]
}
if (mode === 'control' && pathname.startsWith('/control/')) {
const sub = pathname.match(/^(\/control\/[^/?]+)/)
if (sub) return sub[1]
}
if (mode === 'work' && pathname.startsWith('/work/')) {
const sub = pathname.match(/^(\/work\/[^/?]+)/)
if (sub) return sub[1]
}
return defaults.portfolioHub
}
/**
* Ziel für Klick auf Vorhaben im Breadcrumb (Scope behält Initiative, Projekt-Filter weg).
* @param {string} pathname
* @param {string} initiativeId
* @param {import('./routes.js').scopedPath} scopedPathFn
*/
export function resolveInitiativeHub(pathname, initiativeId, scopedPathFn) {
const mode = resolveAppMode(pathname)
const scope = { initiativeId }
if (mode === 'plan') {
if (pathname.startsWith('/gates/')) {
return scopedPathFn('/plan/gates', scope)
}
if (pathname.startsWith('/projects/')) {
return scopedPathFn('/plan/structure', scope)
}
const sub = pathname.match(/^(\/plan\/[^/?]+)/)
return scopedPathFn(sub ? sub[1] : MODE_DEFAULTS.plan.initiativeHub, scope)
}
if (mode === 'work' || pathname.startsWith('/actions/')) {
const sub = pathname.match(/^(\/work\/[^/?]+)/)
return scopedPathFn(sub ? sub[1] : MODE_DEFAULTS.work.initiativeHub, scope)
}
if (mode === 'control') {
const sub = pathname.match(/^(\/control\/[^/?]+)/)
return scopedPathFn(sub ? sub[1] : MODE_DEFAULTS.control.initiativeHub, scope)
}
if (mode === 'team') {
return scopedPathFn(MODE_DEFAULTS.team.initiativeHub, scope)
}
return scopedPathFn(MODE_DEFAULTS.cockpit.initiativeHub, scope)
}

View File

@ -0,0 +1,46 @@
import { describe, expect, it } from 'vitest'
import { scopedPath } from './routes.js'
import {
resolveAppMode,
resolveInitiativeHub,
resolvePortfolioHub,
} from './scopeNavigation.js'
describe('scopeNavigation', () => {
it('resolves app mode from path', () => {
expect(resolveAppMode('/plan/structure')).toBe('plan')
expect(resolveAppMode('/plan/gates')).toBe('plan')
expect(resolveAppMode('/projects/abc')).toBe('plan')
expect(resolveAppMode('/gates/abc')).toBe('plan')
expect(resolveAppMode('/work/today')).toBe('work')
expect(resolveAppMode('/actions/abc')).toBe('work')
expect(resolveAppMode('/control/status')).toBe('control')
expect(resolveAppMode('/cockpit')).toBe('cockpit')
expect(resolveAppMode('/team')).toBe('team')
})
it('keeps plan sub-route for portfolio hub', () => {
expect(resolvePortfolioHub('/plan/gates')).toBe('/plan/gates')
expect(resolvePortfolioHub('/plan/inbox')).toBe('/plan/inbox')
})
it('initiative hub stays in plan mode on gates sub-route', () => {
const href = resolveInitiativeHub('/plan/gates', 'init-1', scopedPath)
expect(href).toBe('/plan/gates?initiative=init-1')
})
it('initiative hub from action object routes to work', () => {
const href = resolveInitiativeHub('/actions/act-1', 'init-1', scopedPath)
expect(href).toBe('/work/today?initiative=init-1')
})
it('initiative hub from project object routes to plan structure', () => {
const href = resolveInitiativeHub('/projects/proj-1', 'init-1', scopedPath)
expect(href).toBe('/plan/structure?initiative=init-1')
})
it('control initiative hub uses current sub-route', () => {
const href = resolveInitiativeHub('/control/journey', 'init-1', scopedPath)
expect(href).toBe('/control/journey?initiative=init-1')
})
})