# Lovdata Chat Interface A container-per-session architecture for Norwegian legal research. Each user session gets an isolated [OpenCode](https://opencode.ai/) container connected to the external [Lovdata MCP server](https://modelcontextprotocol.io/), which provides 15+ tools for searching Norwegian laws, provisions, and cross-references. ## Architecture ``` Users → Caddy (reverse proxy) → Session Manager (FastAPI) ↓ Docker-in-Docker daemon ↓ ↓ ↓ [OC 1] [OC 2] [OC 3] ← OpenCode containers ↓ ↓ ↓ Lovdata MCP Server (external) LLM APIs (OpenAI/Anthropic/Google) ``` | Component | Purpose | |-----------|---------| | **Session Manager** | FastAPI service managing OpenCode container lifecycles | | **OpenCode Containers** | Isolated chat environments with MCP integration | | **Lovdata MCP Server** | External Norwegian legal research (laws, provisions, cross-references) | | **Caddy** | Reverse proxy with dynamic session-based routing | | **PostgreSQL** | Session persistence across restarts | | **Docker-in-Docker** | TLS-secured Docker daemon for container management | ### Session Manager Components ``` main.py → FastAPI endpoints, session lifecycle orchestration docker_service.py → Docker abstraction layer (testable, mockable) async_docker_client.py → Async Docker operations database.py → PostgreSQL session persistence with asyncpg session_auth.py → Token-based session authentication container_health.py → Health monitoring and auto-recovery resource_manager.py → CPU/memory limits, throttling http_pool.py → Connection pooling for container HTTP requests host_ip_detector.py → Docker host IP detection logging_config.py → Structured JSON logging with context ``` ## Quick Start 1. **Set up environment variables:** ```bash cp .env.example .env # Edit .env with your API keys and MCP server URL ``` 2. **Start the services:** ```bash docker-compose up --build ``` 3. **Create a session:** ```bash curl http://localhost/api/sessions -X POST ``` 4. **Access the chat interface** at the URL returned in step 3. ## Development ### Running the Stack ```bash # Start all services (session-manager, docker-daemon, caddy) docker-compose up --build # Start in background docker-compose up -d --build # View logs docker-compose logs -f session-manager # Stop services docker-compose down ``` ### Session Management API ```bash POST /api/sessions # Create new session GET /api/sessions # List all sessions GET /api/sessions/{id} # Get session info DELETE /api/sessions/{id} # Delete session POST /api/cleanup # Manual cleanup GET /api/health # Health check ``` ### Running Locally (without Docker) ```bash cd session-manager pip install -r requirements.txt uvicorn main:app --reload --host 0.0.0.0 --port 8000 ``` ### Testing Test scripts live in `docker/scripts/` and are self-contained: ```bash python docker/scripts/test-docker-service.py python docker/scripts/test-async-docker.py python docker/scripts/test-resource-limits.py python docker/scripts/test-session-auth.py python docker/scripts/test-database-persistence.py python docker/scripts/test-container-health.py python docker/scripts/test-http-connection-pool.py python docker/scripts/test-host-ip-detection.py python docker/scripts/test-structured-logging.py ``` ### Building the OpenCode Image ```bash make build MCP_SERVER=http://your-lovdata-server:8001 make run # Run interactively make clean # Clean up ``` ## Environment Configuration Required variables (see `.env.example`): ```bash MCP_SERVER=http://localhost:8001 # External Lovdata MCP server URL # Docker TLS (if using TLS instead of socket) DOCKER_TLS_VERIFY=1 DOCKER_CERT_PATH=/etc/docker/certs DOCKER_HOST=tcp://host.docker.internal:2376 # Optional LLM keys (at least one required for chat) OPENAI_API_KEY=... ANTHROPIC_API_KEY=... GOOGLE_API_KEY=... ``` ## Security **Docker socket**: Default setup uses socket mounting (`/var/run/docker.sock`). For production, enable TLS: ```bash cd docker && DOCKER_ENV=production ./scripts/generate-certs.sh ./scripts/setup-docker-tls.sh ``` **Session isolation:** - Each session gets a dedicated container - Resource limits: 4GB RAM, 1 CPU core per container - Max 3 concurrent sessions (configurable via `resource_manager.py`) - Auto-cleanup after 60 minutes inactivity - Token-based session authentication ## Further Documentation - [`CLAUDE.md`](CLAUDE.md) — AI assistant guidance for working with this codebase - [`LOW_PRIORITY_IMPROVEMENTS.md`](LOW_PRIORITY_IMPROVEMENTS.md) — Backlog of non-critical improvements - [`docs/project-analysis.md`](docs/project-analysis.md) — Detailed architectural analysis - `docker/*.md` — Implementation docs for individual components