florian.wildeandClaude Opus 5 c270038edd
CI / pruefen (push) Canceled after 0s
feat(git): Webhooks fuer Push und Issues, v1.7.0
Ein Push aktualisiert den Stand sofort, statt bis zum naechsten Durchlauf
des Zeitgebers zu warten; ein geschlossenes Issue hakt seine Aufgabe ab.
Der Zeitplan bleibt als Rueckfalllosung.

Der Endpunkt ist der einzige ohne Anmeldung, der schreibt – entsprechend
eng gefasst:

- Ausgewiesen wird sich mit einer Signatur ueber den Rumpf. GitHub und
  Gitea rechnen HMAC-SHA256, GitLab schickt nur den Token im Klartext;
  dessen Verfahren ist schwaecher, mehr gibt die Plattform nicht her.
  Verglichen wird durchweg zeitkonstant.
- Geprueft wird gegen den **rohen** Rumpf. Durch JSON.parse und
  JSON.stringify gedreht kaeme eine andere Zeichenfolge heraus und die
  Signatur passte nie.
- Der Rumpf ist nie Quelle fuer Inhalte. Wer das Geheimnis kennt, kann eine
  Aufgabe auf- oder zumachen und einen Abgleich ausloesen – keine
  beliebigen Daten einschleusen.
- Ratenbegrenzung je Repository, Deckel auf die Rumpfgroesse, und ein
  unbekanntes Repository antwortet wie ein nicht eingerichtetes: 404,
  damit die ID nicht bestaetigt wird.
- Unbekannte Ereignisse werden angenommen und liegen gelassen. Ein Fehler
  brachte das Git-System zum Wiederholen und irgendwann zum Abschalten.

Das Geheimnis liegt verschluesselt am Repository, wie die Zugangstoken, und
ist genau einmal zu sehen. Damit es nicht doch nach draussen wandert, laedt
repositoryInclude die Repositories nicht mehr per include, sondern ueber
eine ausdrueckliche Feldliste: ein include haette das neue Feld still in
jede Projektantwort und jede Seite mitgenommen. Ob ein Haken eingerichtet
ist, holt die Projektseite getrennt.

Die Migration legt zwei nullbare Spalten an, mehr nicht; der Gegenlauf von
migrate diff kommt leer heraus.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-15 00:35:29 +02:00
2026-07-26 14:30:43 +02:00

✦ Nebula

Das Kontrollzentrum für deine Vibe-Coding Projekte.

Ideen festhalten · Status pflegen · Notizen sammeln · Git-Repos live im Blick

Next.js 15 · TypeScript · Tailwind CSS 4 · Prisma · PostgreSQL · Docker


Was ist Nebula?

Vibe Coding produziert schnell viele halbfertige Projekte: ein Repo hier, eine Idee dort, irgendwo eine Notiz in einer Textdatei. Nebula bündelt das an einem Ort.

Jedes Projekt bekommt einen Status (von der rohen Idee bis „Fertig"), beliebig viele Notizen und optional ein verknüpftes Repository. Nebula holt sich von dort per API Branches, Tags, Commits, Releases und offene Issues/PRs — egal ob GitHub, GitLab oder eine selbst gehostete Gitea-Instanz.

Die Anmeldung läuft über Benutzername und Passwort oder Passkey (WebAuthn). Nebula kennt zwei Betriebsarten: Einzelbetrieb für ein Konto oder Mehrbenutzerbetrieb, in dem jede Person ihren eigenen, streng getrennten Bereich hat. Umschalten geht jederzeit in den Admin-Einstellungen.

Alle Daten liegen in deiner lokalen PostgreSQL. Es gibt keinen Cloud-Dienst dahinter, Access Tokens werden verschlüsselt abgelegt.

Eine vollständige Auflistung aller Funktionen steht in FEATURES.md, geplante Erweiterungen in ROADMAP.md. Für den Dauerbetrieb auf einem Server — TLS, Firewall, Sicherungen und Updates — gibt es DEPLOYMENT.md.


Schnellstart

Zwei Betriebsarten, dieselbe Codebasis. Beide brauchen zuerst eine .env:

node scripts/setup.mjs      # legt .env an und erzeugt ein zufälliges APP_SECRET

Ohne Node zur Hand? Einfach .env.example nach .env kopieren und APP_SECRET von Hand auf einen langen Zufallswert setzen.

Variante A — Standalone (empfohlen zum Entwickeln)

Die App läuft nativ auf dem Rechner, nur PostgreSQL kommt aus dem Container:

npm run docker:db            # Postgres 17 auf 127.0.0.1:5432
npm install
npm run db:migrate           # Schema anlegen
npm run db:seed              # optional: drei Beispielprojekte
npm run dev                  # → http://localhost:3000

Für den Produktivbetrieb ohne Docker:

npm run build
npm start                    # → http://localhost:3000

Variante B — Alles in Docker

docker compose --profile full up -d --build     # → http://localhost:3000

Der App-Container spielt beim Start automatisch die Migrationen ein und wartet dabei auf die Datenbank. Logs mitlesen:

docker compose --profile full logs -f app

Stoppen:

docker compose --profile full down              # Container weg, Daten bleiben
docker compose --profile full down -v           # inkl. Datenbank-Volume

Variante C — Eigene, bereits laufende PostgreSQL

Docker wird gar nicht gebraucht. In der .env nur den Connection-String setzen:

DATABASE_URL="postgresql://benutzer:passwort@dbhost:5432/nebula?schema=public"

Dann npm install && npm run db:migrate && npm run dev.


Voraussetzungen

Variante Benötigt
Standalone Node.js ≥ 20.11, npm, PostgreSQL ≥ 14 (lokal oder via Docker)
Docker Docker Engine ≥ 24 mit Compose v2

Konfiguration

Alle Variablen sind in .env.example dokumentiert.

Variable Bedeutung Default
APP_NAME Anzeigename: Seitentitel, Kopfzeile, Passkey-Dialog Nebula
APP_TAGLINE Kleine Zeile unter dem Namen Vibe Coding
APP_URL Öffentliche Adresse — bestimmt die WebAuthn-RP-ID http://localhost:3000
DATABASE_URL PostgreSQL-Verbindung (Prisma) postgresql://nebula:nebula@localhost:5432/nebula
APP_SECRET Schlüssel für die Token-Verschlüsselung (AES-256-GCM) — unbedingt setzen
SESSION_TTL_DAYS Lebensdauer einer Anmeldung in Tagen 30
PORT Port der Anwendung 3000
APP_PORT Host-Port-Mapping des App-Containers 127.0.0.1:3000
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB Zugangsdaten des DB-Containers nebula
POSTGRES_PORT Host-Port der Datenbank — wirkt nur mit docker-compose.dev.yml, sonst hat die DB keinen 127.0.0.1:5432
ADMINER_PORT Host-Port von Adminer (--profile tools) 127.0.0.1:8080
GIT_API_TIMEOUT_MS Timeout für Git-API-Aufrufe 15000
GIT_ALLOW_LOOPBACK Git-Instanz auf demselben Rechner erlauben false
GIT_BLOCK_PRIVATE Zugriff ins private LAN sperren false
GIT_ALLOWED_HOSTS Strengster Modus: nur diese Hosts erlauben leer
NOTIFY_TIMEOUT_MS Timeout beim Zustellen von Benachrichtigungen 10000
SMTP_HOST … SMTP_FROM SMTP-Zugang; ohne SMTP_HOST steht der Weg „E-Mail" nicht zur Verfügung leer

APP_NAME, APP_TAGLINE und APP_URL werden zur Laufzeit gelesen. Dasselbe Docker-Image lässt sich also ohne Neubau umbenennen oder unter einer anderen Adresse betreiben — Container neu starten genügt.

APP_SECRET nachträglich ändern macht bereits gespeicherte Git-Tokens unlesbar. Sie müssen dann in den Verbindungen neu hinterlegt werden — Konten, Passwörter und Passkeys bleiben unberührt.

APP_URL nachträglich ändern (anderer Hostname) macht bestehende Passkeys ungültig, weil sie an die RP-ID gebunden sind. Passwörter funktionieren weiter.


Erste Anmeldung

Beim ersten Aufruf landest du auf /setup. Dort legst du das Administratorkonto an und wählst die Betriebsart:

  • Einzelbetrieb — genau ein Konto, keine Registrierung, keine Benutzerliste.
  • Mehrbenutzerbetrieb — beliebig viele Konten. Projekte, Notizen und Git-Verbindungen sind pro Konto strikt getrennt; auch ein Administrator sieht fremde Projekte nicht.

Nach der Einrichtung ist /setup gesperrt. Bereits vorhandene Projekte ohne Besitzer (etwa aus den Seed-Daten) werden dem neuen Konto zugeordnet.

Passkey einrichten: unter Mein Konto → Passkeys → Passkey hinzufügen. Danach genügt auf der Anmeldeseite ein Klick auf „Mit Passkey anmelden" — ohne Benutzernamen, weil Nebula auffindbare Credentials nutzt.

Passkeys brauchen einen sicheren Kontext. Sie funktionieren über https:// und über http://localhost, nicht über eine LAN-IP ohne TLS. APP_URL muss dabei exakt der Adresse entsprechen, unter der du die App aufrufst.

Git-Verbindung einrichten

  1. Im Git-System einen Personal Access Token mit Leserechten erzeugen:

    System Scopes
    GitHub Fine-grained Token: Contents: Read, Metadata: Read, Issues: Read, Pull requests: Read
    GitLab read_api (alternativ read_repository)
    Gitea / Forgejo repository:read, issue:read, user:read
  2. In Nebula unter Git-Verbindungen → Verbindung hinzufügen eintragen: System wählen, Basis-URL (z. B. https://git.meine-firma.de, ohne /api) und Token.

  3. Mit Testen prüfen — Nebula meldet den erkannten Benutzer zurück.

  4. Beim Anlegen oder Bearbeiten eines Projekts die Verbindung auswählen und über Repos laden das Repository aussuchen (oder die URL direkt eintippen).

  5. Auf der Projektseite Jetzt synchronisieren — Branches, Tags, Commits und Releases werden geholt und als Snapshot gespeichert.

Der Snapshot bleibt in der Datenbank, das Dashboard funktioniert also auch offline. Ohne Token gehen nur öffentliche Repositories, mit strengem Rate-Limit.

Automatisch statt auf Knopfdruck

Unter Admin-Einstellungen → Automatischer Abgleich lässt sich der Sync in den Hintergrund verlegen: Abstand von 15 Minuten bis täglich, Anzahl Projekte je Durchlauf, und wahlweise ohne fertige und archivierte Projekte. Standardmäßig ist er aus, weil jeder Durchlauf API-Kontingent verbraucht.

Der Zeitgeber läuft im Serverprozess — kein zusätzlicher Container, kein externer Cron. Nach Fehlschlägen wird ein Repository mit wachsendem Abstand zurückgehalten, damit ein abgelaufener Token nicht dauerhaft Kontingent verbrennt. Einzelne Projekte lassen sich im Projektdialog ausnehmen; manuell synchronisieren geht immer.

Wer lieber von außen taktet, lässt den Automatismus aus und ruft POST /api/admin/sync/run per eigenem Cron auf.


Export, Import und Sicherung

Projekte mitnehmen

Weg Wo Inhalt
Alle Projekte als JSON Dashboard → Datenbank-Symbol Stammdaten, Notizen, Repo-Verknüpfung
Ein Projekt als JSON Projektseite → Download-Symbol dasselbe, für ein Projekt
Ein Projekt als Markdown Projektseite → Download-Symbol lesbar, inklusive letztem Git-Stand
Import Dashboard → Datenbank-Symbol JSON einlesen, mit Vorschau

Access Tokens sind nie enthalten. Die Git-Verbindung wird nur beschrieben (Name, System, Basis-URL); nach dem Import muss das Token neu hinterlegt werden. Verweist eine importierte Datei auf eine hier unbekannte Verbindung, wird das Projekt ohne Verknüpfung angelegt und in der Vorschau angezeigt.

Beim Import wird über den Slug abgeglichen. Für Treffer gibt es drei Strategien:

  • Überspringen — Vorhandene bleiben unverändert
  • Zusätzlich anlegen — Kopie mit freiem Slug (nebula → nebula-2)
  • Ersetzen — Stammdaten überschreiben, Notizen austauschen

Vor dem Schreiben zeigt eine Vorschau, was passieren würde. Erst dann wird geschrieben.

Sicherung

Zwei Wege, mit unterschiedlichem Zweck:

JSON-Sicherung (Admin-Einstellungen → Sicherung) enthält Einstellungen, Konten, Verbindungen, Projekte und Notizen. Gut zum Umziehen. Passwörter liegen als scrypt-Hash vor, Git-Tokens als Chiffrat — ohne dasselbe APP_SECRET sind sie wertlos. Trotzdem vertraulich behandeln.

Datenbank-Sicherung über pg_dump — das, was man zum Wiederherstellen einer kaputten Instanz braucht:

.\scripts\backup.ps1                    # → .\backups\nebula-<datum>.sql
.\scripts\restore.ps1 -File .\backups\nebula-....sql
./scripts/backup.sh                     # → ./backups/nebula-<datum>.sql
./scripts/restore.sh backups/nebula-....sql

Die Skripte lesen Benutzer und Datenbankname aus der .env und führen pg_dump im Container aus — auf dem Rechner selbst muss nichts installiert sein.

Eine Sicherung ist erst dann eine Sicherung, wenn du sie einmal zurückgespielt hast. Das geht ohne Risiko in eine Wegwerf-Datenbank:

docker exec nebula-db psql -U nebula -d postgres -c "CREATE DATABASE nebula_test"
.\scripts\restore.ps1 -File .\backups\nebula-....sql -Database nebula_test -Force

Projektstruktur

nebula/
├── docker/entrypoint.sh        Migrationen + Serverstart im Container
├── docker-compose.yml          db (immer) · app (--profile full) · adminer (--profile tools)
├── Dockerfile                  Multi-Stage-Build auf Basis des Next-Standalone-Outputs
├── prisma/
│   ├── schema.prisma           Datenmodell
│   ├── migrations/             versionierte SQL-Migrationen
│   └── seed.ts                 Beispieldaten
├── scripts/setup.mjs           .env erzeugen inkl. APP_SECRET
└── src/
    ├── app/
    │   ├── page.tsx            Dashboard (Board, Filter, Kennzahlen)
    │   ├── projects/[id]/      Projektdetail: Beschreibung, Notizen, Git
    │   ├── connections/        Verwaltung der Git-Verbindungen
    │   └── api/                REST-Endpunkte (Projekte, Notizen, Verbindungen, Sync)
    ├── components/             UI-Komponenten (Board, Karten, Panels, Dialoge)
    ├── lib/
    │   ├── crypto.ts           AES-256-GCM für Access Tokens
    │   ├── db.ts               Prisma-Client
    │   ├── git/                Provider-Adapter: github.ts · gitlab.ts · gitea.ts
    │   ├── sync.ts             Repo-Snapshot holen und speichern
    │   └── validation.ts       Zod-Schemas für alle Eingaben
    └── types/                  gemeinsame Typen für Server und Client

npm-Skripte

Skript Zweck
npm run dev Entwicklungsserver mit Hot Reload
npm run build / npm start Produktionsbuild und -start (ohne Docker)
npm run setup .env anlegen inkl. generiertem APP_SECRET
npm run db:migrate Migrationen einspielen (prisma migrate deploy)
npm run db:migrate:dev Neue Migration aus Schemaänderungen erzeugen
npm run db:seed Beispielprojekte anlegen
npm run db:studio Prisma Studio öffnen
npm run db:reset Datenbank zurücksetzen (löscht alles)
npm test Unit-Tests (Vitest), unter einer Sekunde
npm run test:watch Tests im Beobachtungsmodus
npm run typecheck TypeScript prüfen
npm test Unit-Tests (Vitest, ohne Datenbank)
npm run test:e2e Ende-zu-Ende-Tests (Playwright, baut vorher)
npm run test:all Beides nacheinander
npm run docker:db Nur die Datenbank starten, mit Host-Port für npm run dev
npm run docker:up / docker:down Kompletten Stack starten / stoppen
npm run docker:tools Adminer auf http://localhost:8080

API

Alle Endpunkte liefern und erwarten JSON.

Bis auf /api/health und /api/auth/* erfordern alle Endpunkte eine Anmeldung und liefern ausschließlich Daten des angemeldeten Kontos.

Methode Pfad Zweck
GET /api/health Status inkl. Datenbankverbindung (Docker-Healthcheck)
POST /api/auth/setup Administratorkonto anlegen (nur beim ersten Mal)
POST /api/auth/login /api/auth/logout /api/auth/register Anmeldung
POST /api/auth/mfa Zweiter Faktor: Einmalkennwort oder Wiederherstellungscode
GET /api/auth/session Aktuelle Sitzung und Instanzzustand
POST /api/auth/passkey/{login,register}/{options,verify} WebAuthn
PATCH /api/account/profile Eigenes Profil
POST /api/account/password Eigenes Passwort setzen
GET DELETE /api/account/sessions Eigene Sitzungen / überall abmelden
PATCH DELETE /api/account/passkeys/:id Passkey umbenennen / entfernen
GET POST PUT DELETE /api/account/totp Zwei-Faktor: Zustand, einrichten, aktivieren, abschalten
POST /api/account/totp/recovery Neue Wiederherstellungscodes
GET PATCH /api/admin/settings Betriebsart, Registrierung, Abgleich (Admin)
POST /api/admin/sync/run Abgleich sofort anstoßen (Admin)
GET POST /api/admin/users Konten auflisten / anlegen (Admin)
PATCH DELETE /api/admin/users/:id Konto ändern / löschen (Admin)
GET POST /api/projects Projekte auflisten / anlegen
GET /api/projects/export Alle eigenen Projekte als JSON
GET /api/projects/:id/export Ein Projekt (?format=md für Markdown)
POST /api/projects/import Import, mit dryRun für die Vorschau
GET POST /api/templates Projektvorlagen auflisten / anlegen
PATCH DELETE /api/templates/:id Vorlage ändern / löschen
POST /api/templates/from-project Aus einem Projekt eine Vorlage machen
GET /api/admin/backup Vollständige Sicherung als JSON (Admin)
GET /api/search?q= Volltextsuche über die eigenen Notizen
GET POST /api/notifications Benachrichtigungsziele
PATCH DELETE /api/notifications/:id Ziel ändern / entfernen
POST /api/notifications/:id/test Testnachricht senden
GET PATCH DELETE /api/projects/:id Projekt lesen / ändern / löschen
POST /api/projects/:id/sync Alle Repositories des Projekts abgleichen
PATCH /api/projects/reorder Neue Reihenfolge im Brett
POST /api/projects/bulk Status, Tags oder Löschen für mehrere
GET /api/projects/:id/activity Verlauf des Projekts (?limit=)
GET POST /api/projects/:id/repositories Repositories des Projekts
PATCH DELETE /api/repositories/:id Repository ändern / vom Projekt lösen
POST /api/repositories/:id/sync Ein einzelnes Repository abgleichen
GET POST /api/projects/:id/tasks Aufgaben des Projekts
PATCH /api/projects/:id/tasks/reorder Neue Reihenfolge nach dem Ziehen
POST /api/projects/:id/tasks/from-issues Offene Issues als Aufgaben übernehmen
PATCH DELETE /api/tasks/:id Aufgabe ändern / löschen
GET POST /api/projects/:id/notes Notizen des Projekts
PATCH DELETE /api/notes/:id Notiz ändern / löschen
GET POST /api/connections Git-Verbindungen
PATCH DELETE /api/connections/:id Verbindung ändern / löschen
POST /api/connections/:id/check Verbindung und Token testen
GET /api/connections/:id/repos Zugängliche Repositories auflisten

Beispiel — Idee per Kommandozeile anlegen:

curl -X POST http://localhost:3000/api/projects \
  -H "Content-Type: application/json" \
  -d '{"name":"Neue Idee","status":"IDEA","tags":["experiment"]}'

Sicherheit

Bereich Umsetzung
Anmeldung Passwort-Hashing mit scrypt (N=32768, r=8, p=1), serverseitige Sitzungen — in der Datenbank liegt nur der SHA-256-Hash des Cookie-Tokens
Passkeys WebAuthn über SimpleWebAuthn, Challenges einmalig verwendbar und in der DB abgelegt, Signaturzähler wird fortgeschrieben
Cookies HttpOnly, SameSite=Lax, Secure automatisch bei https
CSRF Jede schreibende Anfrage muss vom eigenen Origin kommen (Sec-Fetch-Site / Origin); zusätzlich wird Content-Type: application/json erzwungen, was den Formular-Trick ohne Preflight ausschließt
CSP Strikte Policy mit Per-Request-Nonce und strict-dynamic, dazu frame-ancestors 'none', object-src 'none', base-uri 'none'
Weitere Header X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, Cross-Origin-Opener-Policy, Cross-Origin-Resource-Policy
SSRF Die Basis-URL einer Git-Verbindung ist Benutzereingabe. Vor jedem ausgehenden Aufruf werden Hostname und alle aufgelösten IPs geprüft (auch nach Redirects); Loopback, Link-Local samt Cloud-Metadaten, Multicast und CGNAT sind gesperrt
Datentrennung Jede Abfrage filtert auf den Besitzer. Fremde IDs liefern 404, nicht 403 — die Antwort verrät also nicht einmal, dass es den Datensatz gibt
Rate-Limiting Anmeldung pro IP und Konto, ausgehende Git-Aufrufe, WebAuthn-Optionen; Konto sperrt sich nach 8 Fehlversuchen für 15 Minuten
Eingaben Zod-Schemas an jeder API-Grenze, Body auf 256 KB begrenzt
Git-Tokens AES-256-GCM, Schlüssel per scrypt aus APP_SECRET. Werden nie an den Browser ausgeliefert — die API zeigt nur ghp_…9f3a
Sitzungsende Deaktivieren, Löschen oder ein neues Passwort beenden sofort alle Sitzungen des Kontos

Grenzen, die du kennen solltest:

  • Ist APP_SECRET nicht gesetzt, warnt die App beim Start und nutzt einen unsicheren Entwicklungsschlüssel.
  • Ohne Origin- und Sec-Fetch-Site-Header wird eine schreibende Anfrage durchgelassen. Das betrifft nur Nicht-Browser-Clients (curl, Skripte) und ist bewusst so, damit die API skriptbar bleibt — ein CSRF-Vektor ist es nicht, weil jeder Browser mindestens einen der beiden Header sendet.
  • Das Rate-Limiting liegt im Arbeitsspeicher und wird beim Neustart zurückgesetzt.
  • Es gibt kein HSTS und keine TLS-Terminierung. Für den Betrieb im Internet gehört ein Reverse Proxy mit gültigem Zertifikat davor — der ist ohnehin nötig, damit Passkeys funktionieren.
  • Passwort-Zurücksetzen per E-Mail gibt es nicht; ein Administrator setzt Passwörter neu.

Fehlersuche

Symptom Ursache / Lösung
Can't reach database server Läuft npm run docker:db? Ein blosses docker compose up -d db startet die DB ohne Host-Port — dann ist sie von npm run dev aus nicht erreichbar. Stimmt DATABASE_URL?
The table ... does not exist Migrationen fehlen: npm run db:migrate
Sync meldet 401 Token abgelaufen oder falsche Scopes — unter Git-Verbindungen neu setzen
Sync meldet 404 Owner/Repo prüfen; bei GitLab gehört die volle Gruppenkette in „Owner"
Sync meldet 403 Rate-Limit Ohne Token ist das Limit sehr niedrig — Token hinterlegen
Tokens plötzlich ungültig APP_SECRET wurde geändert — Tokens neu eintragen
Port 3000 belegt APP_PORT in der .env ändern (Docker) bzw. npm run dev -- -p 3001
package.json#prisma is deprecated Harmlose Warnung von Prisma 6.19. Die Umstellung auf prisma.config.ts steht aus, weil dann die .env nicht mehr automatisch geladen wird — vor Prisma 7 zu erledigen
Passkey-Knopf fehlt / „kein sicherer Kontext" APP_URL zeigt weder auf https:// noch auf http://localhost
Passkey wird nicht akzeptiert APP_URL weicht von der aufgerufenen Adresse ab, oder der Hostname wurde geändert (RP-ID)
Nach docker compose down -v ist alles weg Das Volume enthielt Konten und Projekte — -v löscht es
Kein Zugriff auf die eigene Gitea im LAN Läuft sie auf demselben Rechner? Dann GIT_ALLOW_LOOPBACK=true setzen

Getestet mit

Stand 25.07.2026 gegen echte Systeme verifiziert — beide Betriebsarten, alle drei Git-Adapter (GitHub, GitLab und Gitea jeweils gegen die öffentliche Instanz).

Version
Node.js 26.5.0
npm 11.17.0
Next.js 15.5.21
Prisma 6.19.3
PostgreSQL 17 (Alpine)
Docker / Compose 29.6.2 / v5.3.1

Lizenz

MIT — siehe LICENSE.

S
Description
No description provided
Readme MIT
2.3 MiB
Languages
TypeScript 95.9%
CSS 1.7%
Shell 1.5%
PowerShell 0.4%
Dockerfile 0.3%
Other 0.2%