Container-ready via docker/ compose (frontend nginx + backend Node). Compose adjusted for Coolify on the prod server: frontend uses expose:80 (no host binding — host 8080 is taken by the Coolify proxy; Traefik routes visigine.de), backend ALLOWED_ORIGINS=https://visigine.de. Secrets stay in server/.env (git-ignored); see server/.env.example. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
72 lines
2.0 KiB
Markdown
72 lines
2.0 KiB
Markdown
# Visigine
|
|
|
|
GEO/SEO-Auditor für AI-Suchen (ChatGPT, Claude, Perplexity, Gemini …).
|
|
Frontend: React 19 + Vite. Backend: Node 20 + Express.
|
|
|
|
## Dev-Setup
|
|
|
|
```bash
|
|
# Frontend deps
|
|
npm install
|
|
|
|
# Backend deps
|
|
npm install --prefix server
|
|
|
|
# Backend secrets
|
|
cp server/.env.example server/.env
|
|
# → MISTRAL_KEY=... in server/.env eintragen
|
|
```
|
|
|
|
## Start
|
|
|
|
```bash
|
|
npm run dev
|
|
```
|
|
|
|
Startet client (Vite, Port 5173) und server (Express, Port 3001) parallel.
|
|
Vite proxied `/api/*` automatisch an den Backend-Port.
|
|
|
|
Health-Check: `curl http://localhost:3001/health` → `{"ok":true}`.
|
|
|
|
## Secrets
|
|
|
|
Der Mistral-API-Key liegt **nur** in `server/.env` als `MISTRAL_KEY`.
|
|
Es gibt keine `VITE_*`-Keys im Frontend — der Browser sieht den Schlüssel nie.
|
|
|
|
## Stack
|
|
|
|
- React 19, Vite 8 (kein TypeScript)
|
|
- Express 4, Node 20 native `fetch`
|
|
- Mistral `mistral-large-latest` (nur serverseitig)
|
|
|
|
## Production Deployment
|
|
|
|
### Backend (`server/`)
|
|
|
|
Required env vars:
|
|
|
|
- `MISTRAL_KEY` — Mistral API key (server-only, never exposed to the client).
|
|
- `PORT` — port to bind (default `3001`).
|
|
- `ALLOWED_ORIGINS` — comma-separated CORS whitelist
|
|
(e.g. `https://www.visigine.de,https://visigine.de`).
|
|
- `NODE_ENV=production` — disables debug mode unconditionally.
|
|
- `ALLOW_PRIVATE_HOSTS=0` — keep at `0` in production (SSRF protection).
|
|
|
|
Run: `npm start` inside `server/`. The Express listener binds `0.0.0.0:$PORT`
|
|
so containers and reverse proxies can reach it.
|
|
|
|
Health check: `GET /health` → `{ "ok": true }`.
|
|
|
|
### Frontend
|
|
|
|
Static build: `npm run build` in the repo root → `dist/`. Serve via any
|
|
static host. The frontend calls `/api/analyze` — your hosting layer must
|
|
proxy `/api/*` to the backend (nginx / Caddy / Cloudflare Workers / etc.).
|
|
|
|
### Operations
|
|
|
|
- Rate limit: 20 requests / 60 s / IP on `/api/analyze`.
|
|
- In-memory cache: 1 h TTL, 1000 entries (LRU). `X-Cache: HIT|MISS` header.
|
|
- Every request gets an `X-Request-Id` and a structured log line.
|
|
- `?debug=1` is ignored when `NODE_ENV=production`.
|