From b22bdd8425a1f71c3699f2145b8aaa7c7821f37e Mon Sep 17 00:00:00 2001 From: "CTO (LegalAI)" Date: Thu, 9 Apr 2026 14:28:19 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20API=20key=20save=20network=20error=20?= =?UTF-8?q?=E2=80=94=20add=20ENCRYPTION=5FKEY=20env=20and=20auto-migrate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Netzwerkfehler beim Speichern des Schlüssels" was caused by two issues: 1. ENCRYPTION_KEY env var was not passed to the Docker container, so AES-256-GCM encrypt() threw at runtime on every POST/PATCH. 2. The 0003_tenant_api_keys migration was not in the drizzle journal and no migration runner existed in the Docker image. Changes: - docker-compose.yml: pass ENCRYPTION_KEY to app container - .env.example: document ENCRYPTION_KEY with generation command - .gitignore: allow .env.example to be tracked - Dockerfile: include drizzle/ migrations and entrypoint script - entrypoint.sh: run migrations before starting the app - migrate.mjs: runtime migration script using drizzle-orm migrator - drizzle journal: register 0003_tenant_api_keys migration Co-Authored-By: Paperclip --- .env.example | 23 +++++++++++++++++++++++ .gitignore | 1 + Dockerfile | 6 +++++- docker-compose.yml | 1 + drizzle/meta/_journal.json | 7 +++++++ entrypoint.sh | 4 ++++ migrate.mjs | 20 ++++++++++++++++++++ 7 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 .env.example create mode 100644 entrypoint.sh create mode 100644 migrate.mjs diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..f60e22b --- /dev/null +++ b/.env.example @@ -0,0 +1,23 @@ +# Database +DATABASE_URL=postgresql://legalai:legalai@localhost:5432/legalai + +# Authentication +NEXTAUTH_URL=http://localhost:3000 +NEXTAUTH_SECRET=your-secret-here + +# AI Providers (set the one you use: anthropic, openai, ollama) +AI_PROVIDER=anthropic +ANTHROPIC_API_KEY= +OPENAI_API_KEY= + +# Ollama (local LLM) +OLLAMA_URL=http://localhost:11434 +OLLAMA_MODEL=llama3 + +# Search +MEILISEARCH_URL=http://localhost:7700 +MEILISEARCH_API_KEY=masterKey + +# Encryption (required for per-tenant API key storage) +# Generate with: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" +ENCRYPTION_KEY= 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/Dockerfile b/Dockerfile index 53d6c9c..21d646c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,8 +19,12 @@ RUN adduser --system --uid 1001 nextjs COPY --from=builder /app/public ./public COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static +COPY --from=builder --chown=nextjs:nodejs /app/drizzle ./drizzle +COPY --from=builder --chown=nextjs:nodejs /app/migrate.mjs ./migrate.mjs +COPY --from=builder --chown=nextjs:nodejs /app/entrypoint.sh ./entrypoint.sh +RUN chmod +x ./entrypoint.sh USER nextjs EXPOSE 3000 ENV PORT=3000 ENV HOSTNAME="0.0.0.0" -CMD ["node", "server.js"] +ENTRYPOINT ["./entrypoint.sh"] diff --git a/docker-compose.yml b/docker-compose.yml index ee8effc..e453948 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,6 +12,7 @@ services: - AI_PROVIDER=${AI_PROVIDER:-anthropic} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} - OPENAI_API_KEY=${OPENAI_API_KEY} + - ENCRYPTION_KEY=${ENCRYPTION_KEY} depends_on: postgres: condition: service_healthy diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 988d291..e8a8f65 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -22,6 +22,13 @@ "when": 1775729813628, "tag": "0002_wide_grandmaster", "breakpoints": true + }, + { + "idx": 3, + "version": "7", + "when": 1775775900000, + "tag": "0003_tenant_api_keys", + "breakpoints": true } ] } \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..3bbfc32 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,4 @@ +#!/bin/sh +set -e +node migrate.mjs +exec node server.js diff --git a/migrate.mjs b/migrate.mjs new file mode 100644 index 0000000..76dc308 --- /dev/null +++ b/migrate.mjs @@ -0,0 +1,20 @@ +// Runtime migration script — runs drizzle SQL migrations against the database. +// Used by the Docker entrypoint before starting the app. + +import { drizzle } from 'drizzle-orm/node-postgres'; +import { migrate } from 'drizzle-orm/node-postgres/migrator'; +import pg from 'pg'; + +const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL }); + +try { + const db = drizzle(pool); + console.log('Running database migrations...'); + await migrate(db, { migrationsFolder: './drizzle' }); + console.log('Migrations complete.'); +} catch (err) { + console.error('Migration failed:', err); + process.exit(1); +} finally { + await pool.end(); +}