@@ -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 .
5689docker-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
79167Set 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