Dashboard Service¶
The Aegis Dashboard is a FastAPI application that provides the web interface, API endpoints, and administrative tools for Project Aegis.
Overview¶
- Framework: FastAPI
- Container:
aegis-dashboard - Port: 8080 (internal), mapped to public domains via Traefik
- URLs:
- https://aegisagent.ai (primary)
- https://aegis.rbnk.uk (redirects to primary)
- https://intel.aegisagent.ai (intel subdomain)
Architecture¶
Application Structure¶
The dashboard follows a modular architecture with separate route modules:
aegis/dashboard/
├── app.py # Main FastAPI application
├── routes/ # 58+ route modules (22,203 total lines)
│ ├── system.py # Health, status, rate limits
│ ├── intel_api.py # Intel API subscriptions
│ ├── vonage.py # WhatsApp webhooks
│ ├── marketplace.py # API marketplace
│ ├── blog.py # Blog content
│ └── ...
├── templates/ # Jinja2 HTML templates
└── repository.py # Data access layer
Middleware Stack¶
Applied in order (first = outermost):
- ProxyHeadersMiddleware - Trusts X-Forwarded-* headers from Traefik
- CORSMiddleware - CORS headers for API access
- SecurityHeadersMiddleware - Security headers (X-Content-Type-Options, X-Frame-Options, etc.)
Security Headers¶
All responses include:
- X-Content-Type-Options: nosniff
- X-Frame-Options: DENY
- X-XSS-Protection: 1; mode=block
- Referrer-Policy: strict-origin-when-cross-origin
- Cache-Control: no-store, no-cache, must-revalidate
API Endpoints¶
System APIs¶
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Health check (returns database status) |
/api/status |
GET | System status (phase, version, timestamp) |
/api/tasks |
GET | Task statistics |
/api/ooda |
GET | OODA cycle success rate |
/api/memory/recent |
GET | Recent episodic memories |
/api/rate-limit |
GET | Check rate limit status |
Intel APIs¶
| Endpoint | Method | Description |
|---|---|---|
/api/intel/pricing |
GET | Get pricing tiers |
/api/intel/key/create |
POST | Create new API key |
/api/intel/key/verify |
GET | Verify API key |
/api/intel/keys |
GET | List API keys |
/api/intel/docs |
GET | API documentation |
File Sharing APIs¶
| Endpoint | Method | Description |
|---|---|---|
/api/files/share |
POST | Create shareable link |
/share/{token} |
GET | Access shared file |
HTML Pages¶
| Route | Description |
|---|---|
/ |
Landing page (intel dashboard for intel subdomain) |
/products |
Products overview |
/research |
Research API landing |
/api-docs |
Human-friendly API documentation |
/dashboard |
Internal status dashboard |
/analytics |
Usage analytics with charts |
/orchestration |
Agent orchestration visualization |
/market |
Market research dashboard |
/blog |
Blog post listing |
/blog/{slug} |
Individual blog post |
/docs/architecture |
System architecture docs |
Startup Process¶
1. Initialization¶
2. Startup Event¶
On application start (@app.on_event("startup")):
- Create asyncpg connection pool (2-10 connections)
- Host:
host.docker.internal(PostgreSQL on host) - Database:
aegis -
User:
agent -
Initialize ShareTokenRepository
- Creates
file_sharestable if not exists -
Manages time-limited file sharing tokens
-
Start APScheduler
- Loads scheduled jobs from
aegis.scheduler -
See scheduler.md for details
-
Resume Meshy 3D Tasks
- Checks for incomplete 3D model generation tasks
- Resumes polling for completion
3. Shutdown Event¶
On application shutdown (@app.on_event("shutdown")):
- Stop APScheduler
- Close asyncpg connection pool
Configuration¶
Environment Variables¶
Core settings from docker-compose.yml:
# Database
POSTGRES_HOST=host.docker.internal
POSTGRES_PORT=5432
POSTGRES_USER=agent
POSTGRES_PASSWORD=agent
POSTGRES_DB=aegis
# External APIs
GITHUB_TOKEN=<token>
STRIPE_SECRET_KEY=<key>
ZAI_API_KEY=<key>
CLAUDE_CODE_OAUTH_TOKEN=<token>
DISCORD_ALERTS_CHANNEL=<channel_id>
TELEGRAM_BOT_TOKEN=<token>
# Vonage/WhatsApp
VONAGE_API_KEY=<key>
VONAGE_API_SECRET=<secret>
VONAGE_APPLICATION_ID=<app_id>
VONAGE_WHATSAPP_NUMBER=+447441443388
VONAGE_PRIVATE_KEY_B64=<base64_key>
VONAGE_SIGNATURE_SECRET=<secret>
# Email (Resend)
SMTP_HOST=smtp.resend.com
SMTP_PORT=587
SMTP_USER=<resend_key>
SMTP_PASSWORD=<resend_key>
SMTP_FROM=noreply@aegisagent.ai
RESEND_API_KEY=<key>
# Knowledge Graph
FALKORDB_HOST=host.docker.internal
FALKORDB_PORT=6379
OLLAMA_BASE_URL=http://host.docker.internal:11434
# Base URL
AEGIS_BASE_URL=https://aegisagent.ai
Volumes¶
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro # Docker API (read-only)
- /home/agent/memory:/home/agent/memory # Memory files
- /home/agent/downloads:/home/agent/downloads # Download cache
- /home/agent/projects/aegis-core/.beads:/app/.beads:ro # Beads tasks
- /home/agent/.secure:/home/agent/.secure:ro # Secrets
Traefik Integration¶
Docker Labels¶
The dashboard container uses Traefik labels for routing:
labels:
- "traefik.enable=true"
# Main router (aegisagent.ai)
- "traefik.http.routers.aegis.rule=Host(`aegisagent.ai`)"
- "traefik.http.routers.aegis.entrypoints=websecure"
- "traefik.http.routers.aegis.tls.certresolver=cf"
- "traefik.http.services.aegis.loadbalancer.server.port=8080"
# Redirect router (aegis.rbnk.uk → aegisagent.ai)
- "traefik.http.routers.aegis-redirect.rule=Host(`aegis.rbnk.uk`)"
- "traefik.http.routers.aegis-redirect.middlewares=aegis-redirect-mw"
- "traefik.http.middlewares.aegis-redirect-mw.redirectregex.regex=^https://aegis\\.rbnk\\.uk(.*)"
- "traefik.http.middlewares.aegis-redirect-mw.redirectregex.replacement=https://aegisagent.ai$$1"
- "traefik.http.middlewares.aegis-redirect-mw.redirectregex.permanent=true"
# Intel subdomain
- "traefik.http.routers.intel.rule=Host(`intel.aegisagent.ai`)"
- "traefik.http.routers.intel.service=aegis"
SSL/TLS¶
- Certificate resolver: Cloudflare DNS challenge (
cf) - Email: aegis@richardbankole.com
- Automatic renewal via Let's Encrypt
Rate Limiting¶
Rate limits are applied per client key (IP or API key):
from aegis.ratelimit import check_rate_limit, get_client_key
key, tier = get_client_key(request, api_key)
allowed, info = check_rate_limit(key, endpoint, tier)
Tiers: - Anonymous: IP-based, lower limits - Basic/Pro/Enterprise: API key-based, higher limits
Database Integration¶
Connection Pool¶
The dashboard uses asyncpg for async PostgreSQL operations:
pool = await asyncpg.create_pool(
host=settings.postgres_host,
port=settings.postgres_port,
user=settings.postgres_user,
password=settings.postgres_password,
database=settings.postgres_db,
min_size=2,
max_size=10,
)
app.state.pg_pool = pool
Access pool in routes:
async def my_endpoint(request: Request):
pool = request.app.state.pg_pool
async with pool.acquire() as conn:
result = await conn.fetch("SELECT * FROM table")
Synchronous Access¶
For synchronous operations, use aegis.db:
from aegis.db import db
status = db.get_state("operational_status")
memories = db.fetch_all("SELECT * FROM episodic_memory LIMIT 10")
Health Checks¶
Container Health¶
Docker healthcheck runs every 30 seconds:
Returns:
If database is unreachable:
Development¶
Running Locally¶
cd /home/agent/projects/aegis-core
# Build image
docker compose build dashboard
# Start service
docker compose up -d dashboard
# View logs
docker compose logs -f dashboard
# Restart after code changes
docker compose restart dashboard
Adding New Routes¶
- Create route module in
aegis/dashboard/routes/my_feature.py -
Define router:
-
Export router in
aegis/dashboard/routes/__init__.py: -
Include in
aegis/dashboard/app.py:
Adding Templates¶
- Create Jinja2 template in
aegis/dashboard/templates/my_page.html - Add route in
app.py:
Monitoring¶
Logs¶
View logs with structured logging:
Log format (structlog):
2026-01-25T12:00:00Z event=request_received method=GET path=/api/status
2026-01-25T12:00:01Z event=asyncpg_pool_initialized
Metrics¶
Key metrics tracked: - Request count per endpoint - Response times - Database connection pool utilization - Rate limit hits - Error rates
Troubleshooting¶
Dashboard won't start¶
-
Check PostgreSQL is running:
-
Check Docker socket access:
-
View container logs:
Database connection errors¶
Ensure host.docker.internal resolves inside container:
SSL/certificate issues¶
Check Traefik logs:
Verify Cloudflare DNS challenge works:
Rate limiting too strict¶
Adjust limits in aegis/ratelimit.py or bypass with API key.
Related Documentation¶
- scheduler.md - Scheduled jobs and cron tasks
- postgresql.md - Database schema and queries
- traefik.md - Reverse proxy configuration
- falkordb.md - Knowledge graph integration