diff --git a/backend/src/tracker/api/routes/vorlagen.py b/backend/src/tracker/api/routes/vorlagen.py
index 82ae58c..6a5feaf 100644
--- a/backend/src/tracker/api/routes/vorlagen.py
+++ b/backend/src/tracker/api/routes/vorlagen.py
@@ -29,6 +29,65 @@ def _db():
conn.close()
+@router.get("/suggest")
+def suggest(q: str = Query("", min_length=2, max_length=200), conn=Depends(_db)):
+ """Typeahead suggestions using FTS5."""
+ has_fts = conn.execute(
+ "SELECT name FROM sqlite_master WHERE type='table' AND name='vorlagen_fts'"
+ ).fetchone()
+ if not has_fts or not q.strip():
+ return {"items": []}
+
+ # Build prefix query for typeahead (last word gets *)
+ words = q.strip().split()
+ parts = [f'"{w}"' for w in words[:-1]]
+ parts.append(f'"{words[-1]}"*') # prefix match on last word
+ fts_query = " ".join(parts)
+
+ try:
+ rows = conn.execute(
+ """SELECT rowid,
+ snippet(vorlagen_fts, 1, '', '', '…', 10) as snip
+ FROM vorlagen_fts
+ WHERE vorlagen_fts MATCH ?
+ ORDER BY rank
+ LIMIT 7""",
+ (fts_query,),
+ ).fetchall()
+ except Exception:
+ return {"items": []}
+
+ if not rows:
+ return {"items": []}
+
+ ids = [r["rowid"] for r in rows]
+ placeholders = ",".join("?" * len(ids))
+ vorlagen = conn.execute(
+ f"""SELECT id, aktenzeichen, betreff, typ
+ FROM vorlagen WHERE id IN ({placeholders})""",
+ ids,
+ ).fetchall()
+ v_map = {v["id"]: v for v in vorlagen}
+ snip_map = {r["rowid"]: r["snip"] for r in rows}
+
+ items = []
+ for rid in ids:
+ v = v_map.get(rid)
+ if v:
+ items.append({
+ "id": v["id"],
+ "aktenzeichen": v["aktenzeichen"],
+ "betreff": v["betreff"],
+ "typ": v["typ"],
+ "snippet": snip_map.get(rid, ""),
+ })
+
+ return {"items": items}
+
+
+
+
+
@router.get("")
def list_vorlagen(
page: int = Query(1, ge=1),
diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts
index dc372f8..b604544 100644
--- a/frontend/src/lib/api.ts
+++ b/frontend/src/lib/api.ts
@@ -204,6 +204,17 @@ export const reevalKette = (id: number, anmerkung: string) =>
export const fetchJobStatus = (jobId: string) =>
get<{ status: string; result?: object; error?: string }>(`/bewertung/status/${jobId}`);
+export interface SuchVorschlag {
+ id: number;
+ aktenzeichen: string | null;
+ betreff: string | null;
+ typ: string | null;
+ snippet?: string;
+}
+
+export const fetchSuchvorschlaege = (q: string) =>
+ get<{ items: SuchVorschlag[] }>(`/vorlagen/suggest?q=${encodeURIComponent(q)}`);
+
export const fetchFraktionen = () => get<{ id: number; kuerzel: string; name: string; farbe: string | null; anzahl: number }[]>('/fraktionen');
export const fetchFraktionDashboard = (kuerzel: string, jahr?: string) => {
const params = jahr ? `?jahr=${jahr}` : '';
diff --git a/frontend/src/routes/vorlagen/+page.svelte b/frontend/src/routes/vorlagen/+page.svelte
index c90850b..d14495e 100644
--- a/frontend/src/routes/vorlagen/+page.svelte
+++ b/frontend/src/routes/vorlagen/+page.svelte
@@ -1,7 +1,7 @@