Egen hosting
Node och en skrivbar katalog är hela kravet. Påståendena nedan lästes från filerna som namnges bredvid dem; allt som inte kunde bekräftas finns inte här.
Ingångspunkter
- package.json kräver Node >= 22.5. SQLite-lagret är Nodes egen modul node:sqlite.
- Det finns ingen beroendelista alls: appar, paket, skript och tester körs på Nodes standardbibliotek, och Dockerfile installerar ingenting.
- Tre processer finns; var och en öppnar databasen och kör migreringen vid uppstart.
node apps/web/server/main.mjs # hub + console + embedded API
API_EMBED=false node apps/api/src/main.mjs # API only, no pages
node apps/worker/src/run.mjs # probes, latency, rollup, housekeeping
Datalager
DATABASE_URL=sqlite:./data/llmeu.db behöver ingen server, och katalogen och filen skapas vid första öppning. Handtaget körs i WAL-läge med främmande nycklar på och en busy-timeout på 5 s.
packages/shared/src/db/schema.sql är schemat. Det är endast skapande och idempotent, så att köra om det är säkert; en kolumn som läggs till i en befintlig tabell måste också deklareras i det additiva steget i packages/shared/src/db/index.mjs.
En postgres://-URL tar en separat adaptergren. Den grenen kräver pg-paketet, vilket inte är ett deklarerat beroende, och rubriken i schema.sql säger att Postgres-vägen ska betraktas som overifierad tills en riktig drivrutin och en testad migrering finns. SQLite är den väg detta arkiv kör.
Operatörs-CLI
node scripts/db.mjs läser DATABASE_URL och behöver inga tjänster. Kommandon:
| Kommando | Vad den gör |
|---|---|
| node scripts/db.mjs migrate | Tillämpar schema.sql och rapporterar antalet satser. |
| node scripts/db.mjs seed | Infogar eller uppdaterar katalogen och demo-organisationen, och skriver demo-nyckeln till data/demo-key.txt med behörigheten 0600. |
| node scripts/db.mjs reset | Endast för SQLite: tar bort databasfilen och dess -wal- och -shm-följeslagare, migrerar och seedar sedan. På Postgres vägrar den. |
| node scripts/db.mjs status | Skriver ut motorn, antalet tabeller och radantalet för varje icke-tom tabell. |
| node scripts/db.mjs demo-key | Utfärdar en ny nyckel för demo-organisationen och skriver ut den en gång. |
| node scripts/db.mjs passwd <email> | Sätter en användares lösenord från servern och raderar alla sessioner för den användaren. Detta är återställningsvägen när ingen e-posttransport är konfigurerad. Utan --password genererar den ett och skriver ut det en gång. |
Miljö
Grupperade som .env.example grupperar dem.
| Grupp | Variabler | Anteckningar |
|---|---|---|
| URL:er och portar | APP_URL, API_URL, WEB_PORT, API_PORT, API_EMBED, PUBLIC_API_URL | API-porten är som standard 8088, inte 8080. API_EMBED=false är för en distribution som kör API:et som en egen process; PUBLIC_API_URL är basen som visas i dokumentationsutdrag. |
| Datalager | DATABASE_URL, REDIS_URL | DATABASE_URL väljer lagret; REDIS_URL är reserverad för jobbkön och läses inte av v1-kodsökvägen. |
| Inferens | INFERENCE_MOCK, GPU_ENABLED, VLLM_BASE_URL, VLLM_REGION, VLLM_MODEL_VERSION, VLLM_BASE_URL_<REGION>, DEFAULT_REGION, PARTNER_* | Se avsnittet om inferens nedan; PARTNER_* omfattar partnerns bas-URL, region, suveränitetsklass och API-nyckel. |
| Fakturering | FX_EUR_USD, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET | Huvudboken hålls i USD-mikro och EUR härleds för visning vid FX_EUR_USD. |
| E-post | MAIL_FROM, MAIL_SMTP_HOST, MAIL_SMTP_PORT, MAIL_SMTP_SECURE, MAIL_SMTP_USER, MAIL_SMTP_PASS, MAIL_TIMEOUT_MS, MAIL_API_URL, MAIL_API_KEY | Ange MAIL_SMTP_HOST för SMTP, eller MAIL_API_URL med MAIL_FROM för en HTTP-relä, eller ingen av dem. |
| Säkerhet | NODE_ENV, LLMEU_IP_SALT, LLMEU_DEMO_PASSWORD, LLMEU_KEY_ENV | NODE_ENV=production markerar sessionscookies som Secure. LLMEU_IP_SALT saltar den hashade klient-IP:n och bör ändras per distribution. LLMEU_KEY_ENV prefixar genererade nycklar med llmeu_live_ eller llmeu_test_. |
| Övrigt | LOG_LEVEL | LOG_LEVEL anger den lägsta loggnivån. |
Docker
Compose och avbildningen är valfria: arkivets egen svit kräver inte Docker, och den primära vägen är en lokal process utan tjänster.
- Standardprofilen kör web: portarna 3000 och 8088, SQLite på llmeu-data-volymen vid /app/data, det inbäddade API:et och en hälsokontroll på /healthz.
- Samma avbildning kör workern med node apps/worker/src/run.mjs, väntar på att web ska bli frisk och delar llmeu-data-volymen.
- Två extra profiler är avstängda som standard: postgres (postgres:16-alpine) och redis (redis:7-alpine, reserverad och läses inte av v1-kodvägen).
- gpu-profilen kör vllm/vllm-openai med en NVIDIA-enhetsreservation och monterar vikter skrivskyddat från värden; den är inte aktiverad som standard, eftersom att hävda EU-inferens utan en GPU skulle vara falskt.
- Dockerfile är FROM node:24-alpine med tini, inget byggsteg och ingen beroendeinstallation, körs som användaren node, skriver endast under /app/data, exponerar 3000 och 8088, och startar apps/web/server/main.mjs.
Säkerhetskopior
node scripts/backup.mjs utan flaggor skriver ./backups/llmeu-<stamp>.db. SQLite kopieras med VACUUM INTO, aldrig cp, eftersom en levande WAL-databas som kopieras med cp kan ge ett trasigt eller inaktuellt tillstånd.
node scripts/backup.mjs # ./backups/llmeu-<stamp>.db
node scripts/backup.mjs --out /srv/backups/ # explicit destination
node scripts/backup.mjs --verify ./backups/llmeu-<stamp>.db
node scripts/backup.mjs --restore ./backups/llmeu-<stamp>.db --yes
node scripts/backup.mjs --list
Varje SQLite-säkerhetskopia verifieras innan skriptet rapporterar framgång: den återställs till en temp-kopia, PRAGMA integrity_check måste returnera ok, schemat återappliceras, och radantal för modeller, organisationer och användare skrivs ut.
Med en postgres://-URL använder skriptet pg_dump --format=custom och behöver pg_dump i PATH; en dump kan inte öppnas som en databas, så dess radantal kräver en tillfällig återställning.
E-post
Transaktionell e-post – lösenordsåterställning, adressverifiering, inbjudningar – använder MAIL_SMTP_* eller MAIL_API_URL med MAIL_FROM. Transporten väljs en gång vid uppstart och rapporteras på varje sida som behöver e-post.
En distribution med ingen av dem är ett stödt tillstånd: registrering, inloggning, lösenordsbyte, team och inbjudningar fungerar, men e-post för lösenordsåterställning och verifiering kan inte hanteras där. Sidorna säger det, och node scripts/db.mjs passwd <email> är återställningsvägen.
Inferensbackends
En endpoint-rad namnger en körtid och en region, och backend-registret väljer adapter efter region, så en endpoint kan bara besvaras av en maskin i den region den namnger.
- INFERENCE_MOCK=true behåller den deterministiska mock-backenden, som inte behöver någon GPU och inga vikter.
- GPU_ENABLED=false håller hanterade backends borta; med GPU_ENABLED=true gäller VLLM_BASE_URL den enda region som namnges av VLLM_REGION.
- En distribution med flera regioner anger en variabel per region, namngiven efter regionens slug (till exempel VLLM_BASE_URL_DE_FRA). En endpoint i en region utan konfigurerad backend avvisas, i stället för att betjänas från en maskin i en annan region.
- Partner-backends kommer från PARTNER_BASE_URL_<REGION> och tar PARTNER_SOVEREIGNTY och PARTNER_API_KEY; servern tillåter partneranvändning när PARTNER_BASE_URL är satt.
Utan GPU svarar mock-backenden. Dess region är dev-mock, och dess utdata säger att den är mock-backenden, att inga riktiga vikter kördes, och att förstapartsinferens kräver VLLM_BASE_URL och flaggan gpu_enabled. En mock-framgång som såg verklig ut vore det enda den här produkten aldrig får leverera.