# Coolify staging deploy — artenschutz-router Goal: stand up the router on Coolify staging, in the same Docker network as `agent.memory.system`, so it can reach `memory-qdrant`, `memory-embeddings`, and `memory-api` by container name. Then run an end-to-end smoke ingest + search against real data. ## Pre-flight You should already have on staging Coolify: - A running `agent.memory.system` (memory-api + memory-qdrant + memory-embeddings) - The Docker network name those services live on (probably `coolify` — check `docker network ls` on the staging host) Note down: | Setting | Value (example) | |---|---| | Coolify project | `gruenstifter-staging` | | Docker network | `coolify` | | memory-api container name | `memory-api-` | | memory-qdrant container name | `memory-qdrant-` | | memory-embeddings container name | `memory-embeddings-` | > The *full* container names include Coolify's stack hash suffix. The > compose file uses the short service names (`memory-api`, etc.) which work > when the router is on the same Coolify-managed network — Coolify creates > service-name aliases. If they don't resolve, fall back to container IPs > via `docker inspect`. ## Path A — Push to forgejo, let Coolify auto-deploy (preferred) ```bash cd /home/m2/artenschutz-router git init -b main git add . git commit -m "Initial commit — phase 1 + 2" git remote add origin :gruenstifter/artenschutz-router.git git push -u origin main ``` In Coolify staging: 1. New Resource → **Application** → **Public Git Repository** (or Private, add the SSH key) 2. Source: the forgejo URL above 3. Build Pack: **Dockerfile** 4. Set environment variables: ``` QDRANT_URL=http://memory-qdrant:6333 QDRANT_COLLECTION=agent_memory BGE_TEI_URL=http://memory-embeddings:8000 MEMORY_API_URL=http://memory-api:8000 ARTENSCHUTZ_AGENT_ID=gruenstifter_staging ROUTER_PORT=8080 LOG_LEVEL=INFO ``` `gruenstifter_staging` keeps smoke data cleanly separable from any future production write. 5. Network: join the same network as `agent.memory.system` (usually `coolify`). 6. Port: 8080 (no public exposure needed for smoke — internal-only is fine). 7. Deploy. ## Path B — Docker Compose on the Coolify host If you'd rather not push to forgejo yet: ```bash # On the Coolify host (or via SSH): scp -r /home/m2/artenschutz-router coolify-host:/opt/coolify-apps/ ssh coolify-host cd /opt/coolify-apps/artenschutz-router cp .env.example .env # Edit .env to set ARTENSCHUTZ_AGENT_ID=gruenstifter_staging docker compose build docker compose up -d docker compose logs -f artenschutz-router ``` This bypasses Coolify's UI but uses the same `coolify` external network the memory stack joins. ## Verify it's up From any shell on the Coolify host: ```bash docker exec artenschutz-router curl -sS http://localhost:8080/health # expect: {"status":"ok","qdrant":true,"bge":true,"memory_api":true} ``` `status: "degraded"` with one of the three `false` means that service isn't reachable from inside the router's network namespace — fix container names / network attachment before continuing. ## End-to-end smoke (uses the test data already symlinked in `sources/`) ```bash # 1. Fetch BNatSchG into the container's sources/bnatschg/ if not already. docker exec artenschutz-router python scripts/fetch_bnatschg.py # 2. Run the smoke (ingests small batches + queries them back). docker exec artenschutz-router bash scripts/smoke.sh ``` The smoke script ingests ~5 records per source, then runs three searches: - Hybrid query `"Fledermäuse Kartierung"` filtered to `fact_type=method` - Hybrid query `"besonders geschützte Arten"` filtered to `fact_type=legal` - Payload-only scroll on `scope.states=BE` to verify state filtering Expected: each search returns ≥1 hit. If hybrid returns 0 hits but scroll works, BGE-M3 embedding is failing — check the logs. ## Cleanup (after smoke) Drop the staging agent_id from Qdrant: ```bash docker exec memory-qdrant- curl -X POST \ http://localhost:6333/collections/agent_memory/points/delete \ -H 'Content-Type: application/json' \ -d '{"filter":{"must":[{"key":"agent_id","match":{"value":"gruenstifter_staging"}}]}}' ``` This wipes every point we wrote under the staging agent_id. Nothing else is affected because partition isolation is by `agent_id`.