- HTML 44.4%
- JavaScript 42.4%
- TypeScript 9.6%
- CSS 2.7%
- Shell 0.7%
- Other 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
Deploy to Cloud Foundry / deploy (push) Successful in 3m49s
|
||
| .gitea/workflows | ||
| app | ||
| db | ||
| docs | ||
| drizzle | ||
| lib | ||
| resources | ||
| scripts | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yml | ||
| drizzle.config.ts | ||
| LICENSE | ||
| manifest.yml | ||
| next.config.ts | ||
| package-lock.json | ||
| package.json | ||
| postcss.config.mjs | ||
| proxy.ts | ||
| README.md | ||
| tsconfig.json | ||
| vars.prod.yml | ||
| vars.qa.yml | ||
| vars.test.yml | ||
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).
testläuft.
Deploy-Wege. Drei Wege setzen dieselben Zielwerte (
LLM_*percf set-env, DB immer über den cups-Service):
- Gitea/Forgejo CI (Standard):
git pushauftest/qa/proddeployt in den gleichnamigen CF-Space (.gitea/workflows/deploy.yml). Repo-Secrets: nurCF_USERNAME_<ENV>/CF_PASSWORD_<ENV>(space-scoped). Der LLM-Key sitzt bereits per Bootstrap auf der App.- Bootstrap aus Secrets Manager:
infra-spike/scripts/setup-innotools-cf-space.sh <env>(einmalig je Space): legt cups + CI-Account an und setztLLM_*aus dem Secrets Manager.- Manuell aus
.env:scripts/deploy-innotools.sh <env>liestLLM_*aus der lokalen.envund deployt ohne CI. Kein Secret gelangt ins Git (.envist 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.