Engineering Deep Dive
Der tägliche Statusloop, technisch erklärt
Vom Vercel-Cron um 16:00 bis zur Notification im Client-Postfach: jede Schicht, jede Tabelle, jede Sicherheitspolicy in einem Bild.
Warum dieser Loop existiert
Projektmanagement-Tools sammeln entweder zu wenig oder zu viel. Slack ist zu laut, Tickets sind zu trocken, und der Kunde bekommt entweder gar keine Updates oder eine ungefilterte Wand aus Commits. Beides macht Vertrauen kaputt.
Festag löst das mit einem strukturierten täglichen Mini-Ritual. Tagro fragt jeden Developer einmal am Tag — pünktlich um 16:00 Berlin — kurz nach dem Stand. Aus diesen Sätzen baut Tagro einen ruhigen, übersetzten Bericht, den der Client bei Bedarf sofort abrufen kann. Mehr nicht.
Der Ablauf, end-to-end
Zwei Eingänge, ein Ausgang. Der Cron-Job feuert deterministisch um 16:00, der Client darf jederzeit on-demand fragen. Beide Wege schreiben in dieselbe Tabelle — der Client sieht keinen Unterschied zwischen „heute geplant gepingt" und „eben frisch erzeugt".
16:00 Berlin jederzeit
│ │
▼ ▼
Vercel Cron ──► /api/cron/tagro-daily Client klickt
-dev-prompt "Status jetzt abrufen"
│ │
▼ ▼
dev_daily_prompts (eine pro /api/client/status-now POST
dev + projekt + heute) (60s Cooldown)
│ │
Notification: "Wie weit bist │
du heute mit X gekommen?" │
│ │
▼ ▼
Dev sieht Card auf /dev Tagro liest die letzten 24h
│ developer_updates, baut einen
Textarea: ein Satz ruhigen Status-Bericht, schreibt
│ via service-role in status_reports
▼ │
/api/dev/daily-update ▼
│ Report ist sofort im Client-
▶ developer_updates (intern) Dashboard sichtbar
▶ status_reports │
(audience=client, visible=true) │
▶ Notification an den Client ──── ◄ matched ─────┐
mit Link auf /reports │
│
Client sieht roten Inbox-Counter, │
liest in der Rail die übersetzte Lage ───────────────┘Wer sieht was
Sichtbarkeit ist Architektur, nicht UI. Tagro filtert nicht erst beim Render — die Trennung beginnt schon in der Datenbank, mit RLS-Policies und einer ausdrücklichen visible_to_client-Flag auf jedem Bericht.
│ Dev Panel │ Tagro Layer │ Client Panel ──────────────┼────────────┼──────────────┼───────────────── Rohes Update │ ● │ ● (filtert) │ ─ Evidence │ ● │ ● (prüft) │ ─ Blocker │ ● │ ● (ordnet) │ ● (als Risiko) Commits / PRs │ ● │ ● (mapped) │ ─ Confidence │ ─ │ ● │ ─ Übersetzung │ ─ │ ● │ ● (liest) Audio Briefing│ ─ │ ● │ ● (hört) Entscheidung │ ─ │ ● (markiert)│ ● (entscheidet)
Der Client sieht nie rohe Commit-Messages, nie Confidence-Werte und nie interne Dev-Notizen. Was er liest, ist eine bewusste, kurze, professionelle Lage — mit klarem Hinweis, wenn eine Entscheidung gebraucht wird.
Datenmodell
Drei zentrale Tabellen halten den Loop zusammen. Sie sind so klein wie möglich gehalten — jede Spalte ist da, weil sie konkret benutzt wird.
dev_daily_prompts developer_updates status_reports
────────────────── ────────────────── ──────────────
id uuid id uuid id uuid
developer_id fk developer_id fk project_id fk
project_id fk project_id fk audience text
prompt_date date ─┐ update_text text visible_to_ bool
state text │ status text client
submitted_at ts │ blocker bool summary text
related_update fk ────┤ blocker_desc text current_work_ jsonb
payload jsonb │ created_at ts blockers_json jsonb
│ │ generated_on date
│ ▼ created_by fk
└─► matched on submit ◄────────────────────────┘
(related_update_id) ▲
│
client_status_queries │
───────────────────── │
user_id fk │
project_id fk │
status_report_id fk ──────────────────────────────────────►│
generated_fresh bool │
created_at ts (used for 60s cooldown)dev_daily_promptshält den 16:00-Ping.unique(developer_id, project_id, prompt_date)sorgt dafür, dass der Cron idempotent ist — der doppelte 14:00/15:00-UTC-Fire (für Sommer- und Winterzeit) erzeugt nie zwei Karten.developer_updatesist die intern lesbare Rohversion. Sie wird nie an den Client gespiegelt.status_reportsmitaudience=clientundvisible_to_client=trueist die einzige Quelle, die der Client je zu sehen bekommt.client_status_queriesist der Audit-Log für jeden „Status jetzt abrufen"-Klick. Er trägt auch den 60-Sekunden-Cooldown.
Sicherheit & Cron
Der Cron-Endpoint ist öffentlich erreichbar — er wird von Vercels Cron-Infrastructure aufgerufen, und der Code muss damit umgehen können, dass jemand anderes ihn anpingt.
┌──────────────────────────┐ ┌──────────────────────────┐
│ VERCEL CRON │ │ USER REQUEST │
│ │ │ │
│ Authorization: │ │ Supabase Auth Session │
│ Bearer $CRON_SECRET │ │ (cookie-bound, RLS) │
│ │ │ │
└──────────────┬───────────┘ └──────────────┬───────────┘
│ │
▼ ▼
service-role client user-session client
(bypasses RLS) (RLS enforced)
│ │
│ writes: │ reads:
▼ ▼
• dev_daily_prompts • status_reports
• notifications (filtered by project membership)
• status_reports • developer_updates
(audience=client) (only own + admin)
│ • notifications
▼ (user_id = me)
inserts are always
intentional + audited
in audit_logsZwei Authentifizierungspfade nebeneinander: Der Cron-Pfad nutzt einen serverseitigen Bearer-Token (oder Vercels eigenen x-vercel-cron-Header) und schreibt mit der Supabase Service-Role — sauber abgegrenzt vom User-Pfad, der weiterhin durch RLS gegated ist. Jeder Write landet zusätzlich in audit_logs, damit auch der Cron rückverfolgbar bleibt.
Trust Layer
Das eigentliche Festag-Prinzip steht hinter dem Loop: Ein Statusbericht darf nicht aus dünner Luft entstehen. Tagro liest, verdichtet, übersetzt — aber jeder Satz muss eine Wurzel in echter Arbeit haben.
Trust Layer
───────────
┌──────────────┐
│ STATUS │ ← Was der Client liest
│ REPORT │
└──────┬───────┘
│ generiert aus
▼
┌──────────────┐
│ TAGRO │ ← Engine: Plausibilität, Confidence, Übersetzung
│ VERIFICATION│
└──────┬───────┘
│ liest
▼
┌──────────────┐
│ EVIDENCE │ ← developer_updates, commits, tasks, decisions
│ LAYER │
└──────┬───────┘
│ basiert auf
▼
┌──────────────┐
│ AUSFÜHRUNG │ ← echte Arbeit des Developers
│ │
└──────────────┘
Kein Bericht ohne Evidence.
Kein Evidence-Punkt ohne Audit-Spur.Kein Bericht ohne Evidence. Keine Evidence ohne Audit-Spur. Der Client kann sich darauf verlassen, dass ein „Alles im Plan" in seinem Dashboard nicht eine freundliche Behauptung ist, sondern eine Folge aus geprüften Signalen.
Was als nächstes kommt
Drei Ausbaustufen sind im Code schon vorbereitet:
- Tagro-LLM-Übersetzung statt der aktuellen Heuristik — bessere Tonalität, immer noch dieselbe Evidence-Wurzel.
- Voice-Input in der Dev-Card — der Dev darf sprechen statt tippen, Tagro transkribiert + übersetzt.
- Per-Project-Berichte mit Dropdown im Client-Dashboard — bei Kunden mit mehreren Projekten parallel.
Der Loop ist der erste vollständige Tagro-Kreis, der ohne Mensch in der Mitte funktioniert. Die nächsten Schichten — Risiken automatisch erkennen, Entscheidungen vorschlagen, Tasks aus Berichten ableiten — bauen alle darauf auf.