Skip to content

Commit fbf9478

Browse files
committed
docs(readme): update architecture and networking model to reflect single-gateway design
1 parent 294b4e1 commit fbf9478

File tree

1 file changed

+178
-15
lines changed

1 file changed

+178
-15
lines changed

dashboard/README.md

Lines changed: 178 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ The Dashboard service provides a web-based UI for monitoring Shadow IT detection
66

77
- **Frontend:** React 19 + Vite + TailwindCSS v4
88
- **Backend:** FastAPI (Python 3.11)
9-
- **Deployment:** Multi-stage Docker build with Nginx reverse proxy
9+
- **Web Server:** Nginx (single-gateway configuration)
10+
- **Deployment:** Multi-stage Docker build with integrated orchestration
1011

1112
## Structure
1213

@@ -20,11 +21,43 @@ dashboard/
2021
│ ├── main.py
2122
│ ├── config.py
2223
│ └── requirements.txt
23-
├── Dockerfile # Multi-stage build
24-
├── nginx.conf # Reverse proxy config
25-
└── start.sh # Service orchestration
24+
├── Dockerfile # Multi-stage build (Node.js + Python)
25+
├── nginx.conf # Single-gateway reverse proxy configuration
26+
└── start.sh # Service orchestration script
2627
```
2728

29+
## Port Configuration
30+
31+
### Production-Ready Single-Gateway Architecture
32+
33+
**Port 3000** - **ONLY** public entry point (served by Nginx)
34+
- **Dashboard UI:** `http://localhost:3000`
35+
- **API Backend:** `http://localhost:3000/api/*` → proxied to internal port 8001
36+
- **Collector Logs:** `http://localhost:3000/logs` → proxied to collector service
37+
- **Collector Ingest:** `http://localhost:3000/collect/*` → proxied to collector service
38+
39+
**Port 8001** - Internal FastAPI backend (not exposed externally)
40+
- Only accessible within Docker container
41+
- Handles `/api/*` requests from Nginx
42+
43+
**Port 8000** - ❌ **NOT EXPOSED** (collector internal only)
44+
- Collector runs on port 8000 inside Docker network
45+
- Accessible to dashboard container via `shadowguard-collector:8000`
46+
- Not accessible from host machine
47+
48+
### Why Single Gateway?
49+
50+
**One entry point** - All traffic flows through port 3000
51+
**No CORS issues** - Same origin for UI and API
52+
**Clean routing** - Nginx handles all proxying internally
53+
**Production-ready** - Maps directly to port 443 in production
54+
**Security** - Collector not exposed to public network
55+
56+
### Local Development
57+
58+
- Frontend dev server: `http://localhost:5173` (Vite)
59+
- Backend dev server: `http://localhost:8001` (Uvicorn)
60+
2861
## Development (Local)
2962

3063
### Frontend
@@ -56,26 +89,156 @@ docker build -t shadowguard-dashboard .
5689
docker-compose up dashboard
5790

5891
# With all services
59-
docker-compose up
92+
docker-compose up redis collector worker dashboard
93+
94+
# Rebuild after changes
95+
docker-compose up --build dashboard
6096
```
6197

62-
The dashboard will be accessible at **http://localhost:8000**
98+
### Access Points
99+
- **Dashboard UI:** http://localhost:3000
100+
- **API Endpoints:** http://localhost:3000/api/*
101+
- **Log Ingestion:** http://localhost:3000/logs (for generator)
102+
103+
## How It Works
104+
105+
The dashboard uses a multi-stage Docker build and single Nginx gateway configuration:
63106

64-
### How It Works
65-
- Nginx listens on port 3000
66-
- Static frontend files served from `/usr/share/nginx/html`
67-
- API requests (`/api/*`) proxied to FastAPI backend on port 8000
68-
- Redis connection via Docker network (`redis:6379`)
107+
1. **Frontend Build (Stage 1)**
108+
- Node.js 20 builds React app with Vite
109+
- Output: Static files in `dist/`
110+
111+
2. **Backend Preparation (Stage 2)**
112+
- Python 3.11 installs FastAPI dependencies
113+
- Prepares backend application
114+
115+
3. **Runtime Container (Stage 3)**
116+
- Nginx serves static frontend on port 3000
117+
- Nginx proxies API requests to internal port 8001
118+
- Nginx proxies collector requests to `shadowguard-collector:8000`
119+
- FastAPI backend runs on internal port 8001
120+
- All services orchestrated via `start.sh`
121+
122+
### Network Flow (Production-Ready Single Gateway)
123+
124+
```
125+
┌─────────────────────────────────────────────────────────────┐
126+
│ Port 3000 (ONLY Public Entry) │
127+
│ Nginx Gateway │
128+
└─────────────────────────────────────────────────────────────┘
129+
|
130+
┌─────────────────────┼─────────────────────┐
131+
│ │ │
132+
▼ ▼ ▼
133+
Static Files /api/* /logs, /collect/*
134+
(React UI) (Dashboard API) (Collector API)
135+
│ │ │
136+
│ ▼ ▼
137+
│ Port 8001 (Internal) shadowguard-collector:8000
138+
│ FastAPI Backend (Docker Network Only)
139+
│ │
140+
│ ▼
141+
└────────────────► Redis
142+
```
143+
144+
**Key Points:**
145+
- Browser → `http://localhost:3000` → Gets React UI
146+
- UI → `http://localhost:3000/api/alerts` → Nginx proxies to backend port 8001
147+
- Backend → Redis → Fetches alerts
148+
- Generator → `http://localhost:3000/logs` → Nginx proxies to collector
149+
- Collector service NOT accessible directly from host
69150

70151
## API Endpoints
71152

72-
- `GET /` - Health check
73-
- `GET /api/health` - Service health + Redis status
74-
- `GET /api/alerts` - Fetch alerts from Redis
75-
- `/collect/*` - Collector service integration
153+
All endpoints accessed via `http://localhost:3000`
154+
155+
### Dashboard Backend API
156+
- `GET /api/health` - Service health + Redis connectivity status
157+
- `GET /api/alerts` - Fetch security alerts from Redis
158+
- `GET /api/users` - Get user statistics
159+
160+
### Collector Endpoints (Proxied through Nginx)
161+
- `POST /logs` - Log ingestion endpoint (used by generator)
162+
- `GET /logs?params` - Log ingestion via GET (used by proxies)
163+
- `POST /collect/ingest` - Alternative ingestion endpoint
76164

77165
## Environment Variables
78166

79167
Set in `docker-compose.yml`:
80168
- `REDIS_HOST` - Redis hostname (default: `redis`)
81169
- `REDIS_PORT` - Redis port (default: `6379`)
170+
- `DASHBOARD_PORT` - Public port (default: `3000`)
171+
- ~~`API_GATEWAY_PORT`~~ - **REMOVED** (single gateway only)
172+
173+
## Running the Generator
174+
175+
With the new single-gateway architecture, the generator must use port 3000:
176+
177+
```bash
178+
# ✅ Correct (new single-gateway)
179+
python generator/generate_logs.py --url http://localhost:3000/logs --once --num-logs 50
180+
181+
# ❌ Wrong (old dual-gateway - no longer works)
182+
python generator/generate_logs.py --url http://localhost:8000/logs
183+
```
184+
185+
## Health Checks
186+
187+
The container includes automatic health monitoring:
188+
```bash
189+
curl -f http://localhost:3000/api/health
190+
```
191+
192+
Health check runs every 30 seconds with a 40-second startup grace period.
193+
194+
## Architectural Benefits
195+
196+
### Before (Dual Gateway - Problematic)
197+
```
198+
Port 3000: UI + API
199+
Port 8000: API + Collector ← Confusion & duplication
200+
```
201+
202+
### After (Single Gateway - Production-Ready)
203+
```
204+
Port 3000: UI + API + Collector ← Clean & predictable
205+
Port 8000: NOT exposed ← Secure & internal only
206+
```
207+
208+
**Why This Matters:**
209+
1. **Predictable behavior** - One source of truth
210+
2. **No routing confusion** - Updates work everywhere
211+
3. **CORS eliminated** - Same origin for all requests
212+
4. **Production mapping** - Maps cleanly to HTTPS/443
213+
5. **Security** - Internal services not exposed
214+
215+
## Troubleshooting
216+
217+
### Generator fails to connect
218+
**Old command (fails):**
219+
```bash
220+
python generator/generate_logs.py --url http://localhost:8000/logs
221+
# Error: Connection timeout (port not exposed)
222+
```
223+
224+
**New command (works):**
225+
```bash
226+
python generator/generate_logs.py --url http://localhost:3000/logs
227+
```
228+
229+
### Dashboard shows no alerts
230+
1. Check all services are running:
231+
```bash
232+
docker compose ps
233+
```
234+
2. Verify worker is processing events:
235+
```bash
236+
docker logs shadowguard-worker --tail 20
237+
```
238+
3. Test log ingestion:
239+
```bash
240+
curl "http://localhost:3000/logs?user_id=test&domain=example.com&url=/test&method=GET&upload_size_bytes=1000"
241+
```
242+
243+
### Port 8000 connection timeout
244+
This is **expected behavior** in the new architecture. Port 8000 is no longer exposed to the host. All traffic must go through port 3000.

0 commit comments

Comments
 (0)