Skip to content

Commit 137f9b8

Browse files
committed
phase 8
1 parent b0d68b7 commit 137f9b8

9 files changed

Lines changed: 769 additions & 12 deletions

File tree

docs/014-nginx-plan.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Phase 7 — Nginx Plan
2+
3+
## Part 1: What we are doing
4+
5+
We are adding Nginx as a reverse proxy and static file server in front of our application.
6+
7+
### Files being created
8+
9+
| File | Purpose |
10+
|---|---|
11+
| `vault/nginx/nginx.conf` | Nginx configuration — routing rules |
12+
| `vault/nginx/Dockerfile` | Multi-stage build — builds React app, copies into Nginx image |
13+
| `vault/docker-compose.yml` | Updated — adds nginx service |
14+
15+
### What changes
16+
17+
| Before Phase 7 | After Phase 7 |
18+
|---|---|
19+
| Browser hits FastAPI directly on port 8000 | Browser hits Nginx on port 80 |
20+
| Frontend runs on Vite dev server (localhost:5173) | Frontend served by Nginx from built static files |
21+
| Two origins (8000 + 5173) → CORS needed | Single origin (port 80) → CORS no longer needed |
22+
| No SSL termination point | Nginx is the SSL termination point (Phase 7+) |
23+
24+
### What is NOT in scope
25+
26+
- SSL/HTTPS certificate (added when deploying to cloud)
27+
- Kong API gateway (Phase 8)
28+
- Load balancing across multiple backend instances
29+
30+
---
31+
32+
## Part 2: Concepts
33+
34+
### What we are building
35+
36+
```
37+
Browser → Nginx :80
38+
├── GET / → serve React dist/index.html
39+
├── GET /assets/* → serve React dist/assets/ (JS, CSS)
40+
└── ANY /api/* → proxy_pass to api container :8000
41+
```
42+
43+
### Multi-stage Dockerfile
44+
45+
The Nginx Dockerfile has two stages:
46+
47+
Stage 1 — Builder (Node.js):
48+
- Copy frontend source code
49+
- Run npm install + npm run build
50+
- Output: dist/ folder with compiled React app
51+
52+
Stage 2 — Final image (Nginx):
53+
- Start from nginx:alpine
54+
- Copy dist/ from Stage 1
55+
- Copy nginx.conf
56+
- Node.js is completely discarded — not in the final image
57+
58+
### nginx.conf structure
59+
60+
```
61+
worker_processes ← how many CPU cores to use
62+
events {} ← connection handling settings
63+
http {
64+
server {
65+
listen 80 ← port to listen on
66+
location / {} ← serve static React files
67+
location /api/ {} ← proxy to FastAPI
68+
}
69+
}
70+
```

docs/015-kong-plan.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Phase 8 — Kong API Gateway Plan
2+
3+
## Part 1: What we are doing
4+
5+
We are inserting Kong API Gateway between Nginx and FastAPI. Kong will run in **DB-less mode** — its configuration lives in a single `kong.yml` file committed to git. No separate database for Kong.
6+
7+
### Files being created / modified
8+
9+
| File | Purpose |
10+
|---|---|
11+
| `vault/kong/kong.yml` | Kong declarative config — Services, Routes, Plugins |
12+
| `vault/docker-compose.yml` | Updated — adds kong service |
13+
| `vault/nginx/nginx.conf` | Updated — `/api/*` now routes to Kong, not directly to FastAPI |
14+
15+
### What changes
16+
17+
| Before Phase 8 | After Phase 8 |
18+
|---|---|
19+
| Nginx → FastAPI directly | Nginx → Kong → FastAPI |
20+
| Rate limiting not implemented at gateway | Rate limiting Kong plugin (100 req/min per IP) |
21+
| CORS handled in FastAPI middleware | CORS handled by Kong plugin |
22+
| No central request logging at gateway | Kong logs all API requests |
23+
24+
### What is NOT in scope
25+
26+
- Kong DB mode (not needed — DB-less is sufficient for our use case)
27+
- Kong Consumers (Phase 9 — when Keycloak gives each request an identity)
28+
- JWT verification via Kong (still handled by FastAPI — Phase 9)
29+
- Multiple upstream services
30+
31+
---
32+
33+
## Part 2: Architecture
34+
35+
Before:
36+
```
37+
Browser → Nginx :80
38+
├── / → React static files
39+
└── /api/* → FastAPI :8000
40+
```
41+
42+
After:
43+
```
44+
Browser → Nginx :80
45+
├── / → React static files
46+
└── /api/* → Kong proxy :8000 (internal)
47+
└── FastAPI :8000 (internal)
48+
```
49+
50+
**Port layout (no conflicts — each container has its own port namespace):**
51+
52+
| Container | Port | Who talks to it |
53+
|---|---|---|
54+
| `api` (FastAPI) | 8000 internal | Kong only |
55+
| `kong` proxy | 8000 internal | Nginx only |
56+
| `kong` Admin API | 8001 internal, read-only in DB-less | Query only |
57+
| `nginx` | 80 → host:80 | Browser |
58+
59+
FastAPI stays on port 8000. Kong also uses 8000 internally — no conflict because they are different containers (`api:8000` vs `kong:8000`).
60+
61+
---
62+
63+
## Part 3: kong.yml structure
64+
65+
```yaml
66+
_format_version: "3.0"
67+
68+
services:
69+
- name: vault-api
70+
url: http://api:8000
71+
routes:
72+
- name: vault-api-route
73+
paths:
74+
- /
75+
strip_path: false
76+
77+
plugins:
78+
- name: rate-limiting
79+
config:
80+
minute: 100
81+
policy: local
82+
83+
- name: cors
84+
config:
85+
origins:
86+
- http://localhost
87+
methods:
88+
- GET
89+
- POST
90+
- PUT
91+
- DELETE
92+
- OPTIONS
93+
headers:
94+
- Authorization
95+
- Content-Type
96+
credentials: true
97+
```
98+
99+
---
100+
101+
## Part 4: Steps
102+
103+
1. Create `vault/kong/kong.yml` — declarative config
104+
2. Update `vault/docker-compose.yml` — add kong service
105+
3. Update `vault/nginx/nginx.conf` — change `/api/` proxy_pass to Kong
106+
4. Test: `docker compose up --build`
107+
108+
---
109+
110+
## Part 5: Concepts to cover
111+
112+
- DB-less mode: config from kong.yml, version-controlled, no extra database
113+
- Kong's two ports: proxy (8000) and Admin API (8001 — read-only in DB-less)
114+
- Service vs Route: service = where to send it, route = what URL pattern triggers it
115+
- Plugins as a pipeline — every request through the matched route runs all attached plugins
116+
- Consumer role (teach it, implement in Phase 9)

docs/KT-devtools.md

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
# KT — Browser DevTools
2+
3+
---
4+
5+
## What is DevTools?
6+
7+
DevTools is a set of built-in developer tools in every modern browser (Chrome, Firefox, Edge). It lets you inspect everything that is happening inside the browser — the HTML structure, JavaScript errors, network requests, cookies, storage, and performance.
8+
9+
Open it with: `F12` or `Right click → Inspect`
10+
11+
---
12+
13+
## The Tabs — What Each One Is For
14+
15+
| Tab | What it shows | When you use it |
16+
|---|---|---|
17+
| **Elements** | The live HTML/CSS of the page | Debugging layout, styles, DOM structure |
18+
| **Console** | JS errors, logs, run JS manually | Debugging JS, seeing `console.log()` output |
19+
| **Sources** | Your actual JS/CSS source files | Setting breakpoints, debugging JS step by step |
20+
| **Network** | Every HTTP request the browser makes | Debugging API calls, checking payloads, headers |
21+
| **Performance** | Page load and rendering timeline | Diagnosing slow pages |
22+
| **Memory** | JavaScript heap memory usage | Debugging memory leaks |
23+
| **Application** | Cookies, localStorage, sessionStorage | Inspecting stored data, clearing sessions |
24+
| **Security** | SSL certificate details | Checking HTTPS is valid |
25+
26+
As a backend/full-stack developer, you will live in **Network** and **Console** 90% of the time. **Application** is useful for auth debugging (checking JWT tokens in storage).
27+
28+
---
29+
30+
## Network Tab — Deep Dive
31+
32+
### The request list (left side)
33+
34+
When you open the Network tab and use your app, every HTTP request appears as a row. The columns:
35+
36+
| Column | What it means |
37+
|---|---|
38+
| **Name** | Last segment of the URL path (explained below) |
39+
| **Status** | HTTP response code — 200, 401, 404, 500 |
40+
| **Type** | What kind of resource — fetch, xhr, document, script, img |
41+
| **Initiator** | What triggered this request |
42+
| **Size** | Response size (bytes) |
43+
| **Time** | Total time from request sent to response received |
44+
| **Waterfall** | Visual bar showing when this request happened relative to others |
45+
46+
### Where the "Name" comes from
47+
48+
The Name column shows the **last segment of the URL path**. It comes directly from the URL — you do not set it anywhere.
49+
50+
```
51+
URL: http://localhost/api/auth/login → Name: login
52+
URL: http://localhost/api/notes/ → Name: notes
53+
URL: http://localhost/ → Name: localhost
54+
URL: http://localhost/assets/index.js → Name: index.js
55+
```
56+
57+
If the name looks cryptic (like `index-Bx3kP9.js`), that is a hashed filename — the build tool (Vite/Webpack) adds a hash to the filename for cache busting. It is still just the last part of the URL.
58+
59+
### Filters
60+
61+
At the top of the Network tab you can filter by type:
62+
- **All** — everything
63+
- **Fetch/XHR** — only API calls (what you care about most)
64+
- **Doc** — HTML documents
65+
- **JS** — JavaScript files
66+
- **CSS** — stylesheets
67+
- **Img** — images
68+
- **Font** — fonts
69+
- **WS** — WebSocket connections
70+
71+
For API debugging, always switch to **Fetch/XHR** so you only see your API calls.
72+
73+
---
74+
75+
## When You Click a Request — The Sub-tabs
76+
77+
### Headers
78+
79+
Shows two things:
80+
81+
**Request Headers** — what the browser sent to the server:
82+
```
83+
Authorization: Bearer eyJhbGc... ← JWT token
84+
Content-Type: application/json ← telling server the body is JSON
85+
Host: localhost
86+
```
87+
88+
**Response Headers** — what the server sent back:
89+
```
90+
X-Kong-Upstream-Latency: 4 ← time Kong spent waiting for FastAPI
91+
X-Kong-Proxy-Latency: 1 ← time Kong itself spent processing
92+
Content-Type: application/json
93+
```
94+
95+
### Payload
96+
97+
Shows the **request body** — what the browser sent to the server. Only present for POST, PUT, PATCH requests.
98+
99+
```json
100+
{
101+
"username": "alice",
102+
"password": "secret123"
103+
}
104+
```
105+
106+
This is where you see the raw password during login (before TLS encrypts it on the wire).
107+
108+
### Preview
109+
110+
The **response body formatted** — JSON is shown as a collapsible tree. Easier to read than raw text.
111+
112+
### Response
113+
114+
The **raw response body** as text. Useful when Preview fails to format it correctly.
115+
116+
### Initiator
117+
118+
Shows **what triggered this request** — the call stack inside your JavaScript that led to this HTTP request being made.
119+
120+
Example:
121+
```
122+
app.js:47 fetch('/api/auth/login', ...)
123+
app.js:112 handleLoginSubmit()
124+
(anonymous) onClick event
125+
```
126+
127+
This tells you: the login button's onClick handler called `handleLoginSubmit()` on line 112, which called `fetch()` on line 47. Useful for tracing where a request comes from when you have a large codebase.
128+
129+
### Timing
130+
131+
Shows a **breakdown of time** spent on each phase of the request:
132+
133+
| Phase | What it means |
134+
|---|---|
135+
| **Queueing** | Browser queued the request (waiting for a connection slot) |
136+
| **Stalled** | Request was ready but waiting to be sent |
137+
| **DNS Lookup** | Time to resolve the domain name to an IP |
138+
| **Initial connection** | TCP handshake — establishing the connection |
139+
| **SSL** | TLS handshake — encrypting the connection (HTTPS only) |
140+
| **Request sent** | Time to send the request bytes to the server |
141+
| **Waiting (TTFB)** | **Time To First Byte** — server is processing, you are waiting |
142+
| **Content Download** | Time to download the response body |
143+
144+
**TTFB is the most important one.** If TTFB is high (hundreds of ms), your server is slow — database query is slow, or the server is under load. If Content Download is high, the response payload is large.
145+
146+
---
147+
148+
## Console Tab
149+
150+
Shows:
151+
- `console.log()` output from your JavaScript
152+
- JavaScript errors (in red) with file and line number
153+
- Network errors ("Failed to fetch", CORS errors)
154+
- Warnings (in yellow)
155+
156+
You can also type JavaScript directly into the console and run it — useful for quick debugging.
157+
158+
CORS errors always appear here first:
159+
```
160+
Access to fetch at 'http://localhost/api/login' from origin 'http://localhost'
161+
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header
162+
```
163+
164+
---
165+
166+
## Application Tab
167+
168+
### localStorage
169+
170+
Key-value storage in the browser that persists across page refreshes. Your frontend stores the JWT token here after login.
171+
172+
```
173+
Key: token
174+
Value: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
175+
```
176+
177+
You can expand the token at jwt.io to read its contents. This is useful when debugging auth issues.
178+
179+
### sessionStorage
180+
181+
Same as localStorage but cleared when the browser tab is closed.
182+
183+
### Cookies
184+
185+
HTTP cookies set by the server. If your app used cookie-based sessions instead of JWT, you would see the session token here.
186+
187+
---
188+
189+
## Practical Debugging Workflow
190+
191+
**API call not working?**
192+
1. Open Network tab → filter by Fetch/XHR
193+
2. Find the failing request → check Status code
194+
3. Click it → check Payload (did the browser send the right data?)
195+
4. Check Response (what did the server return? Is there an error message?)
196+
5. Check Headers (is the Authorization header present?)
197+
198+
**CORS error?**
199+
1. Open Console → read the full error message
200+
2. Open Network tab → find the OPTIONS preflight request
201+
3. Check Response Headers — is `Access-Control-Allow-Origin` present?
202+
203+
**Slow API call?**
204+
1. Click the request → Timing tab
205+
2. Check TTFB — if high, server is slow
206+
3. Check Content Download — if high, response is too large
207+
208+
**JWT token missing or expired?**
209+
1. Application tab → localStorage
210+
2. Find the token key — is it there?
211+
3. Copy the value → paste at jwt.io → check expiry

0 commit comments

Comments
 (0)