Commit Graph
22 Commits
Author SHA1 Message Date
florian.wildeandClaude Opus 5 18ed4de9f9 feat(admin): Schwelle fuer den Stillstand einstellbar
Eigener Abschnitt mit der Schwelle von 14 Tagen bis zu einem Jahr, dem
Zeitpunkt der letzten Pruefung und der Zahl der Empfaenger. Steht die auf
null, sagt der Abschnitt das und verweist auf "Mein Konto".

Eine Aenderung der Schwelle setzt lastStaleCheckAt zurueck, damit sie beim
naechsten Tick greift und nicht erst in 24 Stunden.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 10:55:15 +02:00
florian.wildeandClaude Opus 5 f1e4271488 feat(ui): Benachrichtigungsziele unter "Mein Konto"
Beliebig viele Ziele je Konto, jedes mit eigenen Anlaessen. Jedes laesst sich
einzeln testen und pausieren; Ergebnis und Zeitpunkt der letzten Zustellung
stehen an der Karte.

Der Weg laesst sich nach dem Anlegen nicht mehr aendern - ein Webhook-Ziel zu
einer E-Mail-Adresse umzubiegen ergaebe keinen Sinn und muesste das
Geheimnis mitwandern lassen. Ist kein SMTP hinterlegt, ist die Auswahl
"E-Mail" gesperrt und erklaert, warum.

targetSafeSelect liegt in lib/notify/types statt in der Route: Next laesst in
route.ts nur bestimmte Exporte zu und bricht den Bau bei allem anderen ab.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 10:22:50 +02:00
florian.wildeandClaude Opus 5 5b40d5e4ff feat(api): progressFromTasks im Projekt-Endpunkt
Der Schalter laesst sich ueber PATCH /api/projects/:id setzen. Beim
Einschalten wird der abgeleitete Wert sofort berechnet, damit er nicht bis
zur naechsten Aufgabenaenderung falsch steht.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 09:30:04 +02:00
florian.wildeandClaude Opus 5 79c4bd1967 feat(export): Aufgaben in Export, Import und Sicherung aufnehmen
Aufgaben gehen mit - JSON-Export, Import und Instanz-Sicherung. Beim Import
wird die Position aus der Datei uebernommen, notfalls die Reihenfolge in ihr.
Wie bei den Notizen werden Aufgaben beim Ersetzen ausgetauscht statt
zusammengefuehrt, damit ein erneuter Import keine Dubletten erzeugt.

Der Markdown-Export bekommt einen Abschnitt "Aufgaben", nach Spalten
gegliedert und als Checkliste geschrieben - so bleibt der Stand auch
ausserhalb von Nebula lesbar.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 09:29:50 +02:00
florian.wildeandClaude Opus 5 0212dad2bf feat(ui): Aufgabenbrett auf der Projektseite
Vier Spalten, Karten per Ziehen verschiebbar - zwischen den Spalten und
innerhalb einer Spalte. Waehrend des Ziehens fuehrt der oertliche Zustand,
danach wird die neue Ordnung als Ganzes gespeichert; scheitert das, springt
das Brett auf den Serverstand zurueck.

Details:
- Gezogen wird am Griff links, damit ein Klick auf die Karte weiter den
  Dialog oeffnet.
- Der Spaltenwechsel passiert schon beim Darueberziehen, nicht erst beim
  Ablegen - sonst wirkt das Brett traege.
- Der Serverstand wird nur uebernommen, wenn gerade nicht gezogen wird,
  sonst spraenge die Karte mitten in der Bewegung zurueck.
- Faelligkeiten faerben sich: ueberfaellig rot, heute gelb, demnaechst
  gedaempft.

Ist "Fortschritt aus Aufgaben" eingeschaltet, wird der Regler gesperrt statt
einen Wert anzubieten, der beim naechsten Aufgabenwechsel ueberschrieben
wuerde - im Dialog wie im Kopfbereich. Die Projektkarte zeigt das Verhaeltnis
als "3/8".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 09:29:28 +02:00
florian.wildeandClaude Opus 5 72bcf824ce feat(tasks): Aufgaben je Projekt mit Spalten und Reihenfolge
Neues Modell Task: Titel, optionale Beschreibung, Spalte, Position,
Faelligkeit und Labels. Vier Spalten - offen, in Arbeit, blockiert,
erledigt.

Anders als beim Projektbrett ist die Reihenfolge innerhalb einer Spalte hier
bedeutsam und wird deshalb gespeichert. Der Reorder-Endpunkt nimmt je Spalte
die vollstaendige Liste in ihrer neuen Reihenfolge entgegen und leitet Status
und Position daraus ab. Das ist wiederholbar, kommt ohne Positionsrechnerei
im Browser aus, und ein verlorener Aufruf laesst sich einfach erneut senden.

Sicherheitsrelevant: der Endpunkt bekommt IDs aus dem Browser. Er
aktualisiert ausschliesslich Aufgaben, die wirklich zu diesem Projekt
gehoeren, und meldet uebergangene IDs zurueck - sonst liessen sich fremde
Aufgaben ueber untergeschobene IDs verschieben.

doneAt wird nur beim tatsaechlichen Wechsel nach "erledigt" gesetzt und beim
Zurueckziehen geleert. Ein Umsortieren innerhalb der Spalte laesst das Datum
in Ruhe.

Der Fortschritt eines Projekts laesst sich wahlweise aus dem Anteil
erledigter Aufgaben ableiten. Er wird nach jeder Aenderung neu berechnet und
auch sofort beim Einschalten.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 09:29:28 +02:00
florian.wildeandClaude Opus 5 92285b11fc fix: Versionsnummer aus einer einzigen Quelle
Die Fusszeile zeigte v0.2.0, die package.json stand auf 0.1.0 - beim
Auth-Feature hatte ich nur die Anzeige hochgezaehlt. Jetzt kommt die Version
aus der package.json, kann also nicht mehr auseinanderlaufen. Stand: 0.4.0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 01:04:42 +02:00
florian.wildeandClaude Opus 5 4bb600bb06 feat(search): Volltextsuche ueber Notizen
Die Suche im Board arbeitet auf den bereits geladenen Projekten und deckt
Name, Kurzbeschreibung, Tags und Repo-Pfad ab. Notizen liegen dort nicht vor
- sie mitzuladen wuerde die Seite unnoetig aufblaehen. Deshalb ein eigener
Endpunkt, der Postgres mit seiner deutschen Textsuche arbeiten laesst.

- websearch_to_tsquery versteht Eingaben wie "docker -compose" und wirft bei
  Unsinn keinen Fehler
- ts_headline liefert den Ausschnitt gleich mit; die Hervorhebung kommt als
  [[…]] zurueck, damit die Oberflaeche kein HTML aus der Datenbank einbetten
  muss
- deutsche Stammformen greifen: "Webhook" findet auch "Webhooks"
- entprellt ab zwei Zeichen, laufende Abfragen werden abgebrochen

Dazu ein GIN-Index auf dem Suchausdruck. Prisma kann Ausdrucksindizes im
Schema nicht abbilden - nachgeprueft: "migrate diff" laesst ihn in Ruhe und
schlaegt kein DROP vor.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 01:03:55 +02:00
florian.wildeandClaude Opus 5 04e8437f29 feat(ui): Markdown in Beschreibung und Notizen
Bisher wurde alles als reiner Text ausgegeben. Jetzt werden Ueberschriften,
Listen, Tabellen, Codebloecke, Zitate und Links dargestellt, und aus
"- [ ] Aufgabe" werden echte Checklisten.

Sicherheitsrelevant: der Inhalt stammt vom Benutzer. Ohne rehype-sanitize
waere das ein XSS-Loch, sobald jemand rohes HTML in eine Notiz schreibt. Das
Standardschema erlaubt nur harmlose Elemente; ergaenzt wird nur, was fuer
Aufgabenlisten und Sprachklassen an Codebloecken noetig ist. Links bekommen
zusaetzlich target=_blank mit noopener und nofollow.

Die Formatierung steht in components.css: Tailwinds Preflight setzt alle
Abstaende und Schriftgroessen zurueck, Ueberschriften und Listen brauchen
also wieder Form.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 01:03:55 +02:00
florian.wildeandClaude Opus 5 91c94e7383 feat(export): Projekte exportieren und importieren
Bislang lagen alle Daten ausschliesslich in der Datenbank - ein
"docker compose down -v" haette alles geloescht, ohne Rueckweg.

Export:
- alle eigenen Projekte oder ein einzelnes als JSON
- ein Projekt zusaetzlich als lesbares Markdown, inklusive letztem
  bekannten Git-Stand

Was bewusst nicht in der Datei steht:
- Access Tokens. Die Verbindung wird nur beschrieben (Name, System,
  Basis-URL), das Token muss beim Import neu hinterlegt werden. Eine
  Exportdatei landet sonst schnell in einem Download-Ordner oder einem
  Cloud-Abgleich.
- Repo-Snapshots. Reproduzierbar und gross; ein Abgleich holt sie zurueck.
- Datenbank-IDs und der Besitzer. Beides gilt nur in der Quellinstanz.

Import:
- die hochgeladene Datei ist Fremdinhalt und wird vor jeder Verwendung
  streng gegen ein Zod-Schema geprueft
- Abgleich ueber den Slug, drei Strategien: ueberspringen, zusaetzlich
  anlegen, ersetzen
- dryRun liefert dieselbe Auswertung, ohne zu schreiben - Grundlage der
  Vorschau in der Oberflaeche
- Verbindungen werden ueber Name oder Provider samt Basis-URL zugeordnet;
  fehlt eine, wird das Projekt ohne Verknuepfung angelegt und das gemeldet
- beim Ersetzen werden Notizen ausgetauscht statt zusammengefuehrt: das ist
  vorhersagbar, und ein erneuter Import erzeugt keine Dubletten

Die Instanz-Sicherung fuer Administratoren enthaelt dagegen alles, was zum
Wiederherstellen noetig ist - Passwort-Hashes und Token-Chiffrate
eingeschlossen. Ohne dasselbe APP_SECRET sind die Tokens wertlos. Sitzungen
und Passkeys bleiben draussen: erstere sind kurzlebig, letztere haengen an
Geraet und rpID.

readJsonBody bekommt eine einstellbare Obergrenze - 256 KB reichen fuer eine
Exportdatei mit vielen Notizen nicht.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 00:33:26 +02:00
florian.wildeandClaude Opus 5 4f2c221db6 feat(admin): Abgleich einstellbar und Schalter je Projekt
Adminbereich, Abschnitt "Automatischer Abgleich":
- ein- und ausschalten
- Abstand von 15 Minuten bis taeglich
- Projekte je Durchlauf
- fertige und archivierte auslassen
- Zustand auf einen Blick: verknuepfte Projekte, letzter und naechster
  Durchlauf, Kurzbericht des letzten Laufs
- Knopf "Jetzt abgleichen" fuer einen sofortigen Durchlauf

Der Endpunkt POST /api/admin/sync/run dient zugleich als Einstieg fuer einen
externen Zeitgeber, falls jemand lieber von aussen taktet als den eingebauten
Automatismus zu nutzen.

Im Projektdialog laesst sich ein einzelnes Projekt vom Abgleich ausnehmen -
nuetzlich bei einem Repo, dessen Token staendig Fehler wirft. Manuell
synchronisieren geht unabhaengig davon immer.

Die Zahl der in Frage kommenden Projekte wird ueber alle Konten gezaehlt: der
Abgleich ist ein Serverauftrag, keine Dateneinsicht. Ein Administrator sieht
dadurch weiterhin keine fremden Projekte.

Nachgewiesen: Durchlauf 1 aktualisiert das echte Repo und meldet das kaputte
als Fehlschlag, Durchlauf 2 stellt das kaputte zurueck, das ausgenommene
Projekt bleibt in beiden unberuehrt. Der Zeitplan loeste eigenstaendig aus.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 23:38:19 +02:00
florian.wildeandClaude Opus 5 b865cf49bd fix(ui): Anzeigefehler aus der Browser-Pruefung beheben
Erstmals mit echtem Browser nachgesehen (headless Chrome ueber Playwright,
Screenshots aller Ansichten). Dabei fuenf Dinge gefunden:

1. Menue klebte am Fensterrand statt am Ausloeser. Bei einem Ausloeser weit
   links wurde die bevorzugte rechtsbuendige Ausrichtung negativ und dann auf
   den Rand geklemmt - das Menue stand quer ueber der Seite. Jetzt wird bei
   Ueberlauf auf die andere Ausrichtung gewechselt und erst danach geklemmt.

2. .popover war mit 97 % nicht ganz deckend, wodurch "Bearbeiten" und
   "Loeschen" schwach durchschienen. Jetzt vollstaendig deckend.

3. Der Schieberegler zeichnete die Spur rechts vom Griff in einem hellen
   Standardton - ein grelles Band im dunklen Layout. Ersetzt durch eine
   selbst gezeichnete Variante mit Farbverlauf und sichtbarem Griff. Auf der
   Projektseite ersetzt sie zugleich das bisherige unsichtbare Eingabefeld
   ueber einem gezeichneten Balken, das gar keinen Griff hatte.

4. Der Hinweis der Kachel "Ideen" wurde mitten im Wort abgeschnitten
   ("Noch ein Gedanke - nichts ge..."). Kurzer Text statt der langen
   Statusbeschreibung.

5. Nach der Einrichtung stand im Adminbereich "noch nie angemeldet", obwohl
   gerade eine Sitzung lief. Einrichtung und Registrierung setzen lastLoginAt
   jetzt mit.

Die Konsole blieb ueber alle Ansichten hinweg frei von Fehlern und Warnungen
- die strikte CSP mit Nonce und strict-dynamic bricht also nichts.

Geprueft an einer separaten Wegwerf-Datenbank auf Port 3100, damit die
laufende Instanz unberuehrt blieb.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 22:46:00 +02:00
florian.wildeandClaude Opus 5 9a4cc75115 fix(ui): Menues und Dialoge ueber Portal ausgeben
Das Statusmenue auf der Projektseite wurde von den Schaltflaechen
"Bearbeiten" und "Loeschen" ueberdeckt, war unten abgeschnitten und der
Fortschrittswert schien hindurch. Drei Ursachen, alle mit derselben Wurzel:

1. Die Karten setzen overflow-hidden fuer den Akzentstreifen und den
   Farbverlaufsrand. Ein absolut positioniertes Kind wird daran
   abgeschnitten.
2. .glass setzt backdrop-filter, die Projektkarte bekommt beim Hovern
   zusaetzlich ein transform. Beides erzeugt einen Stacking-Context: das
   z-index des Menues galt nur noch innerhalb der Karte und verlor gegen
   spaeter gezeichnete Geschwister. Aus demselben Grund bezog sich das
   "position: fixed" der Klickflaeche zum Schliessen auf die Karte statt
   auf das Fenster - ein Klick daneben schloss das Menue nicht.
3. .glass hat 3,5 % Deckkraft. Als Kartenflaeche gut, als Overlay
   unbrauchbar. Der eigene backdrop-filter half nicht, weil er innerhalb
   eines Vorfahren mit backdrop-filter wirkungslos bleibt.

Behoben durch eine neue Popover-Komponente, die per createPortal am body
haengt, ihre Position aus dem Ankerelement berechnet und beim Scrollen und
bei Groessenaenderungen nachfuehrt. Reicht der Platz nach unten nicht, klappt
sie nach oben. Dazu die Klasse .popover mit nahezu deckendem Hintergrund.

Betrifft Statusauswahl, Benutzermenue und - aus demselben Grund - den
Modal-Dialog: der wird aus Karten heraus geoeffnet und haette sich sonst an
der Karte statt am Fenster ausgerichtet.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 22:29:11 +02:00
florian.wildeandClaude Opus 5 ed77ffaed2 feat(security): alle Daten auf den Besitzer einschraenken
Bisher sah jede Anfrage alles. Jetzt traegt jede Abfrage eine
Besitzerbedingung, und zwar an erster Stelle in der where-Klausel statt als
nachtraeglicher Vergleich - so kann sie nicht versehentlich uebersprungen
werden.

- Lesen: findFirst statt findUnique, immer mit ownerId
- Schreiben und Loeschen: updateMany/deleteMany mit ownerId in der
  where-Klausel. Fremde Datensaetze werden dadurch gar nicht erst getroffen,
  und die betroffene Zeilenzahl sagt, ob es den Datensatz gab.
- Notizen haengen ueber project.ownerId am Besitzer
- Beim Verknuepfen eines Projekts wird geprueft, dass die Git-Verbindung dem
  Aufrufer gehoert - sonst liesse sich eine fremde Verbindung und damit ein
  fremder Token unterschieben
- Fremde IDs liefern 404 statt 403: die Antwort bestaetigt nicht einmal,
  dass es den Datensatz gibt
- Ausgehende Endpunkte (Sync, Verbindungstest, Repo-Liste) zusaetzlich
  ratenbegrenzt, Basis-URLs gegen den SSRF-Schutz geprueft
- Slug und Verbindungsname werden je Besitzer auf Eindeutigkeit geprueft

Nachgewiesen: ein zweites Konto erhaelt auf GET, PATCH, DELETE, Notiz
anlegen und Sync eines fremden Projekts durchgaengig 404, auf die
Admin-Endpunkte 403, und das Zielprojekt bleibt unveraendert.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 21:30:59 +02:00
florian.wildeandClaude Opus 5 cf4103a46c feat(admin): Kontoverwaltung und Admin-Einstellungen
"Mein Konto": Profil, Passwort setzen oder wechseln, Passkeys anlegen,
umbenennen und entfernen, aktive Sitzungen einsehen und ueberall abmelden.
Der letzte Passkey laesst sich nicht entfernen, solange kein Passwort
gesetzt ist - sonst waere das Konto ausgesperrt.

Admin-Einstellungen: Betriebsart umschalten, Selbstregistrierung freigeben,
Konten anlegen, bearbeiten, deaktivieren und loeschen. Die Instanzwerte aus
der .env werden angezeigt, damit sichtbar ist, warum Passkeys gegebenenfalls
nicht verfuegbar sind.

Schutzregeln:
- Der Wechsel in den Einzelbetrieb wird abgelehnt, solange mehr als ein
  Konto existiert.
- Der letzte aktive Administrator kann weder herabgestuft noch deaktiviert
  oder geloescht werden.
- Das eigene Konto laesst sich nicht loeschen oder deaktivieren.
- Deaktivieren oder ein neues Passwort beenden sofort alle Sitzungen des
  Kontos.

Administratoren verwalten Konten, keine Inhalte: fremde Projekte sehen auch
sie nicht.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 21:30:33 +02:00
florian.wildeandClaude Opus 5 4f85e00016 feat(auth): Einrichtung, Anmeldeseite und Registrierung
- /setup fuehrt beim ersten Aufruf durch das Anlegen des Administratorkontos
  und die Wahl der Betriebsart. Der Endpunkt funktioniert nur, solange es
  keinen Benutzer gibt; danach kann sich niemand mehr nachtraeglich ein
  Adminkonto erschleichen. Vorhandene Projekte ohne Besitzer werden dabei
  uebernommen und im Formular vorher angekuendigt.
- /login mit Passwort oder Passkey. Der Passkey-Knopf entfaellt, wenn APP_URL
  keinen sicheren Kontext ergibt - mit Hinweis, woran es liegt. Das Ziel nach
  der Anmeldung wird auf relative Pfade begrenzt, sonst waere der
  weiter-Parameter ein offener Redirect.
- /register nur im Mehrbenutzerbetrieb und nur, wenn ein Administrator die
  Selbstregistrierung freigegeben hat.
- Kopfzeile mit Benutzermenue: eigenes Konto, Admin-Einstellungen, Abmelden.
  Ohne Anmeldung bleibt sie auf das Logo reduziert.
- Layout liest Titel und Namen ueber generateMetadata, damit APP_NAME zur
  Laufzeit greift statt beim Build eingefroren zu werden.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 21:30:33 +02:00
florian.wildeandClaude Opus 5 950bca1b81 fix(ui): Komponentenklassen in @layer components verschieben
Im Suchfeld lag das Lupensymbol auf dem Platzhaltertext. Ursache war die
Kaskade: .field steht mit der Kurzschreibweise "padding: .6rem .85rem" im
Stylesheet hinter Tailwinds Utilities, also gewann sie gegen "pl-9" und das
linke Padding blieb bei 13,6 Pixeln - zu wenig fuer das Symbol.

Die wiederkehrenden Bausteine liegen jetzt in einer eigenen Datei und dort in
@layer components. Tailwind sortiert die Layer als theme, base, components,
utilities; damit gewinnen Utilities wieder gegen die Komponentenklasse.

Das behebt nicht nur die Ueberlappung: auch alle Schaltflaechen mit
"btn ... px-2.5 py-1.5" wurden bisher in der Standardgroesse gerendert, weil
.btn ebenfalls eine padding-Kurzschreibweise setzt. Sie sind jetzt so
kompakt wie vorgesehen.

Geprueft am gebauten Stylesheet: .field liegt an Position 11107 im
components-Layer, .pl-9 an 31324 - die Utility gewinnt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 21:29:45 +02:00
florian.wildeandClaude Opus 5 72674dee4e feat(ui): Verwaltung der Git-Verbindungen
Eine Seite fuer alle angebundenen Git-Systeme. Mehrere Verbindungen desselben
Typs sind moeglich, etwa privates GitHub und Firmen-Gitea nebeneinander.

- Anlegen mit Systemauswahl, Basis-URL und Access Token; die Basis-URL wird
  beim Wechsel des Systems auf den passenden Standard gesetzt, sofern sie
  nicht von Hand geaendert wurde
- Verbindungstest auf Knopfdruck: prueft Erreichbarkeit und Token, meldet den
  erkannten Benutzer und bei Gitea die Serverversion. Ergebnis und Zeitpunkt
  werden gespeichert und in der Karte angezeigt
- Token erscheint nur als Hinweis; ein leeres Feld beim Bearbeiten laesst ihn
  unveraendert
- Loeschen trennt nur die Verknuepfung, die Projekte bleiben erhalten
- Hinweis auf die noetigen Scopes samt Link zur Doku des jeweiligen Systems

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 19:34:51 +02:00
florian.wildeandClaude Opus 5 826706aeca feat(ui): Projektdetail mit Notizen und Git-Panel
Kopfbereich mit Statusauswahl samt Erklaerung je Zustand, Favorit,
Fortschrittsregler, Bearbeiten und Loeschen.

Notizen:
- beliebig viele je Projekt, Titel optional, Zeilenumbrueche bleiben erhalten
- anpinnen, bearbeiten, loeschen direkt in der Liste
- "bearbeitet vor ..." erscheint nur bei echter Aenderung, nicht direkt nach
  dem Anlegen

Git-Panel:
- Kennzahlen zu Stars, Forks, offenen PRs/MRs, Issues, Branches und Groesse
- letzter Commit und aktuelle Version als eigene Kacheln
- Sprachverteilung als Balken
- Reiter fuer Branches, Tags, Commits und Releases mit Links ins Repo
- "Jetzt synchronisieren" holt den Stand; Fehler erscheinen im Klartext statt
  als Fehlerseite

Ohne verknuepftes Repository zeigt das Panel einen Hinweis statt leerer
Kacheln.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 19:34:40 +02:00
florian.wildeandClaude Opus 5 62b5c5bfa6 feat(ui): Dashboard mit Board, Filtern und direktem Statuswechsel
- Fuenf Kennzahlen ueber dem Board: Projektzahl mit Durchschnittsfortschritt,
  Ideen, aktive Entwicklungen, fertige Projekte, verknuepfte Repos
- Volltextsuche ueber Name, Beschreibung, Tags und Repo-Pfad
- Statusfilter als Chips mit Trefferzaehler, mehrfach kombinierbar
- Sortierung nach Aenderung, Anlage, Name, Fortschritt oder Prioritaet;
  Favoriten stehen immer oben
- Zwei Ansichten: freies Raster oder nach Status gruppiert
- Archiv standardmaessig ausgeblendet, per Schalter sichtbar

Die Projektkarte zeigt Fortschritt, Provider, Default-Branch, letzten Tag,
Alter des letzten Commits, Notizzahl und Sync-Fehler. Status und Favorit sind
direkt auf der Karte aenderbar - beides optimistisch, mit Rollback wenn der
Server ablehnt. Die Karte ist ein "stretched link", damit die Schaltflaechen
darin nicht in einem Anker verschachtelt sind.

Der Anlege-Dialog verlangt nur einen Namen; neue Projekte starten als Idee.
Ist eine Git-Verbindung gewaehlt, laesst sich das Repository aus einer
durchsuchbaren Liste uebernehmen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 19:34:29 +02:00
florian.wildeandClaude Opus 5 6fcbc04110 feat(ui): Dark-Glassmorphism-Designsystem und Grundlayout
Optischer Rahmen der Anwendung:

- Hintergrund aus drei langsam driftenden Nebeln, feinem Raster und einer
  Rauschtextur gegen Farbbanding
- .glass / .glass-soft als Grundflaechen, .card-glow fuer den Hover-Effekt
  mit Farbverlaufsrand je Projektakzent
- Buttons, Formularfelder und Scrollbars im gleichen Stil
- prefers-reduced-motion schaltet saemtliche Animationen ab

Dazu Kopfzeile mit aktiver Navigationsmarkierung, ein wiederverwendbarer
Modal-Dialog (Escape schliesst, Scroll wird gesperrt), das SVG-Icon sowie
Fehler- und 404-Seiten. Die Fehlerseite erkennt Datenbankprobleme und nennt
direkt die drei Befehle, die in dem Fall meistens helfen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 19:34:15 +02:00
florian.wildeandClaude Opus 5 7690bc87c5 feat(api): REST-Endpunkte fuer Projekte, Notizen, Verbindungen und Sync
Alles, was die Oberflaeche kann, ist damit auch scriptbar:

  GET  POST           /api/projects
  GET  PATCH DELETE   /api/projects/:id
  POST                /api/projects/:id/sync
  GET  POST           /api/projects/:id/notes
  PATCH DELETE        /api/notes/:id
  GET  POST           /api/connections
  PATCH DELETE        /api/connections/:id
  POST                /api/connections/:id/check
  GET                 /api/connections/:id/repos
  GET                 /api/health

Details:
- Jede Eingabe laeuft durch Zod; Feldfehler kommen als Objekt zurueck, damit
  Formulare sie direkt anzeigen koennen.
- Beim Anlegen werden Owner und Repo-Name aus der URL abgeleitet, falls nicht
  explizit angegeben.
- Ein leeres Token-Feld beim Bearbeiten einer Verbindung laesst das
  gespeicherte Token unveraendert; null entfernt es.
- Verbindungsantworten enthalten nie das Chiffrat, nur einen Hinweis
  wie "ghp_...9f3a".
- /api/health prueft die Datenbank und dient dem Docker-Healthcheck.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-25 19:34:02 +02:00