162 lines
5.0 KiB
Markdown
162 lines
5.0 KiB
Markdown
# 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 |