cb649aac34
Ampel / ampel (push) Successful in 24s
Die Seite verlangte eine technische Weichenstellung, BEVOR man gesagt hat was man will — mit Begriffen aus dem Maschinenraum (BOX / IDE: SIMPEL / IDE: GRUENDLICH). Deshalb klebten 116 Woerter Beipackzettel unter einem einzigen Eingabefeld. Zwei unabhaengige Entscheidungen, vorher in vier sich ausschliessende Knoepfe gepresst: wer — die Box allein, oder ein Repo fuer Zed nurDenken — erst nur ein Konzept (passt zu beidem, jetzt ein Haken) Die Knoepfe nennen das ERGEBNIS statt des Werkzeugs, und der erklaerende Satz steht an der Option statt in einer Legende darunter. Neu: POST /api/ideen/einordnen — das dauerwarme Hirn liest den getippten Text und waehlt vor (gemessen ~500 ms, 5 von 5 Testfaellen richtig, inkl. "Lohnt sich...?" -> nur denken). Bewusst ein VORSCHLAG mit sichtbarem Etikett: er setzt nur die Auswahl, die ohnehin dasteht. Faellt er aus, bleibt schlicht die Voreinstellung — das Tippen wird nie blockiert, es gibt keinen Ladebalken und keine Fehlermeldung. Tiefe und Ziel erscheinen nur noch beim Repo-Weg, weil sie nur dort wirken. Ein Schalter der nichts tut ist schlimmer als keiner. Leerer Zustand zeigt drei anklickbare Beispiele statt "wirf der Box eine Idee zu". Kopfzeile nennt nur noch den Zustand — "Ideen" stand dreimal uebereinander. Die API bleibt unveraendert; die Abbildung passiert in submit(). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
155 lines
4.5 KiB
Python
155 lines
4.5 KiB
Python
"""Ideen-Queue-Endpoints — dünner REST-Layer über services/ideen.py (natives Hermes-Kanban).
|
|
LAN-only wie alle MC2-Endpoints; das Mensch-Gate bleibt die Karte im Auftragsbuch."""
|
|
|
|
from fastapi import APIRouter, HTTPException
|
|
from pydantic import BaseModel
|
|
from services import ideen
|
|
|
|
router = APIRouter(prefix="/api")
|
|
|
|
|
|
class IdeeIn(BaseModel):
|
|
titel: str
|
|
notiz: str = ""
|
|
welt: str = "box" # "box" = Werkstatt baut · "ide" = vorbereiten für Zed
|
|
tiefe: str = "" # nur ide: "simpel" | "gruendlich" (leer = Box schätzt selbst)
|
|
ziel: str = "" # nur ide-Projekt: "lxc" | "docker" (leer = Box entscheidet)
|
|
art: str = "projekt" # nur ide: "projekt" (Repo+Roadmap+Bau) | "idee" (nur durchdenken)
|
|
|
|
|
|
class TaskIn(BaseModel):
|
|
id: str
|
|
|
|
|
|
class AntwortIn(BaseModel):
|
|
id: str
|
|
antwort: str
|
|
|
|
|
|
class ArchivAlleIn(BaseModel):
|
|
# Leer = alle fertigen Karten der Queue; gesetzt = nur die dieses Projekts.
|
|
projekt: str = ""
|
|
|
|
|
|
class EinordnenIn(BaseModel):
|
|
text: str
|
|
|
|
|
|
@router.get("/ideen")
|
|
def list_queue() -> dict:
|
|
return ideen.list_queue()
|
|
|
|
|
|
@router.post("/ideen")
|
|
def add_idea(body: IdeeIn) -> dict:
|
|
res = ideen.add_idea(body.titel, body.notiz, welt=body.welt, tiefe=body.tiefe,
|
|
ziel=body.ziel, art=body.art)
|
|
if not res.get("ok"):
|
|
raise HTTPException(400, res.get("error", "Idee konnte nicht angelegt werden."))
|
|
return res
|
|
|
|
|
|
@router.post("/ideen/antwort")
|
|
def answer(body: AntwortIn) -> dict:
|
|
res = ideen.answer_task(body.id, body.antwort)
|
|
if not res.get("ok"):
|
|
raise HTTPException(400, res.get("error", "Antwort konnte nicht gesendet werden."))
|
|
return res
|
|
|
|
|
|
class PrioIn(BaseModel):
|
|
id: str
|
|
richtung: str # hoch | runter
|
|
|
|
|
|
@router.post("/ideen/stopp")
|
|
def stop(body: TaskIn) -> dict:
|
|
res = ideen.stop_task(body.id)
|
|
if not res.get("ok"):
|
|
raise HTTPException(400, res.get("error", "Stoppen fehlgeschlagen."))
|
|
return res
|
|
|
|
|
|
@router.post("/ideen/retry")
|
|
def retry(body: TaskIn) -> dict:
|
|
res = ideen.retry_task(body.id)
|
|
if not res.get("ok"):
|
|
raise HTTPException(400, res.get("error", "Neuer Versuch fehlgeschlagen."))
|
|
return res
|
|
|
|
|
|
@router.post("/ideen/prio")
|
|
def prio(body: PrioIn) -> dict:
|
|
res = ideen.prio_task(body.id, body.richtung)
|
|
if not res.get("ok"):
|
|
raise HTTPException(400, res.get("error", "Prio-Änderung fehlgeschlagen."))
|
|
return res
|
|
|
|
|
|
class WeiterIn(BaseModel):
|
|
id: str
|
|
ziel: str = "" # "lxc" | "docker" (leer = Box entscheidet)
|
|
tiefe: str = "" # "simpel" | "gruendlich" (leer = Box schätzt selbst)
|
|
|
|
|
|
@router.post("/ideen/weiterfuehren")
|
|
def weiterfuehren(body: WeiterIn) -> dict:
|
|
"""„Konzept gefällt mir" → IDE-Projekt-Karte mit dem fertigen Konzept als Vorlage."""
|
|
res = ideen.projekt_aus_idee(body.id, ziel=body.ziel, tiefe=body.tiefe)
|
|
if not res.get("ok"):
|
|
raise HTTPException(400, res.get("error", "Projekt konnte nicht angelegt werden."))
|
|
return res
|
|
|
|
|
|
class NachschaerfenIn(BaseModel):
|
|
id: str
|
|
hinweis: str
|
|
|
|
|
|
@router.post("/ideen/nachschaerfen")
|
|
def nachschaerfen(body: NachschaerfenIn) -> dict:
|
|
"""„Punkt X passt nicht" → Überarbeitungs-Runde am bestehenden Konzept."""
|
|
res = ideen.konzept_ueberarbeiten(body.id, body.hinweis)
|
|
if not res.get("ok"):
|
|
raise HTTPException(400, res.get("error", "Überarbeitung konnte nicht gestartet werden."))
|
|
return res
|
|
|
|
|
|
@router.post("/ideen/archivieren")
|
|
def archive(body: TaskIn) -> dict:
|
|
res = ideen.archive_task(body.id)
|
|
if not res.get("ok"):
|
|
raise HTTPException(400, res.get("error", "Archivieren fehlgeschlagen."))
|
|
return res
|
|
|
|
|
|
@router.post("/ideen/einordnen")
|
|
def einordnen(body: EinordnenIn) -> dict:
|
|
"""Einordnungs-VORSCHLAG beim Tippen. Wirft nie — scheitert es, kommt `ok: false`
|
|
und die Oberfläche behält ihre Voreinstellung."""
|
|
return ideen.einordnen(body.text)
|
|
|
|
|
|
@router.post("/ideen/archivieren-alle")
|
|
def archive_alle(body: ArchivAlleIn) -> dict:
|
|
"""Fertige Karten sammelweise wegräumen. Fasst ausschließlich `done` an."""
|
|
res = ideen.archive_done(body.projekt)
|
|
if not res.get("ok"):
|
|
raise HTTPException(400, res.get("error", "Archivieren fehlgeschlagen."))
|
|
return res
|
|
|
|
|
|
@router.get("/ideen/{id}/log")
|
|
def get_log(id: str) -> dict:
|
|
return ideen.log_of(id)
|
|
|
|
|
|
@router.get("/ideen/{id}/ergebnis")
|
|
def get_ergebnis(id: str) -> dict:
|
|
return ideen.ergebnis_of(id)
|
|
|
|
|
|
@router.get("/ideen/{id}/konzept")
|
|
def get_konzept(id: str) -> dict:
|
|
return ideen.konzept_of(id)
|