No description
  • HTML 44.4%
  • JavaScript 42.4%
  • TypeScript 9.6%
  • CSS 2.7%
  • Shell 0.7%
  • Other 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Claudio Weck 277a1c7e28
All checks were successful
Deploy to Cloud Foundry / deploy (push) Successful in 3m49s
docs: DEPLOYMENT.md — CF deploy guide + hard-won gotchas
2026-07-27 17:23:52 +02:00
.gitea/workflows fix(deploy): run migrate/seed tasks with -k 2G (task default disk 1G too small) 2026-07-27 17:14:25 +02:00
app LLM-Client mit Mock-Fallback und lokale Konfiguration 2026-07-27 13:27:54 +02:00
db Gerüst, Deployment-Strecke und Datenmodell 2026-07-27 13:18:57 +02:00
docs docs: DEPLOYMENT.md — CF deploy guide + hard-won gotchas 2026-07-27 17:23:52 +02:00
drizzle Gerüst, Deployment-Strecke und Datenmodell 2026-07-27 13:18:57 +02:00
lib LLM-Client mit Mock-Fallback und lokale Konfiguration 2026-07-27 13:27:54 +02:00
resources Gerüst, Deployment-Strecke und Datenmodell 2026-07-27 13:18:57 +02:00
scripts fix(deploy): run migrate/seed tasks with -k 2G (task default disk 1G too small) 2026-07-27 17:14:25 +02:00
.env.example feat(deploy): manual .env-driven CF deploy script 2026-07-27 15:17:57 +02:00
.gitignore LLM-Client mit Mock-Fallback und lokale Konfiguration 2026-07-27 13:27:54 +02:00
docker-compose.yml Gerüst, Deployment-Strecke und Datenmodell 2026-07-27 13:18:57 +02:00
drizzle.config.ts Gerüst, Deployment-Strecke und Datenmodell 2026-07-27 13:18:57 +02:00
LICENSE Initial commit 2026-07-27 10:55:03 +00:00
manifest.yml fix(deploy): bump disk_quota to 2G (unpruned node_modules exceed 1G) 2026-07-27 17:06:46 +02:00
next.config.ts Gerüst, Deployment-Strecke und Datenmodell 2026-07-27 13:18:57 +02:00
package-lock.json Gerüst, Deployment-Strecke und Datenmodell 2026-07-27 13:18:57 +02:00
package.json Gerüst, Deployment-Strecke und Datenmodell 2026-07-27 13:18:57 +02:00
postcss.config.mjs Gerüst, Deployment-Strecke und Datenmodell 2026-07-27 13:18:57 +02:00
proxy.ts Gerüst, Deployment-Strecke und Datenmodell 2026-07-27 13:18:57 +02:00
README.md docs: DEPLOYMENT.md — CF deploy guide + hard-won gotchas 2026-07-27 17:23:52 +02:00
tsconfig.json Gerüst, Deployment-Strecke und Datenmodell 2026-07-27 13:18:57 +02:00
vars.prod.yml Gerüst, Deployment-Strecke und Datenmodell 2026-07-27 13:18:57 +02:00
vars.qa.yml feat(cf): add qa env vars and explicit per-env routes 2026-07-27 15:11:33 +02:00
vars.test.yml Gerüst, Deployment-Strecke und Datenmodell 2026-07-27 13:18:57 +02:00

IPAI Innovations & Tools

Internes Verzeichnis für Innovationstools: Einreichen per URL (ein LLM füllt das Profil vor), Voting, Trending, Quartals-Ranking, strukturierte Tool-Profile, Use Cases, Kommentare, Status-Signale, kollaboratives Editieren, DE/EN-Interface.

Stack: Next.js (App Router) · TypeScript · Postgres über Drizzle ORM · Deployment auf Cloud Foundry.

Aufbaustand

Etappe Inhalt Status
1 Deploybares Gerüst: Health-Endpoint, Identität über Reverse Proxy, CF-Manifest
2 Datenmodell, Migrationen, Seed-Daten, LLM-Client
3 Oberfläche und Funktionen aus dem Design-Handoff offen

Die ersten beiden Etappen sind bewusst zuerst fertig, damit die Deployment-Strecke inklusive Postgres-Service-Binding früh auf test durchgespielt werden kann.

Die Oberfläche fehlt noch: die Startseite ist ein Platzhalter mit Hero-Styling. Für einen Test der Deployment-Strecke reicht das, als fertige Anwendung noch nicht.

Aufbau

Pfad Inhalt
app/ Seiten und Route-Handler (App Router)
proxy.ts liest die Proxy-Header, setzt die Identität — Next-16-Konvention, früher middleware.ts
lib/identity.ts Zugriff auf die Identität in Server-Komponenten und Routes
lib/llm.ts LiteLLM-Client, striktes JSON, Mock-Fallback ohne Key
db/schema.ts Drizzle-Schema inklusive Unique-Constraints
db/migrate.ts, db/seed.ts Migrations- und Seed-Skript, laufen auch als CF-Task
drizzle/ generierte Migrationen — gehören ins Repo
manifest.yml, vars.*.yml Cloud-Foundry-Deployment je Umgebung
resources/ Design-Handoff: Prototyp, Tokens, Seed-Rohdaten (keine Laufzeit-Abhängigkeit)

Grundlage ist der Design-Handoff unter resources/design_handoff_innovation_tool_directory/. Toolhub.dc.html dort ist eine Design-Referenz, kein Produktionscode.

Lokal starten

cp .env.example .env
npm install
npm run dev

Ohne Reverse Proxy greift lokal die Identität aus DEV_USER_EMAIL / DEV_USER_FIRST_NAME / DEV_USER_LAST_NAME. Dieser Fallback ist auf NODE_ENV != production beschränkt — in der Produktion entscheidet ausschliesslich der Proxy, es gibt dort keinen Bypass.

Ist DEV_USER_EMAIL leer, verhält sich die App wie produktiv: sie zeigt nur „Bitte einloggen“. Die Proxy-Header lassen sich auch direkt setzen:

curl -H "x-auth-request-email: du@ipai.eu" \
     -H "x-auth-request-given-name: Vorname" \
     -H "x-auth-request-family-name: Nachname" \
     http://localhost:3000/

Datenbank

npm run db:up       # Postgres via Docker
npm run db:migrate
npm run db:seed     # 19 Ideation-Tools, idempotent

LiteLLM lokal

Trag Base-URL, Modell und Key in die .env ein:

LLM_BASE_URL=https://…/v1
LLM_MODEL=LLM_API_KEY=

Ohne LLM_API_KEY läuft die App gegen einen Mock: der Analyse-Flow leitet den Namen aus der Domain ab und lässt die inhaltlichen Felder leer, statt etwas zu erfinden. Zum Entwickeln reicht das — ein Key ist nicht nötig.

Ob die Konfiguration greift, zeigt /api/llm-status (der Key selbst wird nie ausgegeben):

curl -s localhost:3000/api/llm-status
# {"mode":"litellm","model":"…","host":"…","apiKeySet":true}
# mode "mock" heisst: kein Key gesetzt

Deployment

Ziel ist Cloud Foundry, getrennt nach Umgebung:

Umgebung App Datenbank-Service Vars-Datei
Test ipai-innovations-tools-test ipai-innovations-tools-test-db vars.test.yml
QA ipai-innovations-tools-qa ipai-innovations-tools-qa-db vars.qa.yml
Produktion ipai-innovations-tools ipai-innovations-tools-db vars.prod.yml

manifest.yml ist für alle gleich; die Unterschiede stehen ausschliesslich in den Vars-Dateien.

Deploy-Details & Fallstricke: siehe docs/DEPLOYMENT.md (Gitea-CI, Next-standalone-auf-CF-Eigenheiten, migrate/seed-Tasks). test läuft.

Deploy-Wege. Drei Wege setzen dieselben Zielwerte (LLM_* per cf set-env, DB immer über den cups-Service):

  1. Gitea/Forgejo CI (Standard): git push auf test/qa/prod deployt in den gleichnamigen CF-Space (.gitea/workflows/deploy.yml). Repo-Secrets: nur CF_USERNAME_<ENV> / CF_PASSWORD_<ENV> (space-scoped). Der LLM-Key sitzt bereits per Bootstrap auf der App.
  2. Bootstrap aus Secrets Manager: infra-spike/scripts/setup-innotools-cf-space.sh <env> (einmalig je Space): legt cups + CI-Account an und setzt LLM_* aus dem Secrets Manager.
  3. Manuell aus .env: scripts/deploy-innotools.sh <env> liest LLM_* aus der lokalen .env und deployt ohne CI. Kein Secret gelangt ins Git (.env ist gitignored).

Einmalige Vorbereitung je Umgebung

Die Datenbank-Bindung (cups aus dem Secrets Manager), der CI-Service-Account und die LLM-Env werden je Umgebung einmalig vom Bootstrap-Skript im infra-spike-Repo eingerichtet:

# im infra-spike-Repo, nach: cf login -a https://api.system.01.cf.eu01.stackit.cloud --sso
scripts/setup-innotools-cf-space.sh test   # bzw. qa | prod

Das Binding erfolgt über den user-provided service ipai-innovations-tools-<env>-db (prod: ipai-innovations-tools-db), den das Skript anlegt; cf push bindet ihn über den services:-Eintrag im Manifest. Die Service-Namen müssen zu den Vars-Dateien passen.

Manuell deployen

npm ci && npm run build

# Standalone-Bundle schnüren
rm -rf deploy && mkdir deploy
cp -r .next/standalone/. deploy/
mkdir -p deploy/.next && cp -r .next/static deploy/.next/static
[ -d public ] && cp -r public deploy/public
cp manifest.yml deploy/
cp vars.test.yml deploy/vars.yml          # oder vars.prod.yml
cp -r drizzle deploy/drizzle

# Migration und Seed zu reinem JS bündeln: im Droplet gibt es weder tsx
# noch Dev-Abhängigkeiten.
npx esbuild db/migrate.ts db/seed.ts --bundle --platform=node --target=node22 \
  --format=cjs --external:pg --external:pg-native --outdir=deploy
mkdir -p deploy/db && cp -r db/seed deploy/db/seed

cd deploy
cf push --vars-file vars.yml --no-start   # ohne Start, damit die Env vorher sitzt

APP=ipai-innovations-tools-test
cf set-env "$APP" LLM_BASE_URL "…/v1"
cf set-env "$APP" LLM_MODEL    "…"
cf set-env "$APP" LLM_API_KEY  "…"

cf start "$APP"
cf run-task "$APP" --command "node migrate.js" --name migrate --wait
cf run-task "$APP" --command "node seed.js"    --name seed    --wait

Danach sollte /api/health mit 200 antworten (daran hängt der CF-Health-Check), die App ohne Proxy-Header „Bitte einloggen“ zeigen und die Datenbank 19 Tools enthalten.

Konfiguration in der Pipeline

Sobald eine Pipeline eingerichtet wird, braucht sie diese Werte als Secrets bzw. CI-Variablen:

Wert Zweck
CF_API API-Endpunkt der Cloud-Foundry-Landschaft
CF_USERNAME technischer Nutzer für das Deployment
CF_PASSWORD dessen Passwort
CF_ORG Ziel-Organisation
CF_SPACE Ziel-Space
LLM_BASE_URL Basis-URL des OpenAI-kompatiblen Anbieters (LiteLLM), inkl. /v1
LLM_MODEL Name des Basismodells
LLM_API_KEY API-Key des Anbieters

Die drei LLM-Werte landen ausschliesslich per cf set-env in der App — nie im Repo, nie im manifest.yml. Postgres wird nicht über Secrets konfiguriert: die Credentials kommen aus dem gebundenen Service über VCAP_SERVICES; DATABASE_URL ist nur der lokale Fallback. Einen Key rotieren: Wert in der CI-Konfiguration ändern und neu deployen.

Lizenz

MIT — siehe LICENSE.