diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..90c2e10
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,29 @@
+# --- Datenbank ---
+POSTGRES_USER=isms
+POSTGRES_PASSWORD=isms
+POSTGRES_DB=isms
+DATABASE_URL=postgresql://isms:isms@localhost:5432/isms?schema=public
+
+# --- Redis (BullMQ) ---
+REDIS_URL=redis://localhost:6379
+
+# --- Objektspeicher (MinIO / S3-kompatibel) ---
+S3_ENDPOINT=http://localhost:9000
+S3_ACCESS_KEY=isms
+S3_SECRET_KEY=isms-secret
+S3_BUCKET=isms-documents
+
+# --- Auth ---
+AUTH_SECRET=change-me-generate-with-openssl-rand-base64-32
+AUTH_URL=http://localhost:3000
+
+# --- KI-Provider (anthropic | openai) ---
+AI_PROVIDER=anthropic
+AI_API_KEY=
+
+# --- E-Mail (Dev: Mailhog) ---
+SMTP_HOST=localhost
+SMTP_PORT=1025
+SMTP_USER=
+SMTP_PASSWORD=
+SMTP_FROM=isms@example.com
diff --git a/.gitignore b/.gitignore
index 5ef6a52..7b8da95 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,6 +32,7 @@ yarn-error.log*
# env files (can opt-in for committing if needed)
.env*
+!.env.example
# vercel
.vercel
diff --git a/AGENTS.md b/AGENTS.md
index 8bd0e39..f87cd61 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -3,3 +3,32 @@
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
+
+# ISMS-Tool — Projektregeln
+
+Multi-Tenant-SaaS für Informationssicherheits-Managementsysteme (ISO/IEC 27001:2022, TISAX/VDA-ISA 6.0).
+
+**Maßgebliche Spezifikation: [docs/SPEC.md](docs/SPEC.md)** — Architektur, Datenmodell, Module, Rollen, Akzeptanzkriterien. UI-Referenz: [docs/ISMS-Prototyp-GEFIM.html](docs/ISMS-Prototyp-GEFIM.html) (Orientierung für Navigation/Layout; fachlich gilt die Spec, die über das Mockup hinausgeht).
+
+## Eiserne Regeln
+
+1. **Mandanten-Isolation:** Kein DB-Zugriff an Prisma vorbei, kein Query ohne Tenant-Kontext. Fachliche Tabellen tragen `tenant_id`; Zugriff nur über den Tenant-Guard (`src/server/db.ts`), zusätzlich Postgres RLS.
+2. **RBAC serverseitig:** Jede Mutation/Query prüft Permissions am Server (`asset:read`, `risk:write`, …). UI-Ausblenden ist nur Komfort, nie Sicherheit.
+3. **Audit-Log:** Jede schreibende Aktion erzeugt einen `AuditLog`-Eintrag (before/after).
+4. **i18n:** Keine hartkodierten UI-Texte — alle Strings über den Message-Katalog (`de` default, `en` vorbereitet).
+5. **Lizenz:** Keine ISO-Normtexte oder VDA-ISA-Kataloginhalte einchecken — nur Control-Referenzen/Titel; VDA-ISA-Inhalte kommen per Kunden-Import (`ISA6-EN.xlsx`).
+
+## Stack & Konventionen
+
+- Next.js (App Router) + TypeScript, Tailwind CSS 4, shadcn/ui, dnd-kit, Recharts.
+- Prisma + PostgreSQL 16 (pgvector), BullMQ + Redis (Worker), MinIO (S3), Auth.js (Credentials, Argon2id).
+- Tests: Vitest (Unit), Playwright (E2E). `npm run lint` und `npm run build` müssen vor jedem Commit grün sein.
+- Sprache: UI und Fachbegriffe Deutsch; Code (Bezeichner, Kommentare) Englisch.
+
+## Entwicklung
+
+```bash
+docker compose up -d postgres redis minio # Infrastruktur
+npx prisma migrate dev # Migrationen
+npm run dev # App auf :3000
+```
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..52de3a5
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,23 @@
+# ISMS-Tool — Next.js App (Multi-Stage-Build)
+FROM node:22-alpine AS deps
+WORKDIR /app
+COPY package.json package-lock.json ./
+COPY prisma ./prisma
+RUN npm ci
+
+FROM node:22-alpine AS builder
+WORKDIR /app
+COPY --from=deps /app/node_modules ./node_modules
+COPY . .
+RUN npx prisma generate && npm run build
+
+FROM node:22-alpine AS runner
+WORKDIR /app
+ENV NODE_ENV=production
+RUN addgroup -S app && adduser -S app -G app
+COPY --from=builder /app/.next/standalone ./
+COPY --from=builder /app/.next/static ./.next/static
+COPY --from=builder /app/public ./public
+USER app
+EXPOSE 3000
+CMD ["node", "server.js"]
diff --git a/README.md b/README.md
index e215bc4..95cb9b4 100644
--- a/README.md
+++ b/README.md
@@ -1,36 +1,42 @@
-This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
+# ISMS-Tool
-## Getting Started
+Multi-Tenant-SaaS zum Betrieb eines Informationssicherheits-Managementsystems (ISMS), ausgerichtet auf **ISO/IEC 27001:2022** und **TISAX / VDA-ISA 6.0**.
-First, run the development server:
+📄 Vollständige Spezifikation: [docs/SPEC.md](docs/SPEC.md) · UI-Mockup: [docs/ISMS-Prototyp-GEFIM.html](docs/ISMS-Prototyp-GEFIM.html)
+
+## Module
+
+- **Assets & BIA** — Asset-Inventar und Business Impact Analyse als gemeinsames Modul (Schutzbedarf, RTO/RPO/MTD, primäre/sekundäre Assets, zugeordnete Risiken)
+- **Risikoanalyse** — 5×5-Heatmap mit Drag-and-Drop, Detailansicht mit Maßnahmen, betroffenen Assets und Rest-Risiko
+- **SoA & Control-Kataloge** — ISO 27001:2022 Annex A (93 Controls), VDA-ISA-6.0-Struktur mit Reifegraden
+- **Maßnahmen** — Kanban, wiederkehrende Aufgaben, Fristen und Eskalation
+- **Vorfälle, Audits, Lieferanten, Nachweise, Richtlinien (KI-Assistent), RAG-Chat, Dashboards, Management-Review**
+
+## Tech-Stack
+
+Next.js (App Router, TypeScript) · Prisma + PostgreSQL 16 (pgvector) · BullMQ + Redis · MinIO (S3) · Auth.js · Tailwind CSS + shadcn/ui · Docker Compose
+
+## Quickstart (Entwicklung)
```bash
-npm run dev
-# or
-yarn dev
-# or
-pnpm dev
-# or
-bun dev
+cp .env.example .env # Werte anpassen
+docker compose up -d postgres redis minio # Infrastruktur starten
+npm install
+npx prisma migrate dev # Datenbank migrieren
+npm run dev # http://localhost:3000
```
-Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
+Produktions-Stack (App + Worker + Infrastruktur):
-You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+```bash
+docker compose up -d --build
+```
-This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
+## Projektstruktur
-## Learn More
-
-To learn more about Next.js, take a look at the following resources:
-
-- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
-- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
-
-You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
-
-## Deploy on Vercel
-
-The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
-
-Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
+```
+docs/ Spezifikation (SPEC.md) und UI-Mockup
+prisma/ Datenbankschema, Migrationen, Seeds
+src/app/ Next.js App Router (UI + API)
+src/server/ Server-Logik (Tenant-Guard, RBAC, Services)
+```
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..6af1740
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,72 @@
+services:
+ app:
+ build: .
+ ports:
+ - "3000:3000"
+ env_file: .env
+ depends_on:
+ postgres:
+ condition: service_healthy
+ redis:
+ condition: service_started
+ minio:
+ condition: service_started
+ restart: unless-stopped
+
+ worker:
+ build: .
+ command: ["npm", "run", "worker"]
+ env_file: .env
+ depends_on:
+ postgres:
+ condition: service_healthy
+ redis:
+ condition: service_started
+ restart: unless-stopped
+
+ postgres:
+ image: pgvector/pgvector:pg16
+ environment:
+ POSTGRES_USER: ${POSTGRES_USER:-isms}
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-isms}
+ POSTGRES_DB: ${POSTGRES_DB:-isms}
+ volumes:
+ - pgdata:/var/lib/postgresql/data
+ ports:
+ - "5432:5432"
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-isms}"]
+ interval: 5s
+ timeout: 5s
+ retries: 10
+
+ redis:
+ image: redis:7-alpine
+ volumes:
+ - redisdata:/data
+ ports:
+ - "6379:6379"
+
+ minio:
+ image: minio/minio:latest
+ command: server /data --console-address ":9001"
+ environment:
+ MINIO_ROOT_USER: ${MINIO_ROOT_USER:-isms}
+ MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-isms-secret}
+ volumes:
+ - miniodata:/data
+ ports:
+ - "9000:9000"
+ - "9001:9001"
+
+ mailhog:
+ image: mailhog/mailhog:latest
+ profiles: ["dev"]
+ ports:
+ - "1025:1025"
+ - "8025:8025"
+
+volumes:
+ pgdata:
+ redisdata:
+ miniodata:
diff --git a/docs/ISMS-Prototyp-GEFIM.html b/docs/ISMS-Prototyp-GEFIM.html
new file mode 100644
index 0000000..ece0bea
--- /dev/null
+++ b/docs/ISMS-Prototyp-GEFIM.html
@@ -0,0 +1,753 @@
+
+
+
+
+
+GEFIM ISMS – Prototyp
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/SPEC.md b/docs/SPEC.md
new file mode 100644
index 0000000..d22e748
--- /dev/null
+++ b/docs/SPEC.md
@@ -0,0 +1,310 @@
+# ISMS-Plattform – Umsetzungsspezifikation
+
+> **Version 1.2** · Ergänzt gegenüber 1.1: **Assets & BIA als ein gemeinsames Modul**, zugeordnete Risiken in Asset-/Prozess-Detailansichten, ausgearbeitete **Risiko-Detailansicht** (Maßnahmen, betroffene Assets, Control-Verknüpfung, Verlauf).
+>
+> Diese Datei ist die Projekt-Spec für die Umsetzung durch Claude Code.
+> Sie beschreibt **Architektur, Datenmodell, Module, Rollen, API und Akzeptanzkriterien**.
+> Sprache der Anwendung: **Deutsch (i18n-fähig, EN vorbereitet)**.
+
+## 0. Kontext & Leitentscheidungen
+
+Es wird eine Web-Applikation zum Betrieb eines Informationssicherheits-Managementsystems (ISMS) entwickelt, die von mehreren Kunden (Mandanten) mit mehreren Nutzern und Rollen genutzt wird. Ausrichtung auf **ISO/IEC 27001:2022** und **TISAX / VDA-ISA 6.0**.
+
+Getroffene Entscheidungen (aus Anforderungsklärung):
+
+| Thema | Entscheidung |
+|---|---|
+| Betriebsmodell | Zentrale SaaS, **Multi-Tenant** (gemeinsame DB, Mandanten-ID + strikte Row-Level-Trennung) |
+| Container | Betrieb in Docker (Compose), horizontal skalierbar |
+| KI / Assistent + Chat | **Cloud-LLM** (Anthropic/OpenAI) über austauschbaren Provider-Adapter |
+| Tech-Stack | Modernes Web-Frontend, Technologie offen → **empfohlener Stack unten** |
+| Authentifizierung | **Lokale Accounts (MVP)** mit RBAC; SSO (OIDC/SAML) als spätere Erweiterung vorbereiten |
+| Umfang | Alle Module gleichwertig (kein hartes Phasing), aber sinnvolle Iterationsreihenfolge |
+| Norm-Inhalte | **ISO 27001:2022 Annex A (93 Controls)** vorbefüllt + SoA; **VDA-ISA** Struktur/Mapping vorbereitet, Katalog-Inhalte per Import (lizenzrechtlich, siehe §12) |
+| Sprache | Deutsch, i18n-ready |
+| UX | Modern, einfach, geringe Komplexität, Drag-and-Drop, grafische Oberflächen |
+
+## 1. Empfohlener Tech-Stack
+
+Ziel: **eine** Codebasis, geringe Betriebs- und Wartungskomplexität, moderne UX.
+
+- **Frontend & Backend:** Next.js 15 (App Router, React 19, TypeScript) — SSR + API in einem Deployment.
+- **API-Layer:** tRPC (typsicher) oder REST (OpenAPI). Empfehlung: tRPC intern, zusätzlich schlanke REST-Endpunkte für Integrationen/Webhooks.
+- **ORM/DB:** Prisma + **PostgreSQL 16**. Vektorsuche für den Chat/RAG über **pgvector** (kein zusätzlicher Vektor-DB-Dienst nötig).
+- **Auth:** Auth.js (NextAuth) mit Credentials-Provider (lokale Accounts), Argon2id-Hashing, TOTP-2FA. OIDC/SAML-Provider als Feature-Flag vorbereitet.
+- **Hintergrundjobs / wiederkehrende Aufgaben:** BullMQ + Redis (Scheduler für Reviews, Audits, Fristen, Erinnerungen).
+- **Dateispeicher:** S3-kompatibel (MinIO im Compose-Stack), verschlüsselt.
+- **UI-Kit:** Tailwind CSS + shadcn/ui, Icons via lucide-react, Diagramme via Recharts.
+- **Drag-and-Drop:** dnd-kit (Kanban-Boards, Risiko-Matrix-Einordnung, Aufgaben, Datei-Uploads).
+- **KI-Anbindung:** Provider-Adapter (`AiProvider`-Interface) für Anthropic/OpenAI; RAG-Pipeline auf Dokumenten des Mandanten.
+- **E-Mail:** SMTP (Benachrichtigungen, Fristen, Eskalationen).
+- **Tests:** Vitest (Unit), Playwright (E2E). Linting: ESLint + Prettier.
+
+> Alternative bei starkem KI-/Analytics-Fokus: zusätzlicher **Python-FastAPI-Microservice** nur für RAG/Embedding. Für geringe Komplexität zunächst **nicht** empfohlen — alles in Next.js.
+
+## 2. Architektur (High-Level)
+
+```
+ ┌─────────────────────────────────────────────┐
+ Browser ───▶ │ Next.js (App Router) │
+ (DE UI) │ - React UI (Tailwind + shadcn/ui, dnd-kit) │
+ │ - tRPC/REST API │
+ │ - Auth.js (RBAC, Mandanten-Guard) │
+ └───────┬───────────────┬──────────────┬───────┘
+ │ │ │
+ Prisma BullMQ AiProvider
+ │ (Worker) (Adapter)
+ ┌───────▼───────┐ ┌───▼────┐ ┌────▼─────────┐
+ │ PostgreSQL 16 │ │ Redis │ │ Anthropic / │
+ │ + pgvector │ │ │ │ OpenAI API │
+ └───────────────┘ └────────┘ └──────────────┘
+ ┌───────────────┐
+ │ MinIO (S3) │ Dokumente, Nachweise, Uploads
+ └───────────────┘
+```
+
+**Mandantenfähigkeit (Multi-Tenant):** Jede fachliche Tabelle trägt `tenant_id`. Zugriff ausschließlich über einen zentralen Prisma-Middleware-/Query-Guard, der `tenant_id` aus der Session erzwingt (Row-Level-Isolation). Zusätzlich Postgres **Row Level Security (RLS)** als zweite Verteidigungslinie. Kein Query ohne Mandantenkontext.
+
+## 3. Rollen- und Rechtemodell (RBAC)
+
+Rollen sind pro Mandant vergeben. Ein Nutzer kann mehrere Rollen haben.
+
+| Rolle | Beschreibung | Kernrechte |
+|---|---|---|
+| **Plattform-Admin** (mandantenübergreifend) | Betreiber der SaaS | Mandanten anlegen/sperren, globale Kataloge pflegen, keine Einsicht in Kundendaten außer für Support (protokolliert) |
+| **Mandanten-Admin** | Kundenadministrator | Nutzer/Rollen im Mandanten verwalten, Stammdaten, Konfiguration |
+| **ISB / CISO** | Informationssicherheitsbeauftragter | Vollzugriff fachlich: Risiken, Assets, BIA, Maßnahmen, Vorfälle, Freigaben, Chat-Eskalationsziel |
+| **Auditor** (intern/extern) | Prüfer | Lesezugriff + Audit-Durchführung, Findings anlegen, keine Bearbeitung der Fachdaten |
+| **Asset-/Risk-Owner** | Fachverantwortliche | Bearbeitung zugewiesener Assets/Risiken/Maßnahmen |
+| **Mitarbeiter / User** | Standardnutzer | Chat nutzen, Richtlinien lesen, Vorfälle melden, eigene Aufgaben |
+
+Rechte werden als granulare **Permissions** (`asset:read`, `risk:write`, `incident:manage`, …) implementiert und über Rollen gebündelt. UI blendet nicht-erlaubte Aktionen aus; API prüft serverseitig.
+
+## 4. Module (funktionaler Kern)
+
+### 4.1 Assets & BIA (ein gemeinsames Modul)
+
+Asset-Inventar und Business Impact Analyse bilden **ein zusammenhängendes Modul** (gemeinsamer Navigationsbereich, durchgängige Detailansichten). Assets, Prozesse und deren Kritikalität werden im selben Kontext gepflegt.
+
+#### 4.1.1 Asset-Inventar
+Zentrales Verzeichnis aller Werte (Assets): Informationen, Systeme, Anwendungen, Standorte, Lieferanten, Personen/Rollen, Datenkategorien.
+
+- Attribute: Name, Typ, Owner, Standort/Prozesszuordnung, Klassifizierung (C/I/A — Vertraulichkeit/Integrität/Verfügbarkeit als Schutzbedarf 1–4), Lieferanten/Verantwortliche, Status, Tags.
+- Beziehungen zwischen Assets (Abhängigkeiten) modellierbar → speist BIA und Risiko.
+- Import/Export (Excel/CSV), Bulk-Bearbeitung, Versionshistorie.
+- **Grafische Ansicht:** filterbare Tabelle + optionale Abhängigkeits-/Netzwerkgrafik.
+- **Asset-Detailansicht** zeigt neben Stammdaten und Beziehungen auch:
+ - **Zugeordnete Risiken** (mit Risikowert, Status, Behandlung) inkl. Absprung in die Risiko-Detailansicht,
+ - zugeordnete Prozesse (mit Rolle primär/sekundär) und daraus vererbter Schutzbedarf,
+ - verknüpfte Maßnahmen, Vorfälle und Nachweise.
+
+#### 4.1.2 Business Impact Analyse (BIA)
+Ermittelt Kritikalität von Prozessen/Assets und Wiederanlaufparameter.
+
+- Erfassung von Geschäftsprozessen, Zuordnung zu Assets.
+- **Asset-Rollen je Prozess (Detailansicht):** In der Prozess-Detailansicht werden die zugeordneten Assets nach Rolle unterschieden:
+ - **Primäres Asset** = das im Prozess erzeugte/verantwortete Ergebnis-Asset (z. B. der erzeugte Datensatz/das Informationsobjekt). Genau ein oder wenige je Prozess.
+ - **Sekundäre Assets** = alle unterstützenden Assets, die zur Prozessdurchführung benötigt werden (Systeme, Anwendungen, Infrastruktur, Personen/Rollen, Lieferanten).
+ - Die Rollenzuordnung speist die Abhängigkeitsanalyse (siehe 4.11) und die Schutzbedarfsvererbung: Der Schutzbedarf des primären Assets/Prozesses vererbt sich auf die sekundären Assets (max. Prinzip).
+- Schadensszenarien und Schadenshöhe je Schutzziel und Zeitverlauf.
+- Kennzahlen: **RTO, RPO, MTD/MTPD**, maximal tolerierbarer Ausfall.
+- Ergebnis: Kritikalitätsstufe je Prozess/Asset → priorisiert Risikoanalyse und Maßnahmen.
+- **Prozess-Detailansicht** zeigt zusätzlich die **zugeordneten Risiken** des Prozesses und seiner Assets (aggregiert, mit Risikowert und Status).
+- Geführter Wizard (Schritt-für-Schritt), Ergebnis als Report exportierbar.
+
+### 4.2 Risikoanalyse & -behandlung
+Aufbauend auf Assets + BIA.
+
+- Risiken = (Asset/Prozess) × Bedrohung × Schwachstelle.
+- Bewertung: Eintrittswahrscheinlichkeit × Auswirkung → Risikowert; konfigurierbare Skalen (z. B. 5×5).
+- **Interaktive Risiko-Matrix (Heatmap)** mit Drag-and-Drop-Einordnung/Filter.
+- Risikobehandlung: Vermeiden / Vermindern / Übertragen / Akzeptieren; Maßnahmen (Controls) verknüpfen.
+- Rest-Risiko nach Maßnahme, Risikoakzeptanz mit Freigabe-Workflow (ISB/Leitung).
+- Vererbung: Schutzbedarf aus Asset/BIA wird vorbelegt.
+- Verknüpfung zu ISO-27001-Annex-A-Controls und VDA-ISA-Zielen (SoA-Bezug).
+- **Risiko-Detailansicht (vollständig):**
+ - Stammdaten: Beschreibung, Bedrohung/Schwachstelle, Owner, Status, Termine/Reviews.
+ - Bewertung: Brutto-Risiko (Wahrscheinlichkeit × Auswirkung), **Rest-Risiko** nach Maßnahmen, Bewertungshistorie (Verlauf des Risikowerts über Zeit).
+ - **Notwendige/verknüpfte Maßnahmen:** Liste der behandelnden Maßnahmen mit Status, Fälligkeit und Owner; neue Maßnahme direkt aus dem Risiko heraus anlegbar.
+ - **Betroffene Assets/Prozesse:** alle verknüpften Assets und Prozesse mit Schutzbedarf/Kritikalität, Absprung in deren Detailansichten.
+ - Verknüpfte Annex-A-Controls / VDA-ISA-Ziele (SoA-Bezug) und ggf. auslösende Vorfälle.
+ - Freigabe-/Akzeptanz-Workflow mit Kommentar und Audit-Trail.
+
+### 4.3 Control-Kataloge & Statement of Applicability (SoA)
+- **ISO 27001:2022 Annex A** mit 93 Controls in 4 Themen (Organisatorisch 37, Personenbezogen 8, Physisch 14, Technologisch 34) **vorbefüllt**.
+- **SoA:** je Control Anwendbarkeit (ja/nein + Begründung), Umsetzungsstatus, Verweise auf Maßnahmen/Nachweise, Verantwortliche.
+- **VDA-ISA 6.0**: 9 Kapitel/Prüfziele als Struktur + Mapping-Tabelle ISO↔VDA-ISA (siehe §12 zur Lizenz).
+- Reifegrad-Bewertung (VDA-ISA-Reifegradmodell 0–5) je Prüfziel.
+
+### 4.4 Maßnahmenverwaltung (Controls/Tasks)
+- Maßnahmen mit Owner, Fälligkeit, Status, Priorität, Nachweisen (Dateien).
+- **Kanban-Board (Drag-and-Drop)** und Listen-/Kalenderansicht.
+- Verknüpfung zu Risiken, Controls, Vorfällen, Audits.
+- **Maßnahmen-Detailansicht** zeigt die **zugeordneten Risiken** (welche Risiken behandelt diese Maßnahme, mit Risikowert vor/nach) sowie verknüpfte Controls, Vorfälle und Nachweise.
+
+### 4.5 Wiederkehrende Aufgaben & Fristen (Scheduler)
+Automatische Erzeugung/Erinnerung für u. a.:
+- **Benutzer-/Zugriffs-Review** (z. B. quartalsweise),
+- **Interne Audits** und **externe Audits/Re-Zertifizierung** (Zyklen),
+- **Management-Review**, Richtlinien-Review, Risiko-Review, Lieferanten-Review.
+- Konfigurierbare Wiederholung (cron-artig), Zuweisung, Eskalation bei Überfälligkeit, E-Mail-Benachrichtigung, Dashboard-Fälligkeitsanzeige.
+
+### 4.6 Richtlinien-Management & Implementierungs-Assistent
+- Richtlinien-Bibliothek mit Versionierung, Freigabe- und Lese-Bestätigungs-Workflow.
+- **KI-Assistent** führt Nutzer durch die Anpassung von Muster-Richtlinien an das eigene Unternehmen.
+- **Zwei Individualisierungs-Ebenen:**
+ 1. **Basisdaten/Metadaten:** Firmenname, verantwortliche Rollen, Geltungsbereich, Platzhalter.
+ 2. **Inhaltliche Anpassung der Klauseln:** Die KI formuliert und passt die eigentlichen Richtlinientexte (Klauseln/Abschnitte) auf Basis der Unternehmensangaben an (z. B. erlaubte Geräte, Fristen, Verantwortlichkeiten, branchenspezifische Anforderungen). Vorschläge sind akzeptier-/verwerfbar.
+- **Inline-Editor (WYSIWYG):** Nutzer bearbeiten die generierten Klauseltexte direkt im Tool; KI-Assistenz („umformulieren", „kürzen", „an Control X ausrichten") auf Absatzebene.
+- **In-Tool-Darstellung:** Die Richtlinie wird innerhalb der Anwendung gerendert lesbar dargestellt (formatierte Ansicht, Inhaltsverzeichnis, verknüpfte Controls), nicht nur als Download.
+- **Governance:** Versionierung mit Änderungsverlauf/Diff, Freigabe-Workflow, Lesebestätigung durch Mitarbeiter, Verknüpfung zu ISO-/VDA-Controls.
+- Export als PDF/DOCX; Ablage in der Richtlinien-Bibliothek; Anbindung an den Chat (RAG) als Wissensquelle.
+
+### 4.7 Interaktiver Chat (RAG + Eskalation)
+- Nutzer stellen Fragen; der Chat sucht per **RAG** in der Dokumentation/Richtlinien des Mandanten (pgvector) und antwortet mit Quellenangabe.
+- Wenn keine belastbare Antwort/Berechtigung → **Eskalation/Ticket an den ISB** (Weiterleitung, Benachrichtigung, Nachverfolgung).
+- Nur mandanten-eigene Dokumente im Kontext; keine mandantenübergreifende Vermischung.
+
+### 4.8 Sicherheitsvorfall-Management (Incident)
+- Meldung von Vorfällen (auch niedrigschwellig durch Mitarbeiter, Formular + Chat).
+- Workflow: Erfassung → Triage/Kategorisierung → Bearbeitung → Eskalation → Abschluss → Lessons Learned.
+- Schweregrad, betroffene Assets, SLA/Fristen, Aufgaben, Zeitleiste, Nachweise.
+- Verknüpfung zu Risiken (neue/erhöhte Risiken) und ggf. Meldepflichten-Hinweis.
+
+### 4.9 Dashboards & Reporting
+- Rollenbezogene Dashboards (ISB, Auditor, Owner): offene Risiken, überfällige Aufgaben, SoA-Erfüllungsgrad, Reifegrade, Vorfälle.
+- Exporte: SoA, Risikoregister, Maßnahmenplan, Audit-Report, Management-Review — als PDF/Excel.
+
+### 4.10 Audit-Management
+- Audit-Plan (intern/extern), Scope, Prüfpunkte (aus Katalogen), Findings, Maßnahmen aus Findings, Nachverfolgung, Audit-Report.
+
+### 4.11 Abhängigkeits- & Kritische-Pfade-Analyse
+Visualisiert die Verkettung von Prozessen und Assets, um Single Points of Failure und kritische Pfade sichtbar zu machen.
+
+- **Netzwerkgraph:** Knoten = Prozesse und Assets (primär/sekundär), Kanten = Abhängigkeiten (aus Asset-Relationen und BIA-Rollenzuordnung).
+- **Kritische Pfade** werden anhand von Kritikalität/Schutzbedarf (aus BIA) berechnet und farblich hervorgehoben; Engstellen (Assets, von denen viele kritische Prozesse abhängen) werden markiert.
+- Interaktiv: Filtern nach Prozess/Kritikalität, Knoten anklicken → Detail/Sprung zum Asset, Hervorheben aller abhängigen Elemente.
+- Speist Risikoanalyse (Konzentrationsrisiken) und BCM/Notfallplanung.
+- Umsetzungshinweis: Rendering mit einer Graph-Bibliothek (z. B. Cytoscape.js oder D3-Force); Datenbasis sind `AssetRelation` und die BIA-Primär-/Sekundär-Zuordnung.
+
+### 4.12 Nachweis- & Dokumentenmanagement
+- Zentrale, auditfeste Ablage für Nachweise/Evidenzen (Dateien, Screenshots, Protokolle).
+- Verknüpfung eines Nachweises mit Controls (SoA), Maßnahmen, Audits, Risiken und Vorfällen.
+- Metadaten: Gültigkeit/Ablaufdatum, Verantwortliche, Version, Vertraulichkeit; Erinnerung bei ablaufenden Nachweisen.
+- Volltext-/Metadatensuche; Nachweise sind Quelle für den RAG-Chat.
+
+### 4.13 Lieferanten- & Dienstleister-Management (Third-Party)
+Für TISAX besonders relevant.
+
+- Verzeichnis externer Dienstleister/Lieferanten mit Kontakt, Leistungen, Kritikalität.
+- Sicherheitsbewertung/Fragebögen, Zertifikatsnachweise (z. B. ISO 27001/TISAX-Label), Ablaufüberwachung.
+- Vertrags-/AV-Verwaltung (DSGVO Art. 28), Wiedervorlage/Review-Zyklen (siehe wiederkehrende Aufgaben).
+- Verknüpfung zu Assets (welcher Dienstleister betrifft welche Assets) und Risiken (Third-Party-Risiko).
+
+### 4.14 Management-Review & Kennzahlen (KPIs)
+ISO-27001-Pflichtthemen zur Wirksamkeitsmessung.
+
+- Definierbare Kennzahlen/Metriken (z. B. SoA-Erfüllungsgrad, offene Risiken, Reaktionszeiten Vorfälle, überfällige Aufgaben, Reifegradentwicklung) mit Zielwerten und Trend.
+- Strukturierte **Management-Review**-Vorlage (Eingaben, Ergebnisse, Beschlüsse, Verantwortliche, Termine) mit Historie.
+- Wirksamkeitsbewertung von Maßnahmen; Export als Management-Report (PDF).
+
+## 5. Datenmodell (Kern-Entitäten, vereinfacht)
+
+Alle fachlichen Tabellen enthalten `tenant_id`, `created_at`, `updated_at`, `created_by`.
+
+- **Tenant**(id, name, status, config)
+- **User**(id, tenant_id, email, password_hash, name, status, mfa_secret)
+- **Role**(id, tenant_id, key, name) / **Permission** / **UserRole** / **RolePermission**
+- **Asset**(id, tenant_id, name, type, owner_id, classification_c/i/a, status, tags)
+- **AssetRelation**(asset_id, related_asset_id, type)
+- **Process**(id, tenant_id, name, owner_id) — BIA-Bezug
+- **ProcessAsset**(id, tenant_id, process_id, asset_id, **role** = `primary` | `secondary`) — Asset-Rolle je Prozess (BIA)
+- **BiaEntry**(id, tenant_id, process_id, rto, rpo, mtd, impact_scores, criticality)
+- **Threat** / **Vulnerability** (Kataloge, teils global)
+- **Risk**(id, tenant_id, asset_id/process_id, threat_id, likelihood, impact, score, treatment, residual_score, owner_id, status)
+- **RiskAsset**(risk_id, asset_id) — n:m betroffene Assets je Risiko (zusätzlich zum Hauptbezug)
+- **RiskMeasure**(risk_id, measure_id) — n:m Risiko ↔ behandelnde Maßnahmen
+- **Control**(id, framework, ref, title, theme) — global (ISO/VDA)
+- **Soa**(id, tenant_id, control_id, applicable, justification, status, maturity, owner_id)
+- **Measure/Task**(id, tenant_id, title, owner_id, due_date, status, priority, links[])
+- **RecurringTask**(id, tenant_id, type, schedule_cron, next_run, assignee)
+- **Policy**(id, tenant_id, title, version, status, body, ack_required)
+- **Document/Evidence**(id, tenant_id, name, storage_key, embedding[] via pgvector)
+- **ChatSession/ChatMessage**(…, sources[], escalated_to_isb)
+- **Incident**(id, tenant_id, title, severity, status, category, affected_assets[], timeline[])
+- **Audit**(id, tenant_id, type, scope, planned_date) / **Finding**(…)
+- **Supplier**(id, tenant_id, name, criticality, contract_ref, av_status, cert_status, cert_expiry, review_cron) / **SupplierAsset**(supplier_id, asset_id)
+- **Kpi**(id, tenant_id, name, target, unit) / **KpiValue**(kpi_id, period, value)
+- **ManagementReview**(id, tenant_id, date, inputs, results, decisions, owner_id)
+- **AuditLog**(id, tenant_id, actor, action, entity, before/after, timestamp)
+
+## 6. API-Design (Auszug)
+
+REST-/tRPC-Ressourcen je Modul mit CRUD + Aktionen:
+`/assets`, `/bia`, `/risks`, `/controls`, `/soa`, `/measures`, `/recurring-tasks`, `/policies`, `/chat`, `/incidents`, `/audits`, `/reports`, `/admin/tenants`, `/admin/users`.
+
+Querschnitt: `GET /export/{modul}` (Excel/PDF), `POST /import/{modul}` (Excel/CSV), Webhooks für Fristen/Eskalationen. Jede Anfrage: Auth-Guard → Mandanten-Guard → Permission-Check → Handler → AuditLog.
+
+## 7. Nicht-funktionale Anforderungen
+
+- **Sicherheit:** Verschlüsselung at-rest (DB/Objektspeicher) und in-transit (TLS), Argon2id-Passwörter, TOTP-2FA, Session-Härtung, CSRF-/XSS-/SQLi-Schutz, striktes RBAC + Mandanten-Isolation (RLS), vollständiges Audit-Log.
+- **Datenschutz (DSGVO):** Auftragsverarbeitung, Löschkonzept, Datenminimierung; für Cloud-LLM: DPA mit KI-Anbieter, konfigurierbares Opt-out des Trainings, optionale Anonymisierung sensibler Felder vor KI-Aufruf.
+- **Performance:** Listen mit Server-Pagination/Filter; Zielantwortzeit < 300 ms für Standardabfragen.
+- **Verfügbarkeit:** Stateless App-Container (horizontal skalierbar), Backups DB + Objektspeicher, Health-/Readiness-Endpunkte.
+- **Barrierefreiheit & UX:** WCAG-AA-orientiert, responsive, konsistente Komponenten, geringe Klicktiefe.
+- **i18n:** Alle UI-Texte über Message-Katalog (de default, en vorbereitet).
+- **Nachvollziehbarkeit:** Versionierung von Richtlinien, Risiken, SoA; lückenloses Änderungsprotokoll (auditfest).
+
+## 8. Deployment (Docker)
+
+`docker-compose.yml` mit Services: `app` (Next.js), `worker` (BullMQ), `postgres` (pgvector-Image), `redis`, `minio`, optional `mailhog` (Dev). Konfiguration über `.env` (DB, Redis, S3, SMTP, `AI_PROVIDER`, `AI_API_KEY`). Migrations via Prisma. Seed-Skript befüllt globale Kataloge (ISO Annex A, VDA-ISA-Struktur, Threat-/Vuln-Beispiele) und einen Demo-Mandanten.
+
+## 9. UX-Leitlinien
+
+Modern, aufgeräumt, geringe Komplexität. Konsequenter Einsatz von: geführten Wizards (BIA, Richtlinien-Assistent), **Drag-and-Drop** (Kanban für Maßnahmen/Aufgaben, Risiko-Heatmap, Datei-Uploads), grafischen Auswertungen (Heatmaps, Reifegrad-Radar, Fortschrittsbalken), Inline-Bearbeitung und klaren, rollenbezogenen Startseiten. Fachbegriffe mit Tooltips erklärt.
+
+Das HTML-Mockup (`docs/ISMS-Prototyp-GEFIM.html`) dient als **Orientierung** für Navigation, Layout und Views — die Module werden fachlich darüber hinaus vervollständigt (z. B. Risiko-Verknüpfungen in Detailansichten, siehe §4).
+
+## 10. Akzeptanzkriterien (Definition of Done je Modul)
+
+- Ein Nutzer eines Mandanten sieht **niemals** Daten eines anderen Mandanten (durch Test nachgewiesen: RLS + Guard).
+- RBAC serverseitig erzwungen; UI blendet unerlaubte Aktionen aus.
+- Asset → BIA → Risiko → SoA/Maßnahme bilden eine durchgängige, verknüpfte Kette — in beide Richtungen navigierbar (Asset zeigt Risiken, Risiko zeigt Maßnahmen/Assets, Maßnahme zeigt Risiken).
+- Wiederkehrende Aufgaben erzeugen automatisch Instanzen, benachrichtigen und eskalieren bei Überfälligkeit.
+- Chat beantwortet Fragen mit Quellen aus Mandanten-Dokumenten und eskaliert korrekt an den ISB.
+- Incident-Workflow von Meldung bis Abschluss inkl. Zeitleiste und Nachweisen.
+- Exporte (SoA, Risikoregister, Audit-Report) erzeugen valide PDF/Excel.
+- E2E-Tests (Playwright) für die Kernpfade grün; Audit-Log erfasst alle schreibenden Aktionen.
+
+## 11. Empfohlene Umsetzungsreihenfolge (Iterationen)
+
+Auch wenn Module gleichwertig sind, minimiert diese Reihenfolge das Risiko:
+
+1. **Fundament:** Projektsetup, Docker-Compose, Auth (lokale Accounts), Mandanten-Isolation (RLS + Guard), RBAC, Audit-Log, i18n-Gerüst.
+2. **Kern-Fachdaten:** Assets & BIA (ein Modul) → Risikoanalyse (inkl. Heatmap + Detailansicht).
+3. **Compliance:** ISO-Annex-A-Katalog + SoA, VDA-ISA-Struktur + Mapping, Reifegrade.
+4. **Betrieb:** Maßnahmen-Kanban, wiederkehrende Aufgaben/Scheduler, Benachrichtigungen.
+5. **Vorfälle:** Incident-Management inkl. Meldeformular.
+6. **KI:** RAG-Chat mit Eskalation, Richtlinien-Implementierungs-Assistent.
+7. **Auswertung:** Dashboards, Reporting/Exporte, Audit-Management.
+8. **Härtung:** Sicherheits-/Datenschutz-Review, Tests, Doku.
+
+## 12. Lizenz-/Rechtshinweis zu Katalog-Inhalten (empfohlenes Vorgehen)
+
+- **ISO 27001:2022** Control-**Titel/Referenzen** (Annex A, A.5–A.8) können als Katalog abgebildet werden; der **volle Normtext** ist urheberrechtlich geschützt und darf nicht mitgeliefert werden. → Nur Kurzbezeichnungen + eigene Umsetzungshinweise, Volltext verweist der Kunde auf seine erworbene Norm.
+- **VDA-ISA 6.0 / TISAX:** Der ISA-Katalog wird vom VDA/ENX bereitgestellt (ISA6 als Excel). Empfehlung: **Struktur (9 Kapitel/Prüfziele) und Mapping** abbilden, die konkreten Katalog-Inhalte per **Import** aus der offiziellen ENX-Datei einspielen (Import-Funktion für `ISA6-EN.xlsx`). So bleibt die Anwendung lizenzkonform und aktualisierbar.
+- **Mapping ISO 27001 ↔ VDA-ISA** als pflegbare Tabelle vorsehen (Controls beeinflussen mehrere Prüfziele und umgekehrt).
+
+## 13. Offene Punkte / spätere Erweiterungen
+
+- SSO (OIDC/SAML, z. B. Entra ID) — Feature-Flag bereits vorgesehen.
+- Self-hosted-LLM-Option je Mandant (falls Datenschutzanforderungen es verlangen).
+- Meldepflichten-Assistent (NIS2/DSGVO-Fristen) im Incident-Modul.
+- Mobile App / PWA für Vorfallmeldung.
+
+---
+
+### Quellen
+- VDA-ISA / TISAX Katalog v6.0: https://portal.enx.com/en-us/TISAX/downloads/
+- VDA ISA 6.0 verpflichtend: https://vda-isa-berater.com/en/mandatory-vda-isa-catalog-version-6-0-for-all-those-who-order-the-tisax-assessment-now/
+- VDA Information Security: https://www.vda.de/en/topics/digitization/data/information-security
diff --git a/next.config.ts b/next.config.ts
index e9ffa30..566c88e 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -1,7 +1,8 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
- /* config options here */
+ // Standalone-Output für den Docker-Multi-Stage-Build (siehe Dockerfile)
+ output: "standalone",
};
export default nextConfig;
diff --git a/package-lock.json b/package-lock.json
index cf11247..18f960c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,9 +8,13 @@
"name": "isms-tool",
"version": "0.1.0",
"dependencies": {
+ "@prisma/adapter-pg": "^7.8.0",
+ "@prisma/client": "^7.8.0",
+ "dotenv": "^17.4.2",
"next": "16.2.10",
"react": "19.2.4",
- "react-dom": "19.2.4"
+ "react-dom": "19.2.4",
+ "zod": "^4.4.3"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
@@ -19,7 +23,9 @@
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "16.2.10",
+ "prisma": "^7.8.0",
"tailwindcss": "^4",
+ "tsx": "^4.22.4",
"typescript": "^5"
}
},
@@ -276,6 +282,36 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@electric-sql/pglite": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.4.1.tgz",
+ "integrity": "sha512-mZ9NzzUSYPOCnxHH1oAHPRzoMFJHY472raDKwXl/+6oPbpdJ7g8LsCN4FSaIIfkiCKHhb3iF/Zqo3NYxaIhU7Q==",
+ "devOptional": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/@electric-sql/pglite-socket": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/@electric-sql/pglite-socket/-/pglite-socket-0.1.1.tgz",
+ "integrity": "sha512-p2hoXw3Z3LQHwTeikdZNsFBOvXGqKY2hk51BBw+8NKND8eoH+8LFOtW9Z8CQKmTJ2qqGYu82ipqiyFZOTTXNfw==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "pglite-server": "dist/scripts/server.js"
+ },
+ "peerDependencies": {
+ "@electric-sql/pglite": "0.4.1"
+ }
+ },
+ "node_modules/@electric-sql/pglite-tools": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/@electric-sql/pglite-tools/-/pglite-tools-0.3.1.tgz",
+ "integrity": "sha512-C+T3oivmy9bpQvSxVqXA1UDY8cB9Eb9vZHL9zxWwEUfDixbXv4G3r2LjoTdR33LD8aomR3O9ZXEO3XEwr/cUCA==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "@electric-sql/pglite": "0.4.1"
+ }
+ },
"node_modules/@emnapi/core": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
@@ -309,6 +345,448 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz",
+ "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz",
+ "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz",
+ "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz",
+ "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz",
+ "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz",
+ "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz",
+ "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz",
+ "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz",
+ "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz",
+ "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz",
+ "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz",
+ "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz",
+ "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz",
+ "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz",
+ "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz",
+ "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz",
+ "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz",
+ "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz",
+ "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz",
+ "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz",
+ "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz",
+ "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz",
+ "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz",
+ "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz",
+ "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz",
+ "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@eslint-community/eslint-utils": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
@@ -453,6 +931,19 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/@hono/node-server": {
+ "version": "1.19.11",
+ "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz",
+ "integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.14.1"
+ },
+ "peerDependencies": {
+ "hono": "^4"
+ }
+ },
"node_modules/@humanfs/core": {
"version": "0.19.2",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
@@ -1083,6 +1574,13 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@kurkle/color": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
+ "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/@napi-rs/wasm-runtime": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz",
@@ -1306,6 +1804,387 @@
"node": ">=12.4.0"
}
},
+ "node_modules/@prisma/adapter-pg": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/@prisma/adapter-pg/-/adapter-pg-7.8.0.tgz",
+ "integrity": "sha512-ygb3UkerK3v8MDpXVgCISdRNDozpxh6+JVJgiIGbSr5KBgz10LLf5ejUskPGoXlsIjxsOu6nuy1JVQr2EKGSlg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/driver-adapter-utils": "7.8.0",
+ "@types/pg": "^8.16.0",
+ "pg": "^8.16.3",
+ "postgres-array": "3.0.4"
+ }
+ },
+ "node_modules/@prisma/client": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/@prisma/client/-/client-7.8.0.tgz",
+ "integrity": "sha512-HFp3Dawv/3sU3JtlPha90IB+48lS7zHiH4LKZPjmcE8YH5P9DOXGPvo8dqOtO7MqLDd1p2hOWMcFlRT1DMblHw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/client-runtime-utils": "7.8.0"
+ },
+ "engines": {
+ "node": "^20.19 || ^22.12 || >=24.0"
+ },
+ "peerDependencies": {
+ "prisma": "*",
+ "typescript": ">=5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "prisma": {
+ "optional": true
+ },
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@prisma/client-runtime-utils": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/@prisma/client-runtime-utils/-/client-runtime-utils-7.8.0.tgz",
+ "integrity": "sha512-5NQZztQ0oY/ADFkmd9gPuweH5A1/CCY8YQPorLLO0Mu6a87mY5gsnDkzmFmIHs9NFaLnZojzgddFVN4RpKYrdw==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@prisma/config": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/@prisma/config/-/config-7.8.0.tgz",
+ "integrity": "sha512-HFESzd9rx2ZQxlK+TL7tu1HPvCqrHiL6LCxYykI2c34mvaUuIVVl3lYuicJD/MNnzgPnyeBEMlK4WTomJCV5jw==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "c12": "3.3.4",
+ "deepmerge-ts": "7.1.5",
+ "effect": "3.20.0",
+ "empathic": "2.0.0"
+ }
+ },
+ "node_modules/@prisma/debug": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.8.0.tgz",
+ "integrity": "sha512-p+QZReysDUqXC+mk17q9a+Y/qzh4c2KYliDK30buYUyfrGeTGSyfmc0AIrJRhZJrLHhRiJa9Au/J72h3C+szvA==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@prisma/dev": {
+ "version": "0.24.3",
+ "resolved": "https://registry.npmjs.org/@prisma/dev/-/dev-0.24.3.tgz",
+ "integrity": "sha512-ffHlQuKXZiaDt9Go0OnCTdJZrHxK0k7omJKNV86/VjpsXu5EIHZLK0T7JSWgvNlJwh56kW9JFu9v0qJciFzepg==",
+ "devOptional": true,
+ "license": "ISC",
+ "dependencies": {
+ "@electric-sql/pglite": "0.4.1",
+ "@electric-sql/pglite-socket": "0.1.1",
+ "@electric-sql/pglite-tools": "0.3.1",
+ "@hono/node-server": "1.19.11",
+ "@prisma/get-platform": "7.2.0",
+ "@prisma/query-plan-executor": "7.2.0",
+ "@prisma/streams-local": "0.1.2",
+ "foreground-child": "3.3.1",
+ "get-port-please": "3.2.0",
+ "hono": "^4.12.8",
+ "http-status-codes": "2.3.0",
+ "pathe": "2.0.3",
+ "proper-lockfile": "4.1.2",
+ "remeda": "2.33.4",
+ "std-env": "3.10.0",
+ "valibot": "1.2.0",
+ "zeptomatch": "2.1.0"
+ }
+ },
+ "node_modules/@prisma/driver-adapter-utils": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/@prisma/driver-adapter-utils/-/driver-adapter-utils-7.8.0.tgz",
+ "integrity": "sha512-/Q13o0ZT0rjc1Xk0Q9KhZYwuq2EW/vSbWUBKfgEKkaCuB/Sg6bqnjmTZqC5cD4d6y1vfFAEwBRzfzoSMIVJ55A==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/debug": "7.8.0"
+ }
+ },
+ "node_modules/@prisma/engines": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-7.8.0.tgz",
+ "integrity": "sha512-jx3rCnNNrt5uzbkKlegtQ2GZHxSlihMCzutgT/BP6UIDF1r9tDI39hV/0T/cHZgzJ3ELbuQPXlVZy+Y1n0pcgw==",
+ "devOptional": true,
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/debug": "7.8.0",
+ "@prisma/engines-version": "7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a",
+ "@prisma/fetch-engine": "7.8.0",
+ "@prisma/get-platform": "7.8.0"
+ }
+ },
+ "node_modules/@prisma/engines-version": {
+ "version": "7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a",
+ "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a.tgz",
+ "integrity": "sha512-fJPQxCkLgA5EayWaW8eArgCvjJ+N+Kz3VyeNKMEeYiQC4alNkxRKFVAGxv/ZUzuJISKqdw+zGeDbS6mn6RCPOA==",
+ "devOptional": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/@prisma/engines/node_modules/@prisma/get-platform": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.8.0.tgz",
+ "integrity": "sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/debug": "7.8.0"
+ }
+ },
+ "node_modules/@prisma/fetch-engine": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-7.8.0.tgz",
+ "integrity": "sha512-gwB0Euiz/DDRyxFRpLXYlK3RfaZUj1c5dAYMuhZYfApg7arknJlcb9bIsOHDppJmbqYaVA+yBIiFMDBfprsNPQ==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/debug": "7.8.0",
+ "@prisma/engines-version": "7.8.0-6.3c6e192761c0362d496ed980de936e2f3cebcd3a",
+ "@prisma/get-platform": "7.8.0"
+ }
+ },
+ "node_modules/@prisma/fetch-engine/node_modules/@prisma/get-platform": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.8.0.tgz",
+ "integrity": "sha512-WlxgRGnolL8VH2EmkH1R/DkKNr/mVdS3G2h42IZFFZ3eUrH9OT6t73kIOSlkkrv50wG123Iq8d96ufv5LlZktw==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/debug": "7.8.0"
+ }
+ },
+ "node_modules/@prisma/get-platform": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.2.0.tgz",
+ "integrity": "sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/debug": "7.2.0"
+ }
+ },
+ "node_modules/@prisma/get-platform/node_modules/@prisma/debug": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.2.0.tgz",
+ "integrity": "sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==",
+ "devOptional": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/@prisma/query-plan-executor": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/@prisma/query-plan-executor/-/query-plan-executor-7.2.0.tgz",
+ "integrity": "sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==",
+ "devOptional": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/@prisma/streams-local": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/@prisma/streams-local/-/streams-local-0.1.2.tgz",
+ "integrity": "sha512-l49yTxKKF2odFxaAXTmwmkBKL3+bVQ1tFOooGifu4xkdb9NMNLxHj27XAhTylWZod8I+ISGM5erU1xcl/oBCtg==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "ajv": "^8.12.0",
+ "better-result": "^2.7.0",
+ "env-paths": "^3.0.0",
+ "proper-lockfile": "^4.1.2"
+ },
+ "engines": {
+ "bun": ">=1.3.6",
+ "node": ">=22.0.0"
+ }
+ },
+ "node_modules/@prisma/streams-local/node_modules/ajv": {
+ "version": "8.20.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
+ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/@prisma/streams-local/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/@prisma/studio-core": {
+ "version": "0.27.3",
+ "resolved": "https://registry.npmjs.org/@prisma/studio-core/-/studio-core-0.27.3.tgz",
+ "integrity": "sha512-AADjNFPdsrglxHQVTmHFqv6DuKQZ5WY4p5/gVFY017twvNrSwpLJ9lqUbYYxEu2W7nbvVxTZA8deJ8LseNALsw==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@radix-ui/react-toggle": "1.1.10",
+ "chart.js": "4.5.1"
+ },
+ "engines": {
+ "node": "^20.19 || ^22.12 || >=24.0",
+ "pnpm": "8"
+ },
+ "peerDependencies": {
+ "@types/react": "^18.0.0 || ^19.0.0",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/@radix-ui/primitive": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
+ "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
+ "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+ "devOptional": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-primitive": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
+ "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.2.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-slot": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
+ "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-toggle": {
+ "version": "1.1.10",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz",
+ "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.3",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-controllable-state": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
+ "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-effect-event": "0.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-effect-event": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
+ "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
+ "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rtsao/scc": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
@@ -1313,6 +2192,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@standard-schema/spec": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
+ "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/@swc/helpers": {
"version": "0.5.15",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
@@ -1641,17 +2527,27 @@
"version": "20.19.43",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz",
"integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
+ "node_modules/@types/pg": {
+ "version": "8.20.0",
+ "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.20.0.tgz",
+ "integrity": "sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "pg-protocol": "*",
+ "pg-types": "^2.2.0"
+ }
+ },
"node_modules/@types/react": {
"version": "19.2.17",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz",
"integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"csstype": "^3.2.2"
@@ -1661,7 +2557,7 @@
"version": "19.2.3",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"peerDependencies": {
"@types/react": "^19.2.0"
@@ -2582,6 +3478,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/aws-ssl-profiles": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
+ "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
"node_modules/axe-core": {
"version": "4.12.1",
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.12.1.tgz",
@@ -2621,6 +3527,13 @@
"node": ">=6.0.0"
}
},
+ "node_modules/better-result": {
+ "version": "2.9.2",
+ "resolved": "https://registry.npmjs.org/better-result/-/better-result-2.9.2.tgz",
+ "integrity": "sha512-WIFoBPCdnTOdk9inkE1ZRvCZ4P0CpSkAiLlchC65N7n9DcjZ3NhqkBOlafzpOVnO8ixyi37kicmSJ3ENhPZl7Q==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/brace-expansion": {
"version": "1.1.15",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz",
@@ -2679,6 +3592,35 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
+ "node_modules/c12": {
+ "version": "3.3.4",
+ "resolved": "https://registry.npmjs.org/c12/-/c12-3.3.4.tgz",
+ "integrity": "sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^5.0.0",
+ "confbox": "^0.2.4",
+ "defu": "^6.1.6",
+ "dotenv": "^17.3.1",
+ "exsolve": "^1.0.8",
+ "giget": "^3.2.0",
+ "jiti": "^2.6.1",
+ "ohash": "^2.0.11",
+ "pathe": "^2.0.3",
+ "perfect-debounce": "^2.1.0",
+ "pkg-types": "^2.3.0",
+ "rc9": "^3.0.1"
+ },
+ "peerDependencies": {
+ "magicast": "*"
+ },
+ "peerDependenciesMeta": {
+ "magicast": {
+ "optional": true
+ }
+ }
+ },
"node_modules/call-bind": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz",
@@ -2776,6 +3718,35 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/chart.js": {
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz",
+ "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "@kurkle/color": "^0.3.0"
+ },
+ "engines": {
+ "pnpm": ">=8"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
+ "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^5.0.0"
+ },
+ "engines": {
+ "node": ">= 20.19.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/client-only": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
@@ -2809,6 +3780,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/confbox": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz",
+ "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/convert-source-map": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
@@ -2820,7 +3798,7 @@
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
@@ -2835,7 +3813,7 @@
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/damerau-levenshtein": {
@@ -2924,6 +3902,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/deepmerge-ts": {
+ "version": "7.1.5",
+ "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz",
+ "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==",
+ "devOptional": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
@@ -2960,6 +3948,30 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/defu": {
+ "version": "6.1.7",
+ "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz",
+ "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/denque": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
+ "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/destr": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz",
+ "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
@@ -2983,6 +3995,18 @@
"node": ">=0.10.0"
}
},
+ "node_modules/dotenv": {
+ "version": "17.4.2",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
+ "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@@ -2998,6 +4022,17 @@
"node": ">= 0.4"
}
},
+ "node_modules/effect": {
+ "version": "3.20.0",
+ "resolved": "https://registry.npmjs.org/effect/-/effect-3.20.0.tgz",
+ "integrity": "sha512-qMLfDJscrNG8p/aw+IkT9W7fgj50Z4wG5bLBy0Txsxz8iUHjDIkOgO3SV0WZfnQbNG2VJYb0b+rDLMrhM4+Krw==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "@standard-schema/spec": "^1.0.0",
+ "fast-check": "^3.23.1"
+ }
+ },
"node_modules/electron-to-chromium": {
"version": "1.5.384",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.384.tgz",
@@ -3012,6 +4047,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/empathic": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz",
+ "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ }
+ },
"node_modules/enhanced-resolve": {
"version": "5.21.6",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz",
@@ -3026,6 +4071,19 @@
"node": ">=10.13.0"
}
},
+ "node_modules/env-paths": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz",
+ "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/es-abstract": {
"version": "1.24.2",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz",
@@ -3225,6 +4283,48 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/esbuild": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz",
+ "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.28.1",
+ "@esbuild/android-arm": "0.28.1",
+ "@esbuild/android-arm64": "0.28.1",
+ "@esbuild/android-x64": "0.28.1",
+ "@esbuild/darwin-arm64": "0.28.1",
+ "@esbuild/darwin-x64": "0.28.1",
+ "@esbuild/freebsd-arm64": "0.28.1",
+ "@esbuild/freebsd-x64": "0.28.1",
+ "@esbuild/linux-arm": "0.28.1",
+ "@esbuild/linux-arm64": "0.28.1",
+ "@esbuild/linux-ia32": "0.28.1",
+ "@esbuild/linux-loong64": "0.28.1",
+ "@esbuild/linux-mips64el": "0.28.1",
+ "@esbuild/linux-ppc64": "0.28.1",
+ "@esbuild/linux-riscv64": "0.28.1",
+ "@esbuild/linux-s390x": "0.28.1",
+ "@esbuild/linux-x64": "0.28.1",
+ "@esbuild/netbsd-arm64": "0.28.1",
+ "@esbuild/netbsd-x64": "0.28.1",
+ "@esbuild/openbsd-arm64": "0.28.1",
+ "@esbuild/openbsd-x64": "0.28.1",
+ "@esbuild/openharmony-arm64": "0.28.1",
+ "@esbuild/sunos-x64": "0.28.1",
+ "@esbuild/win32-arm64": "0.28.1",
+ "@esbuild/win32-ia32": "0.28.1",
+ "@esbuild/win32-x64": "0.28.1"
+ }
+ },
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
@@ -3654,11 +4754,41 @@
"node": ">=0.10.0"
}
},
+ "node_modules/exsolve": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.0.tgz",
+ "integrity": "sha512-D+42+T12DdIlJM3uepa55qGiL3sYdLBOxIl2ifQCzCHz4c7eiolaHsi3BIqEr7JxBzxv2pYZQX9kw16ziMcEmw==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-check": {
+ "version": "3.23.2",
+ "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz",
+ "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==",
+ "devOptional": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/dubzzz"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fast-check"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "pure-rand": "^6.1.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/fast-glob": {
@@ -3705,6 +4835,23 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/fast-uri": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz",
+ "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==",
+ "devOptional": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fastify"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fastify"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
"node_modules/fastq": {
"version": "1.20.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
@@ -3795,6 +4942,38 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/foreground-child": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
+ "devOptional": true,
+ "license": "ISC",
+ "dependencies": {
+ "cross-spawn": "^7.0.6",
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -3839,6 +5018,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/generate-function": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
+ "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-property": "^1.0.2"
+ }
+ },
"node_modules/generator-function": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
@@ -3884,6 +5073,13 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/get-port-please": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.2.0.tgz",
+ "integrity": "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
@@ -3929,6 +5125,16 @@
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
}
},
+ "node_modules/giget": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/giget/-/giget-3.3.0.tgz",
+ "integrity": "sha512-gzi2D96p+AMfDcmJHGDj3KJ9NRiwvlFAU5yfa3ROwWZmFUjX4P43x3BcyRaOMMLto1vUo7C+86+MFhYTl6Ryiw==",
+ "devOptional": true,
+ "license": "MIT",
+ "bin": {
+ "giget": "dist/cli.mjs"
+ }
+ },
"node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
@@ -3989,9 +5195,23 @@
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
- "dev": true,
+ "devOptional": true,
"license": "ISC"
},
+ "node_modules/grammex": {
+ "version": "3.1.12",
+ "resolved": "https://registry.npmjs.org/grammex/-/grammex-3.1.12.tgz",
+ "integrity": "sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/graphmatch": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/graphmatch/-/graphmatch-1.1.1.tgz",
+ "integrity": "sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/has-bigints": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
@@ -4103,6 +5323,40 @@
"hermes-estree": "0.25.1"
}
},
+ "node_modules/hono": {
+ "version": "4.12.27",
+ "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.27.tgz",
+ "integrity": "sha512-1yrb/+w6HWQJrUCLkJ2IF5jNIPvvFkblV5RNOYl6bV+OA6p9GLcMpHFFGTosSvHvcAUibuUukRqhlYI4z32C7Q==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=16.9.0"
+ }
+ },
+ "node_modules/http-status-codes": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz",
+ "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
+ "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -4441,6 +5695,13 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-property": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
+ "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/is-regex": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
@@ -4597,7 +5858,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true,
+ "devOptional": true,
"license": "ISC"
},
"node_modules/iterator.prototype": {
@@ -4622,7 +5883,7 @@
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
"integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"bin": {
"jiti": "lib/jiti-cli.mjs"
@@ -5061,6 +6322,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/long": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
+ "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
+ "devOptional": true,
+ "license": "Apache-2.0"
+ },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -5084,6 +6352,22 @@
"yallist": "^3.0.2"
}
},
+ "node_modules/lru.min": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.4.tgz",
+ "integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "bun": ">=1.0.0",
+ "deno": ">=1.30.0",
+ "node": ">=8.0.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wellwelwel"
+ }
+ },
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
@@ -5158,6 +6442,40 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/mysql2": {
+ "version": "3.15.3",
+ "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.3.tgz",
+ "integrity": "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "aws-ssl-profiles": "^1.1.1",
+ "denque": "^2.1.0",
+ "generate-function": "^2.3.1",
+ "iconv-lite": "^0.7.0",
+ "long": "^5.2.1",
+ "lru.min": "^1.0.0",
+ "named-placeholders": "^1.1.3",
+ "seq-queue": "^0.0.5",
+ "sqlstring": "^2.3.2"
+ },
+ "engines": {
+ "node": ">= 8.0"
+ }
+ },
+ "node_modules/named-placeholders": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.6.tgz",
+ "integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "lru.min": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
"node_modules/nanoid": {
"version": "3.3.15",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz",
@@ -5432,6 +6750,13 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/ohash": {
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz",
+ "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -5527,7 +6852,7 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -5540,6 +6865,118 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/pathe": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/perfect-debounce": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz",
+ "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/pg": {
+ "version": "8.22.0",
+ "resolved": "https://registry.npmjs.org/pg/-/pg-8.22.0.tgz",
+ "integrity": "sha512-8wih1vVIBMxoUM2oB4soJsD9tDnDpLv4OXBJ+EJzFsvycD+lfyIreC2gGHq78f8jbLLt+bvlPTFdFZfJkOuzAA==",
+ "license": "MIT",
+ "dependencies": {
+ "pg-connection-string": "^2.14.0",
+ "pg-pool": "^3.14.0",
+ "pg-protocol": "^1.15.0",
+ "pg-types": "2.2.0",
+ "pgpass": "1.0.5"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "optionalDependencies": {
+ "pg-cloudflare": "^1.4.0"
+ },
+ "peerDependencies": {
+ "pg-native": ">=3.0.1"
+ },
+ "peerDependenciesMeta": {
+ "pg-native": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/pg-cloudflare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.4.0.tgz",
+ "integrity": "sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/pg-connection-string": {
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.14.0.tgz",
+ "integrity": "sha512-XwWDGcLRGCXAR8F/AM5bG7Q+A3Wm2s6QeEjlOKZLlH3UYcguiqCWKyWXVag5TLTIjR7oOJUY8kcADaZgWPyLeg==",
+ "license": "MIT"
+ },
+ "node_modules/pg-int8": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
+ "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/pg-pool": {
+ "version": "3.14.0",
+ "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.14.0.tgz",
+ "integrity": "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "pg": ">=8.0"
+ }
+ },
+ "node_modules/pg-protocol": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.15.0.tgz",
+ "integrity": "sha512-cq9sECI5s0+uPUXjbz8ioyPJni6RzsRib0US67i5IoTZKw8fNeYlVE7u8F4dG7vEJJtc5wdD1K189lCCUwqWTQ==",
+ "license": "MIT"
+ },
+ "node_modules/pg-types": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
+ "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
+ "license": "MIT",
+ "dependencies": {
+ "pg-int8": "1.0.1",
+ "postgres-array": "~2.0.0",
+ "postgres-bytea": "~1.0.0",
+ "postgres-date": "~1.0.4",
+ "postgres-interval": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/pg-types/node_modules/postgres-array": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
+ "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/pgpass": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
+ "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
+ "license": "MIT",
+ "dependencies": {
+ "split2": "^4.1.0"
+ }
+ },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -5559,6 +6996,18 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/pkg-types": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz",
+ "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "confbox": "^0.2.4",
+ "exsolve": "^1.0.8",
+ "pathe": "^2.0.3"
+ }
+ },
"node_modules/possible-typed-array-names": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
@@ -5598,6 +7047,59 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/postgres": {
+ "version": "3.4.7",
+ "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.7.tgz",
+ "integrity": "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==",
+ "devOptional": true,
+ "license": "Unlicense",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://github.com/sponsors/porsager"
+ }
+ },
+ "node_modules/postgres-array": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.4.tgz",
+ "integrity": "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/postgres-bytea": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz",
+ "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postgres-date": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
+ "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postgres-interval": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
+ "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
+ "license": "MIT",
+ "dependencies": {
+ "xtend": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -5608,6 +7110,40 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/prisma": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/prisma/-/prisma-7.8.0.tgz",
+ "integrity": "sha512-yfN4yrw7HV9kEJhoy1+jgah0jafEIQsf7uWouSsM8MvJtlubsk+kM7AIBWZ8+GJl74Yj3c+nbYqBkMOxtsZ3Lw==",
+ "devOptional": true,
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@prisma/config": "7.8.0",
+ "@prisma/dev": "0.24.3",
+ "@prisma/engines": "7.8.0",
+ "@prisma/studio-core": "0.27.3",
+ "mysql2": "3.15.3",
+ "postgres": "3.4.7"
+ },
+ "bin": {
+ "prisma": "build/index.js"
+ },
+ "engines": {
+ "node": "^20.19 || ^22.12 || >=24.0"
+ },
+ "peerDependencies": {
+ "better-sqlite3": ">=9.0.0",
+ "typescript": ">=5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "better-sqlite3": {
+ "optional": true
+ },
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -5620,6 +7156,25 @@
"react-is": "^16.13.1"
}
},
+ "node_modules/proper-lockfile": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz",
+ "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "retry": "^0.12.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "node_modules/proper-lockfile/node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "devOptional": true,
+ "license": "ISC"
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -5630,6 +7185,23 @@
"node": ">=6"
}
},
+ "node_modules/pure-rand": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
+ "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
+ "devOptional": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/dubzzz"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fast-check"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -5651,6 +7223,17 @@
],
"license": "MIT"
},
+ "node_modules/rc9": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/rc9/-/rc9-3.0.1.tgz",
+ "integrity": "sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "defu": "^6.1.6",
+ "destr": "^2.0.5"
+ }
+ },
"node_modules/react": {
"version": "19.2.4",
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
@@ -5679,6 +7262,20 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/readdirp": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
+ "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20.19.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
@@ -5723,6 +7320,26 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/remeda": {
+ "version": "2.33.4",
+ "resolved": "https://registry.npmjs.org/remeda/-/remeda-2.33.4.tgz",
+ "integrity": "sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/remeda"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/resolve": {
"version": "2.0.0-next.7",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz",
@@ -5767,6 +7384,16 @@
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
}
},
+ "node_modules/retry": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+ "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
"node_modules/reusify": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
@@ -5857,6 +7484,13 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/scheduler": {
"version": "0.27.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
@@ -5873,6 +7507,12 @@
"semver": "bin/semver.js"
}
},
+ "node_modules/seq-queue": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
+ "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==",
+ "devOptional": true
+ },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@@ -5984,7 +7624,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"shebang-regex": "^3.0.0"
@@ -5997,7 +7637,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"engines": {
"node": ">=8"
@@ -6079,6 +7719,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "devOptional": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -6088,6 +7741,25 @@
"node": ">=0.10.0"
}
},
+ "node_modules/split2": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
+ "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">= 10.x"
+ }
+ },
+ "node_modules/sqlstring": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
+ "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/stable-hash": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz",
@@ -6095,6 +7767,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/std-env": {
+ "version": "3.10.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz",
+ "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/stop-iteration-iterator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
@@ -6422,6 +8101,25 @@
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
+ "node_modules/tsx": {
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz",
+ "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "~0.28.0"
+ },
+ "bin": {
+ "tsx": "dist/cli.mjs"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ }
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -6517,7 +8215,7 @@
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
- "dev": true,
+ "devOptional": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
@@ -6574,7 +8272,6 @@
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/unrs-resolver": {
@@ -6656,11 +8353,26 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/valibot": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.2.0.tgz",
+ "integrity": "sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==",
+ "devOptional": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "typescript": ">=5"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
+ "devOptional": true,
"license": "ISC",
"dependencies": {
"isexe": "^2.0.0"
@@ -6771,6 +8483,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4"
+ }
+ },
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
@@ -6791,11 +8512,21 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/zeptomatch": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/zeptomatch/-/zeptomatch-2.1.0.tgz",
+ "integrity": "sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "grammex": "^3.1.11",
+ "graphmatch": "^1.1.0"
+ }
+ },
"node_modules/zod": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
"integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
- "dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
diff --git a/package.json b/package.json
index e7502f6..7e938d3 100644
--- a/package.json
+++ b/package.json
@@ -9,9 +9,13 @@
"lint": "eslint"
},
"dependencies": {
+ "@prisma/adapter-pg": "^7.8.0",
+ "@prisma/client": "^7.8.0",
+ "dotenv": "^17.4.2",
"next": "16.2.10",
"react": "19.2.4",
- "react-dom": "19.2.4"
+ "react-dom": "19.2.4",
+ "zod": "^4.4.3"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
@@ -20,7 +24,9 @@
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "16.2.10",
+ "prisma": "^7.8.0",
"tailwindcss": "^4",
+ "tsx": "^4.22.4",
"typescript": "^5"
}
}
diff --git a/prisma.config.ts b/prisma.config.ts
new file mode 100644
index 0000000..37c017f
--- /dev/null
+++ b/prisma.config.ts
@@ -0,0 +1,13 @@
+import "dotenv/config";
+import { defineConfig, env } from "prisma/config";
+
+export default defineConfig({
+ schema: "prisma/schema.prisma",
+ datasource: {
+ url: env("DATABASE_URL"),
+ },
+ migrations: {
+ path: "prisma/migrations",
+ seed: "tsx prisma/seed.ts",
+ },
+});
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
new file mode 100644
index 0000000..ec2e2df
--- /dev/null
+++ b/prisma/schema.prisma
@@ -0,0 +1,129 @@
+// ISMS-Tool — Prisma-Schema
+// Fundament (Iteration 1): Mandanten, Nutzer, RBAC, Audit-Log.
+// Fachliche Entitäten (Assets, BIA, Risiken, …) folgen je Iteration — siehe docs/SPEC.md §5.
+//
+// Multi-Tenant-Regel: Jede fachliche Tabelle trägt tenantId. Zugriff nur über den
+// zentralen Tenant-Guard (src/server/db.ts); zusätzlich Postgres RLS (prisma/rls.sql).
+
+generator client {
+ provider = "prisma-client-js"
+ previewFeatures = ["postgresqlExtensions"]
+}
+
+datasource db {
+ provider = "postgresql"
+ extensions = [pgvector(map: "vector")]
+}
+
+enum TenantStatus {
+ ACTIVE
+ SUSPENDED
+}
+
+enum UserStatus {
+ ACTIVE
+ INVITED
+ LOCKED
+ DEACTIVATED
+}
+
+model Tenant {
+ id String @id @default(cuid())
+ name String
+ slug String @unique
+ status TenantStatus @default(ACTIVE)
+ config Json @default("{}")
+ createdAt DateTime @default(now()) @map("created_at")
+ updatedAt DateTime @updatedAt @map("updated_at")
+
+ users User[]
+ roles Role[]
+ auditLogs AuditLog[]
+
+ @@map("tenants")
+}
+
+model User {
+ id String @id @default(cuid())
+ tenantId String @map("tenant_id")
+ email String
+ passwordHash String @map("password_hash")
+ name String
+ status UserStatus @default(ACTIVE)
+ mfaSecret String? @map("mfa_secret")
+ // Plattform-Admin ist mandantenübergreifend (Betreiberrolle)
+ isPlatformAdmin Boolean @default(false) @map("is_platform_admin")
+ createdAt DateTime @default(now()) @map("created_at")
+ updatedAt DateTime @updatedAt @map("updated_at")
+
+ tenant Tenant @relation(fields: [tenantId], references: [id])
+ userRoles UserRole[]
+
+ @@unique([tenantId, email])
+ @@index([tenantId])
+ @@map("users")
+}
+
+model Role {
+ id String @id @default(cuid())
+ tenantId String @map("tenant_id")
+ key String // z. B. tenant-admin, isb, auditor, owner, user
+ name String
+
+ tenant Tenant @relation(fields: [tenantId], references: [id])
+ userRoles UserRole[]
+ rolePermissions RolePermission[]
+
+ @@unique([tenantId, key])
+ @@index([tenantId])
+ @@map("roles")
+}
+
+model Permission {
+ id String @id @default(cuid())
+ key String @unique // z. B. asset:read, risk:write, incident:manage
+
+ rolePermissions RolePermission[]
+
+ @@map("permissions")
+}
+
+model UserRole {
+ userId String @map("user_id")
+ roleId String @map("role_id")
+
+ user User @relation(fields: [userId], references: [id], onDelete: Cascade)
+ role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
+
+ @@id([userId, roleId])
+ @@map("user_roles")
+}
+
+model RolePermission {
+ roleId String @map("role_id")
+ permissionId String @map("permission_id")
+
+ role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
+ permission Permission @relation(fields: [permissionId], references: [id], onDelete: Cascade)
+
+ @@id([roleId, permissionId])
+ @@map("role_permissions")
+}
+
+model AuditLog {
+ id String @id @default(cuid())
+ tenantId String @map("tenant_id")
+ actorId String? @map("actor_id")
+ action String // create | update | delete | login | export | …
+ entity String // z. B. asset, risk, user
+ entityId String? @map("entity_id")
+ before Json?
+ after Json?
+ createdAt DateTime @default(now()) @map("created_at")
+
+ tenant Tenant @relation(fields: [tenantId], references: [id])
+
+ @@index([tenantId, entity, entityId])
+ @@index([tenantId, createdAt])
+ @@map("audit_logs")
+}
diff --git a/src/server/db.ts b/src/server/db.ts
new file mode 100644
index 0000000..0574db3
--- /dev/null
+++ b/src/server/db.ts
@@ -0,0 +1,99 @@
+import { PrismaClient } from "@prisma/client";
+import { PrismaPg } from "@prisma/adapter-pg";
+
+/**
+ * Central database access for the ISMS tool.
+ *
+ * Multi-tenant rule (see docs/SPEC.md §2): no query on tenant-scoped models
+ * without a tenant context. Application code MUST use `dbForTenant(tenantId)`
+ * for all tenant-scoped models — the raw client is only for global data
+ * (permissions, control catalogs) and platform administration.
+ *
+ * Postgres Row Level Security is added on top as a second line of defense
+ * (prisma/rls.sql, applied via migration).
+ */
+
+const globalForPrisma = globalThis as unknown as { prisma?: PrismaClient };
+
+export const prisma =
+ globalForPrisma.prisma ??
+ new PrismaClient({
+ adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }),
+ });
+
+if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
+
+/** Models that carry a tenantId column and must never be queried without one. */
+const TENANT_MODELS = new Set(["User", "Role", "AuditLog"]);
+
+/**
+ * Returns a Prisma client that transparently enforces the tenant scope:
+ * reads are filtered by tenantId, creates get the tenantId injected.
+ */
+export function dbForTenant(tenantId: string) {
+ if (!tenantId) throw new Error("dbForTenant: tenantId is required");
+
+ return prisma.$extends({
+ query: {
+ $allModels: {
+ async $allOperations({ model, operation, args, query }) {
+ if (!TENANT_MODELS.has(model)) return query(args);
+
+ const a = args as Record;
+
+ if (
+ operation === "findMany" ||
+ operation === "findFirst" ||
+ operation === "count" ||
+ operation === "aggregate" ||
+ operation === "updateMany" ||
+ operation === "deleteMany"
+ ) {
+ a.where = { AND: [{ tenantId }, (a.where as object) ?? {}] };
+ } else if (operation === "create") {
+ a.data = { ...(a.data as object), tenantId };
+ } else if (operation === "createMany") {
+ const data = a.data as Record[];
+ a.data = data.map((d) => ({ ...d, tenantId }));
+ } else if (operation === "findUnique" || operation === "findUniqueOrThrow") {
+ // Unique lookups cannot be widened with AND — verify ownership on the result.
+ const result = await query(args);
+ if (
+ result &&
+ typeof result === "object" &&
+ "tenantId" in result &&
+ (result as { tenantId: string }).tenantId !== tenantId
+ ) {
+ throw new Error(
+ `Tenant isolation violation: ${model} belongs to another tenant`
+ );
+ }
+ return result;
+ } else if (
+ operation === "update" ||
+ operation === "delete" ||
+ operation === "upsert"
+ ) {
+ // Mutations on unique keys: verify ownership BEFORE mutating.
+ const delegate = (
+ prisma as unknown as Record<
+ string,
+ { findUnique: (a: unknown) => Promise<{ tenantId?: string } | null> }
+ >
+ )[model.charAt(0).toLowerCase() + model.slice(1)];
+ const existing = await delegate.findUnique({ where: a.where });
+ if (existing && existing.tenantId !== tenantId) {
+ throw new Error(
+ `Tenant isolation violation: ${model} belongs to another tenant`
+ );
+ }
+ }
+
+ return query(args);
+ },
+ },
+ },
+ });
+}
+
+export type TenantDb = ReturnType;