Files
MarketingTool/docs/DEPLOYMENT.md
T

94 lines
5.4 KiB
Markdown
Raw Normal View History

# Portable deployment and recovery runbook (Phase 15)
2026-09-03 16:24:53 +02:00
## Initial administrator is mandatory
Before the **first** API startup, you must choose one administrator-provisioning method. The simplest method is to set both values in the untracked `.env` file:
```dotenv
BOOTSTRAP_ADMIN_EMAIL=admin@example.com
BOOTSTRAP_ADMIN_PASSWORD=<strong-temporary-password>
```
These are not application defaults; they are one-time provisioning inputs. If both values are blank, the API starts without creating an administrator and login cannot succeed. Existing users are never overwritten by changing these values later.
After the first successful login, remove both values from `.env`, restart the API, and rotate the administrator password through the supported account-management process. Never commit or share the password.
## Configuration
Copy `.env.example` to an untracked deployment environment file. Production requires a secret-manager supplied `SESSION_SECRET` of at least 32 characters and refuses `AUTOMATED_OUTREACH_ENABLED=true`. Keep bootstrap credentials one-time only; remove and rotate them after provisioning. Never place secrets in images, Compose YAML, logs, backups, or public web roots.
2026-09-03 21:49:02 +02:00
For criteria-first AI web research without a paid scraper, use the self-hosted mode:
```dotenv
AI_RESEARCH_PROVIDER=nous_portal
NOUS_API_KEY=<Nous Portal API key>
NOUS_MODEL=Hermes-4-405B
NOUS_BASE_URL=https://inference-api.nousresearch.com/v1
NOUS_ALLOWED_HOSTS=inference-api.nousresearch.com
2026-09-03 21:49:02 +02:00
SEARXNG_BASE_URL=http://searxng:8080
SEARXNG_ALLOWED_HOSTS=searxng
SEARXNG_SECRET_KEY=<random secret>
```
2026-09-03 21:49:02 +02:00
Compose starts SearXNG without publishing a host port. The API reaches it only
on the internal Compose network; SearXNG alone has a separate egress network for
its upstream search engines. `web_search` calls SearXNG's JSON endpoint and
`scrape_website` uses the API's bounded SSRF-safe scanner. No Firecrawl key is
required. Firecrawl variables remain an optional legacy compatibility fallback.
The Nous adapter calls `/chat/completions` with strict `web_search` and
`scrape_website` function tools. Tool calls are capped at 4 and each result at
16 KiB; criteria, model output, page text, redirects, and candidate URLs remain
bounded and untrusted. Only structured HTTPS targets are accepted and the
existing crawler fetches/persists evidence. Missing/unsafe configuration,
unavailable providers, malformed calls, oversized responses, SSRF targets, and
exhausted budgets fail closed. Status metadata never includes secrets.
The prior OpenAI Responses and generic provider variables remain supported only
as compatibility adapters.
Validate before startup:
```sh
python3 -c 'from app.config import load_config; load_config()'
docker compose config --quiet
```
## Health and readiness
- `GET /api/v1/health/live` is process liveness and unauthenticated.
- `GET /api/v1/health/ready` checks SQLite connectivity and returns HTTP 503 until ready.
- `scripts/healthcheck.sh` checks readiness and the outreach safety flag.
Use readiness for load balancers and container health checks; liveness is only for process supervision.
## SQLite backup and restore
Backups are host-side artifacts and never include `.env` or secret files. `backup_sqlite.sh` uses SQLite's online backup API for a consistent snapshot, writes with mode 0600 to a temporary file, atomically renames it, writes a SHA-256 sidecar, and retains only the newest configured count.
```sh
scripts/backup_sqlite.sh /var/lib/prospect-platform/prospects.db /var/backups/prospect-platform 30
```
Before restoring, stop application writes, verify the checksum sidecar, and use the explicit confirmation flag. The script first makes a pre-restore backup, then atomically replaces the target only after an integrity check:
```sh
scripts/restore_sqlite.sh /var/backups/prospect-platform/prospects-<timestamp>.db /var/lib/prospect-platform/prospects.db --confirm-restore
```
Validate backup directory permissions and keep copies encrypted/off-host according to the retention policy. Test restores in an isolated directory quarterly. Never use `docker compose down -v` on a data-bearing installation.
## Rollback
`scripts/rollback.sh` is deliberately non-destructive: it prints the approved image/tag or digest rollback procedure and executes no stop, delete, restore, or deployment action. Record old/new image digests, configuration revision, backup/checksum, and health/readiness evidence.
## systemd / Virtualmin
`systemd/prospect-api.service.example` is a least-privilege service example. Copy it to a reviewed systemd unit, create `/etc/prospect-platform/prospect.env` with mode 0600, use a dedicated user/data directory, and place TLS/reverse proxying in the Virtualmin-managed web tier. Do not put environment files under `public_html`.
## Monitoring and incident response
Monitor readiness failures, restart count, HTTP 5xx rate, SQLite backup age/checksum failures, disk usage, and unexpected outbound traffic. Alert when the latest backup is older than the agreed RPO or when a restore drill fails. Routine logs must not contain passwords, tokens, cookies, API keys, full contact values, or free-text notes.
On incident: record image/config revision and health state; preserve redacted logs and audit evidence; isolate the service for data loss, unauthorized access, or unexpected outbound traffic; rotate secrets through the secret manager; validate restore/readiness and tenant-scoped reads; then document root cause and retention impact. Outreach remains disabled throughout.