System Architecture Overview
WDG AI Development Environment is a containerized WordPress development platform with integrated AI capabilities.
High-Level Architecture
%%{init: {'theme':'neutral'}}%%
graph TB
subgraph "Developer Machine"
CLI[WDG CLI]
Browser[Web Browser]
Editor[Code Editor]
Claude[Claude Desktop]
subgraph "Docker Environment"
subgraph "Core Services"
Nginx[Nginx Proxy<br/>host :6443 → :443]
MySQL[(MySQL<br/>host :6306 → :3306)]
Qdrant[(Qdrant<br/>:6333 / :6334)]
MCP[MCP Server<br/>host :6765 → :8765]
Indexer[Code Indexer<br/>host :6666 → :8666]
end
subgraph "Project Containers"
WP1[Project 1<br/>WordPress + PHP]
WP2[Project 2<br/>WordPress + PHP]
WP3[Project N<br/>WordPress + PHP]
end
end
subgraph "File System"
Projects["/projects"]
Repos["/repositories"]
SSL["/ssl"]
Data["/data"]
end
end
CLI --> Nginx
Browser --> Nginx
Claude --> MCP
Editor --> Projects
Nginx --> WP1
Nginx --> WP2
Nginx --> WP3
WP1 --> MySQL
WP2 --> MySQL
WP3 --> MySQL
Indexer -->|embeds in-process| Qdrant
MCP --> Qdrant
WP1 --> Repos
WP2 --> Repos
WP3 --> Repos
Host ports shown are the
.env.defaultsvalues (the canonical defaults checked into git). All ports are configurable via.envorwdg ports. The MCP auth proxy (host:6766) and the dashboard backend (FastAPI, host:6001) run on the host, not in Docker — see Networking.
Component Architecture
1. CLI Layer
The WDG CLI (/cli/wdg) is the primary interface:
- Shell Script: Pure bash for portability
- Docker Integration: Manages containers via docker-compose
- Project Management: Creates, starts, stops, deletes projects
- Repository Management: Git operations and syncing
- Indexing Control: Triggers AI indexing pipeline
2. Container Layer
Core Services (Always Running)
Nginx Proxy
- Routes
*.localhost:6443(default HTTPS port) to project containers - SSL termination with self-signed certificates
- WebSocket support for hot-reload
- Header injection for WordPress HTTPS detection
MySQL Database
- Single instance for all projects (container
wdg-mysql, imagemysql:8.0) - Separate database per project (
wp_project_name) - Root access for management operations
- Data persisted via bind mount at
./data/mysql
Qdrant Vector Database
- Stores code embeddings
- Separate collections per scope (
wdg_framework,platform,project_{name}) - REST API on port 6333, gRPC on 6334
- Data persisted via bind mount at
./data/qdrant
MCP Server
- Model Context Protocol for AI assistants
- Bridges Claude Desktop / Claude Code to vector search
- Python FastMCP application (container
wdg-mcp, host port 6765 → container 8765)
Code Indexer
- FastAPI HTTP service (container
wdg-indexer, host port 6666 → container 8666) - Embeds code in-process with a local Sentence-Transformers model
- Receives incremental index requests from git hooks (see Git Hooks)
Documentation Site
- VitePress dev server (container
wdg-docs, host port 6173 → container 5173)
Project Containers (On-Demand)
Each project runs in its own WordPress container:
- Base Image:
wordpress:latest - PHP Version: 8.1+ with extensions
- WordPress: Latest version auto-installed
- WP-CLI: Pre-installed for automation
- Volume Mounts:
- Theme repositories →
/var/www/html/wp-content/themes/ - Plugin repositories →
/var/www/html/wp-content/plugins/
- Theme repositories →
3. AI Layer
Indexing Pipeline
%%{init: {'theme':'neutral'}}%%
sequenceDiagram
participant CLI
participant Docker
participant Indexer
participant Model
participant Qdrant
CLI->>Docker: Run indexer container
Docker->>Indexer: Execute indexer.py
Indexer->>Indexer: Parse code files
loop For each code chunk
Indexer->>Model: Generate embedding
Model->>Indexer: Return vector
Indexer->>Qdrant: Store vector + metadata
end
Qdrant->>CLI: Indexing complete
Local Embedding Model
- Library: Sentence-Transformers
- Model:
all-MiniLM-L6-v2(default; override withEMBEDDING_MODELin.env) - Dimensions: 384-dimensional vectors (model-dependent)
- Distance: Cosine
- No Internet Required: Model downloaded once and cached in the
transformer-cachenamed volume - In-process: Embeddings are generated inside the indexer process — there is no separate embedder service
4. Storage Architecture
/home/user/wdg-ai-dev/
├── projects/ # Project files
│ └── my-site/
│ ├── backups/ # Database backups
│ ├── config/ # Project configuration
│ ├── logs/ # Application logs
│ ├── repositories/ # Project-specific repository clones
│ │ └── my-site/ # Repository for this project
│ │ └── wp-content/
│ │ ├── themes/
│ │ ├── plugins/
│ │ ├── mu-plugins/
│ │ └── uploads/
│ ├── docker-compose.yml
│ └── project.json
├── repositories/ # Central repository storage
│ ├── wikit-core/ # Wikit framework
│ ├── wikit-theme/ # Base theme template
│ ├── wikit-facets/ # Component library
│ └── wikit-app/ # Application framework
├── services/ # Service configurations
│ ├── nginx/
│ │ ├── default.conf # Mounted into wdg-nginx
│ │ ├── sites-available/
│ │ └── sites-enabled/ # Per-project configs (mounted read-only)
│ ├── wordpress/
│ │ ├── Dockerfile # WordPress image build (default PHP 8.2)
│ │ ├── setup-wp.sh # WP-CLI automation
│ │ └── my.cnf # MySQL client config baked into the WP image
│ ├── templates/ # Project scaffolding templates
│ └── docker-compose.project-template.yml # Per-project compose template
├── ssl/ # SSL certificates
│ ├── my-site.localhost.crt
│ └── my-site.localhost.key
├── data/ # Persistent data (bind mounts, not named volumes)
│ ├── mysql/ # MySQL data files → mounted into wdg-mysql
│ └── qdrant/ # Vector database → mounted into wdg-qdrant
├── cli/ # Command-line tools
└── docker-compose.yml # Main service orchestrationNote: MySQL and Qdrant data live in host bind mounts (./data/mysql, ./data/qdrant), not named volumes. The only named volume in docker-compose.yml is transformer-cache, which holds the downloaded embedding model and is shared by the indexer and MCP server.
Network Architecture
Docker Networks
networks:
wdg-network:
external: truewdg-network is an external bridge network created by the installer/CLI before compose runs (it is not defined inline with a driver/ipam block). Docker assigns the subnet automatically (in practice 172.19.0.0/16); it is not pinned in configuration. All containers join wdg-network for inter-service communication and resolve each other by service name.
Port Mapping
Host ports below are the .env.defaults values and are configurable via .env / wdg ports. Container-internal ports are fixed.
| Service | Container Port | Host Port (default) | Purpose |
|---|---|---|---|
| Nginx | 80, 443 | 6080, 6443 | HTTP/HTTPS proxy |
| MySQL | 3306 | 6306 | Database |
| Qdrant | 6333, 6334 | 6333, 6334 | Vector DB + gRPC |
| MCP Server | 8765 | 6765 | AI bridge (FastMCP) |
| Indexer | 8666 | 6666 | Incremental indexing API |
| WordPress | 80 | — | Internal only |
| Dashboard Frontend | 3000 | 6300 | React dashboard |
| Docs | 5173 | 6173 | VitePress docs |
| phpMyAdmin | 80 | 6081 | Database admin |
Run on the host (not in Docker):
| Service | Host Port (default) | Notes |
|---|---|---|
| MCP Auth Proxy | 6766 | OAuth-authenticated remote MCPs; needs host keychain for token storage |
| Dashboard Backend | 6001 | FastAPI; runs on host so it can spawn the claude CLI with user credentials. Start via dashboard/backend/start-backend.sh |
Note: Default host ports use the 6xxx range to avoid conflicts with common local development servers (e.g. 3000, 5173, 8080) and local MySQL on 3306.
SSL/TLS Configuration
Each project gets automatic SSL:
server {
listen 443 ssl http2;
server_name my-site.localhost;
ssl_certificate /etc/nginx/ssl/my-site.localhost.crt;
ssl_certificate_key /etc/nginx/ssl/my-site.localhost.key;
location / {
proxy_pass http://wdg-wp-my-site:80;
proxy_set_header X-Forwarded-Proto https;
}
}Database Architecture
MySQL Structure
-- System databases
mysql
information_schema
performance_schema
-- Project databases
wp_my_site -- Project: my-site
wp_another_site -- Project: another-siteQdrant Collections
{
"collections": [
{
"name": "wdg_framework",
"dimension": 384
},
{
"name": "platform",
"dimension": 384
},
{
"name": "project_my_site",
"dimension": 384
}
]
}Collections: wdg_framework (Wikit), platform (CLI/MCP/indexer/dashboard/docs, created by wdg index --platform), and one project_{name} per project (hyphens in the project name become underscores). Vector counts vary by codebase and are illustrative only.
Security Architecture
Container Isolation
- Each project runs in isolated container
- No shared file system between projects
- Network segmentation via Docker networks
- Resource limits prevent noisy neighbors
Database Security
- Unique database per project
- Random passwords generated
- No external MySQL access by default
- Connection only via Docker network
SSL/TLS
- Self-signed certificates for development
- Forced HTTPS redirect
- Secure headers (HSTS, XSS protection)
- Certificate per domain
Code Privacy
- All processing happens locally
- No external API calls for embeddings
- Vector database runs on localhost
- Git repositories remain private
Performance Architecture
Caching Layers
Docker Layer Caching
- Base images cached locally
- Incremental builds
- Shared layers between projects
Model Caching
- Embedding model downloaded once
- Cached in Docker volume
- Shared across all indexing operations
Query Caching
- Qdrant in-memory cache
- MCP server caches loaded embedding model and clients
Optimization Strategies
Container Start Time
- Pre-built base images
- Minimal container layers
- Volume mounts over COPY
- Parallel container starts
Indexing Performance
- Batched upserts to Qdrant (50 points per batch)
- Parallel file processing via a thread pool
- Incremental indexing on commit (via the indexer HTTP service)
Query Performance
- HNSW index in Qdrant
- Approximate nearest neighbor
- Limited result sets
Scalability Considerations
Horizontal Scaling
%%{init: {'theme':'neutral'}}%%
graph LR
subgraph "Current"
Single[Single Machine<br/>All Services]
end
subgraph "Scalable"
LB[Load Balancer]
WP_1[WordPress Fleet]
DB[(MySQL Cluster)]
QD[(Qdrant Cluster)]
end
Single --> LB
LB --> WP_1
WP_1 --> DB
WP_1 --> QD
Resource Limits
| Component | CPU Limit | Memory Limit | Disk Usage |
|---|---|---|---|
| WordPress | 2 cores | 2GB | 1GB/project |
| MySQL | 2 cores | 4GB | 10GB total |
| Qdrant | 1 core | 2GB | 5GB |
| Nginx | 0.5 cores | 512MB | 100MB |
| Indexer | 2 cores | 1GB | Ephemeral |
Scaling Strategies
- Vertical: Increase Docker resource limits
- Horizontal: Run projects on multiple machines
- Distributed: Separate database/vector tiers
- Cloud: Deploy to Kubernetes cluster
Development vs Production
This architecture is optimized for local development:
| Aspect | Development (Current) | Production |
|---|---|---|
| SSL | Self-signed | Let's Encrypt |
| Database | Single MySQL | RDS/CloudSQL |
| Vectors | Local Qdrant | Managed Qdrant |
| Storage | Local disk | Object storage |
| Backup | Manual | Automated |
| Monitoring | Basic logs | Full observability |
Future Architecture
Planned Enhancements
Kubernetes Deployment
- Helm charts for easy deployment
- Auto-scaling based on load
- Multi-node support
Incremental Indexing
- Watch file changes
- Index only modified files
- Real-time vector updates
Distributed Vectors
- Qdrant clustering
- Sharded collections
- Federated search
Local LLMs
- Code completion
- Automated refactoring
- Bug detection
Key Takeaway: The architecture prioritizes developer experience with fast project creation, local AI features, and complete privacy while maintaining flexibility for future scaling.