Torbjørn Lindahl 991080ae2b test: add initial Cypress e2e test infrastructure
Smoke tests for verifying Cypress runs, plus basic API tests
for health and sessions endpoints.
2026-02-15 23:05:56 +01:00
2026-01-18 23:29:04 +01:00
2026-02-08 20:27:35 +01:00
2026-02-01 19:40:55 +01:00
2026-02-04 19:10:03 +01:00
2026-02-02 23:37:11 +01:00
2026-02-08 20:27:35 +01:00
2026-01-18 22:10:03 +01:00

Lovdata Chat Interface

A container-per-session architecture for Norwegian legal research. Each user session gets an isolated OpenCode container connected to the external Lovdata MCP server, 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:

    cp .env.example .env
    # Edit .env with your API keys and MCP server URL
    
  2. Start the services:

    docker-compose up --build
    
  3. Create a session:

    curl http://localhost/api/sessions -X POST
    
  4. Access the chat interface at the URL returned in step 3.

Development

Running the Stack

# 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

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)

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:

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

make build MCP_SERVER=http://your-lovdata-server:8001
make run    # Run interactively
make clean  # Clean up

Environment Configuration

Required variables (see .env.example):

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:

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

Description
No description provided
Readme 277 KiB
Languages
Python 84.6%
Shell 12.6%
JavaScript 1.7%
Makefile 0.6%
Dockerfile 0.5%