diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2025-12-03 11:19:40 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2025-12-03 11:19:40 +0000 |
| commit | 2eaff5b79fed364d5eba5eb38e4b7bf76326884d (patch) | |
| tree | deacd6294f8860096ee82ee76930204efd65e33c /docs/archive/2025-11-04-evening/architecture-diagram.md | |
| parent | 57bc8cd9c021feaf08e139e8fb62800bc476068e (diff) | |
remove docs archive
Diffstat (limited to 'docs/archive/2025-11-04-evening/architecture-diagram.md')
| -rw-r--r-- | docs/archive/2025-11-04-evening/architecture-diagram.md | 442 |
1 files changed, 0 insertions, 442 deletions
diff --git a/docs/archive/2025-11-04-evening/architecture-diagram.md b/docs/archive/2025-11-04-evening/architecture-diagram.md deleted file mode 100644 index 056e551..0000000 --- a/docs/archive/2025-11-04-evening/architecture-diagram.md +++ /dev/null | |||
| @@ -1,442 +0,0 @@ | |||
| 1 | # ngit-grasp Architecture Diagram | ||
| 2 | |||
| 3 | **Date:** November 4, 2025 | ||
| 4 | **Purpose:** Visual reference for single-port architecture | ||
| 5 | |||
| 6 | --- | ||
| 7 | |||
| 8 | ## Current Architecture (WRONG ❌) | ||
| 9 | |||
| 10 | ``` | ||
| 11 | ┌─────────────────────────────────────────┐ | ||
| 12 | │ Port 8080 │ | ||
| 13 | │ ┌───────────────────────────────────┐ │ | ||
| 14 | │ │ Nostr Relay (WebSocket) │ │ | ||
| 15 | │ │ - NIP-01 protocol │ │ | ||
| 16 | │ │ - Event storage │ │ | ||
| 17 | │ │ - Subscriptions │ │ | ||
| 18 | │ └───────────────────────────────────┘ │ | ||
| 19 | └─────────────────────────────────────────┘ | ||
| 20 | |||
| 21 | ┌─────────────────────────────────────────┐ | ||
| 22 | │ Port 8081 (WRONG!) │ | ||
| 23 | │ ┌───────────────────────────────────┐ │ | ||
| 24 | │ │ Git HTTP Server │ │ | ||
| 25 | │ │ - Not implemented │ │ | ||
| 26 | │ └───────────────────────────────────┘ │ | ||
| 27 | └─────────────────────────────────────────┘ | ||
| 28 | ``` | ||
| 29 | |||
| 30 | **Problem:** GRASP-01 requires single port! | ||
| 31 | |||
| 32 | --- | ||
| 33 | |||
| 34 | ## Target Architecture (CORRECT ✅) | ||
| 35 | |||
| 36 | ``` | ||
| 37 | ┌─────────────────────────────────────────────────────────────┐ | ||
| 38 | │ Single Port (8080) │ | ||
| 39 | │ │ | ||
| 40 | │ ┌───────────────────────────────────────────────────────┐ │ | ||
| 41 | │ │ actix-web HTTP Server │ │ | ||
| 42 | │ │ │ │ | ||
| 43 | │ │ ┌──────────────────────────────────────────────────┐ │ │ | ||
| 44 | │ │ │ CORS Middleware (ALL requests) │ │ │ | ||
| 45 | │ │ │ - Access-Control-Allow-Origin: * │ │ │ | ||
| 46 | │ │ │ - Access-Control-Allow-Methods: GET, POST │ │ │ | ||
| 47 | │ │ │ - Access-Control-Allow-Headers: Content-Type │ │ │ | ||
| 48 | │ │ └──────────────────────────────────────────────────┘ │ │ | ||
| 49 | │ │ │ │ | ||
| 50 | │ │ ┌──────────────────────────────────────────────────┐ │ │ | ||
| 51 | │ │ │ HTTP Router │ │ │ | ||
| 52 | │ │ │ │ │ │ | ||
| 53 | │ │ │ Path Pattern Matching: │ │ │ | ||
| 54 | │ │ │ - /<npub>/<identifier>.git/* → Git Handler │ │ │ | ||
| 55 | │ │ │ - /* → Nostr Handler │ │ │ | ||
| 56 | │ │ └──────────────────────────────────────────────────┘ │ │ | ||
| 57 | │ │ │ │ | ||
| 58 | │ │ ┌────────────────────┐ ┌─────────────────────────┐ │ │ | ||
| 59 | │ │ │ Git HTTP Handler │ │ Nostr Relay Handler │ │ │ | ||
| 60 | │ │ │ │ │ │ │ │ | ||
| 61 | │ │ │ ┌──────────────┐ │ │ ┌──────────────────┐ │ │ │ | ||
| 62 | │ │ │ │ git-http- │ │ │ │ WebSocket Upgrade│ │ │ │ | ||
| 63 | │ │ │ │ backend │ │ │ │ │ │ │ │ | ||
| 64 | │ │ │ │ │ │ │ │ ┌──────────────┐ │ │ │ │ | ||
| 65 | │ │ │ │ - info/refs │ │ │ │ │ NIP-01 │ │ │ │ │ | ||
| 66 | │ │ │ │ - upload-pack│ │ │ │ │ - EVENT │ │ │ │ │ | ||
| 67 | │ │ │ │ - receive-pack │ │ │ │ - REQ │ │ │ │ │ | ||
| 68 | │ │ │ │ │ │ │ │ │ - CLOSE │ │ │ │ │ | ||
| 69 | │ │ │ │ Authorization: │ │ │ └──────────────┘ │ │ │ │ | ||
| 70 | │ │ │ │ - Query state│ │ │ │ │ │ │ │ | ||
| 71 | │ │ │ │ - Validate │ │ │ │ ┌──────────────┐ │ │ │ │ | ||
| 72 | │ │ │ │ - Accept/ │ │ │ │ │ NIP-11 │ │ │ │ │ | ||
| 73 | │ │ │ │ Reject │ │ │ │ │ - GRASP fields│ │ │ │ │ | ||
| 74 | │ │ │ └──────────────┘ │ │ │ └──────────────┘ │ │ │ │ | ||
| 75 | │ │ │ │ │ │ │ │ │ │ | ||
| 76 | │ │ │ Repository: │ │ │ ┌──────────────┐ │ │ │ │ | ||
| 77 | │ │ │ {GIT_DATA_PATH}/ │ │ │ │ NIP-34 │ │ │ │ │ | ||
| 78 | │ │ │ {npub}/ │ │ │ │ - Announce │ │ │ │ │ | ||
| 79 | │ │ │ {identifier}.git │ │ │ │ - State │ │ │ │ │ | ||
| 80 | │ │ │ │ │ │ │ - Validate │ │ │ │ │ | ||
| 81 | │ │ └────────────────────┘ │ │ └──────────────┘ │ │ │ │ | ||
| 82 | │ │ │ │ │ │ │ │ | ||
| 83 | │ │ │ │ HTTP Root: │ │ │ │ | ||
| 84 | │ │ │ │ - Serve HTML │ │ │ │ | ||
| 85 | │ │ │ │ - NIP-11 JSON │ │ │ │ | ||
| 86 | │ │ │ └──────────────────┘ │ │ │ | ||
| 87 | │ │ │ │ │ │ | ||
| 88 | │ └───────────────────────────┴─────────────────────────┘ │ │ | ||
| 89 | │ │ | ||
| 90 | │ ┌───────────────────────────────────────────────────────┐ │ | ||
| 91 | │ │ Storage Layer │ │ | ||
| 92 | │ │ │ │ | ||
| 93 | │ │ ┌──────────────────────┐ ┌──────────────────────┐ │ │ | ||
| 94 | │ │ │ Git Repositories │ │ Nostr Events DB │ │ │ | ||
| 95 | │ │ │ │ │ │ │ │ | ||
| 96 | │ │ │ {GIT_DATA_PATH}/ │ │ {RELAY_DATA_PATH}/ │ │ │ | ||
| 97 | │ │ │ ├── npub1.../ │ │ - Announcements │ │ │ | ||
| 98 | │ │ │ │ ├── repo1.git/ │ │ - State events │ │ │ | ||
| 99 | │ │ │ │ └── repo2.git/ │ │ - Issues/Patches │ │ │ | ||
| 100 | │ │ │ └── npub2.../ │ │ - Other events │ │ │ | ||
| 101 | │ │ │ └── repo3.git/ │ │ │ │ │ | ||
| 102 | │ │ └──────────────────────┘ └──────────────────────┘ │ │ | ||
| 103 | │ └───────────────────────────────────────────────────────┘ │ | ||
| 104 | └─────────────────────────────────────────────────────────────┘ | ||
| 105 | ``` | ||
| 106 | |||
| 107 | --- | ||
| 108 | |||
| 109 | ## Request Flow Examples | ||
| 110 | |||
| 111 | ### Example 1: Git Clone | ||
| 112 | |||
| 113 | ``` | ||
| 114 | Client: git clone http://localhost:8080/npub1abc.../my-repo.git | ||
| 115 | ↓ | ||
| 116 | actix-web receives HTTP GET request | ||
| 117 | ↓ | ||
| 118 | CORS middleware adds headers | ||
| 119 | ↓ | ||
| 120 | Router matches path: /npub1abc.../my-repo.git | ||
| 121 | ↓ | ||
| 122 | Git Handler receives request | ||
| 123 | ↓ | ||
| 124 | git-http-backend processes: | ||
| 125 | - GET /npub1abc.../my-repo.git/info/refs?service=git-upload-pack | ||
| 126 | ↓ | ||
| 127 | Response includes: | ||
| 128 | - CORS headers | ||
| 129 | - Git protocol data | ||
| 130 | - Capabilities: allow-reachable-sha1-in-want, allow-tip-sha1-in-want | ||
| 131 | ↓ | ||
| 132 | Client receives data and clones repository | ||
| 133 | ``` | ||
| 134 | |||
| 135 | ### Example 2: Git Push | ||
| 136 | |||
| 137 | ``` | ||
| 138 | Client: git push http://localhost:8080/npub1abc.../my-repo.git main | ||
| 139 | ↓ | ||
| 140 | actix-web receives HTTP POST request | ||
| 141 | ↓ | ||
| 142 | CORS middleware adds headers | ||
| 143 | ↓ | ||
| 144 | Router matches path: /npub1abc.../my-repo.git | ||
| 145 | ↓ | ||
| 146 | Git Handler receives request | ||
| 147 | ↓ | ||
| 148 | BEFORE spawning git-receive-pack: | ||
| 149 | 1. Parse ref updates from request body | ||
| 150 | 2. Query latest state announcement from relay | ||
| 151 | 3. Validate pusher in maintainer set | ||
| 152 | 4. Validate ref updates match state | ||
| 153 | ↓ | ||
| 154 | If validation passes: | ||
| 155 | - Spawn git-receive-pack | ||
| 156 | - Stream response back to client | ||
| 157 | ↓ | ||
| 158 | If validation fails: | ||
| 159 | - Return HTTP 403 Forbidden | ||
| 160 | - Include error message | ||
| 161 | ↓ | ||
| 162 | Client receives success/failure | ||
| 163 | ``` | ||
| 164 | |||
| 165 | ### Example 3: WebSocket Connection (Nostr) | ||
| 166 | |||
| 167 | ``` | ||
| 168 | Client: new WebSocket('ws://localhost:8080/') | ||
| 169 | ↓ | ||
| 170 | actix-web receives HTTP GET with Upgrade: websocket | ||
| 171 | ↓ | ||
| 172 | CORS middleware adds headers | ||
| 173 | ↓ | ||
| 174 | Router matches path: / | ||
| 175 | ↓ | ||
| 176 | Nostr Handler receives request | ||
| 177 | ↓ | ||
| 178 | Upgrade to WebSocket | ||
| 179 | ↓ | ||
| 180 | Client sends: ["EVENT", {...}] | ||
| 181 | ↓ | ||
| 182 | Nostr Handler processes EVENT | ||
| 183 | ↓ | ||
| 184 | If kind 30617 (announcement): | ||
| 185 | - Validate clone/relays tags | ||
| 186 | - Provision Git repository | ||
| 187 | - Store event | ||
| 188 | ↓ | ||
| 189 | Response: ["OK", event_id, true, ""] | ||
| 190 | ↓ | ||
| 191 | Client receives confirmation | ||
| 192 | ``` | ||
| 193 | |||
| 194 | ### Example 4: NIP-11 Request | ||
| 195 | |||
| 196 | ``` | ||
| 197 | Client: fetch('http://localhost:8080/', { | ||
| 198 | headers: { 'Accept': 'application/nostr+json' } | ||
| 199 | }) | ||
| 200 | ↓ | ||
| 201 | actix-web receives HTTP GET with Accept header | ||
| 202 | ↓ | ||
| 203 | CORS middleware adds headers | ||
| 204 | ↓ | ||
| 205 | Router matches path: / | ||
| 206 | ↓ | ||
| 207 | Nostr Handler checks Accept header | ||
| 208 | ↓ | ||
| 209 | Returns NIP-11 JSON: | ||
| 210 | { | ||
| 211 | "name": "ngit-grasp instance", | ||
| 212 | "description": "Rust GRASP implementation", | ||
| 213 | "supported_nips": [1, 11, 34], | ||
| 214 | "supported_grasps": ["GRASP-01"], | ||
| 215 | "repo_acceptance_criteria": "Must list this service in clone and relays tags", | ||
| 216 | "curation": "Basic spam prevention" | ||
| 217 | } | ||
| 218 | ↓ | ||
| 219 | Client receives relay information | ||
| 220 | ``` | ||
| 221 | |||
| 222 | ### Example 5: CORS Preflight (OPTIONS) | ||
| 223 | |||
| 224 | ``` | ||
| 225 | Browser: OPTIONS http://localhost:8080/ | ||
| 226 | Headers: | ||
| 227 | - Origin: https://example.com | ||
| 228 | - Access-Control-Request-Method: POST | ||
| 229 | ↓ | ||
| 230 | actix-web receives OPTIONS request | ||
| 231 | ↓ | ||
| 232 | CORS middleware handles preflight | ||
| 233 | ↓ | ||
| 234 | Returns 204 No Content with headers: | ||
| 235 | - Access-Control-Allow-Origin: * | ||
| 236 | - Access-Control-Allow-Methods: GET, POST | ||
| 237 | - Access-Control-Allow-Headers: Content-Type | ||
| 238 | - Access-Control-Max-Age: 3600 | ||
| 239 | ↓ | ||
| 240 | Browser caches preflight response | ||
| 241 | ↓ | ||
| 242 | Browser proceeds with actual request | ||
| 243 | ``` | ||
| 244 | |||
| 245 | --- | ||
| 246 | |||
| 247 | ## Component Responsibilities | ||
| 248 | |||
| 249 | ### actix-web HTTP Server | ||
| 250 | - Listen on single port | ||
| 251 | - Route requests by path | ||
| 252 | - Handle WebSocket upgrades | ||
| 253 | - Apply CORS to all requests | ||
| 254 | |||
| 255 | ### CORS Middleware | ||
| 256 | - Add headers to ALL responses | ||
| 257 | - Handle OPTIONS preflight | ||
| 258 | - Allow any origin (GRASP-01 requirement) | ||
| 259 | |||
| 260 | ### HTTP Router | ||
| 261 | - Match `/npub.../repo.git` → Git Handler | ||
| 262 | - Match `/` → Nostr Handler | ||
| 263 | - Pass through to appropriate handler | ||
| 264 | |||
| 265 | ### Git Handler | ||
| 266 | - Serve Git Smart HTTP protocol | ||
| 267 | - Read from `{GIT_DATA_PATH}/{npub}/{id}.git` | ||
| 268 | - Validate pushes before accepting | ||
| 269 | - Return 404 for missing repos | ||
| 270 | |||
| 271 | ### Nostr Handler | ||
| 272 | - Upgrade HTTP to WebSocket | ||
| 273 | - Process NIP-01 messages | ||
| 274 | - Store/query events | ||
| 275 | - Serve NIP-11 for HTTP requests | ||
| 276 | - Provision repos from announcements | ||
| 277 | |||
| 278 | ### Storage Layer | ||
| 279 | - Git repositories (bare) | ||
| 280 | - Nostr events (database) | ||
| 281 | - Separate paths for each | ||
| 282 | |||
| 283 | --- | ||
| 284 | |||
| 285 | ## Configuration Flow | ||
| 286 | |||
| 287 | ``` | ||
| 288 | Environment Variables | ||
| 289 | ↓ | ||
| 290 | .env file (optional) | ||
| 291 | ↓ | ||
| 292 | Config::from_env() | ||
| 293 | ↓ | ||
| 294 | Config struct: | ||
| 295 | - bind_address: "127.0.0.1:8080" | ||
| 296 | - domain: "example.com" | ||
| 297 | - git_data_path: "./data/repos" | ||
| 298 | - relay_data_path: "./data/relay" | ||
| 299 | - relay_name: "..." | ||
| 300 | - relay_description: "..." | ||
| 301 | - owner_npub: "..." | ||
| 302 | ↓ | ||
| 303 | Passed to: | ||
| 304 | - HTTP server (bind address) | ||
| 305 | - Git handler (git_data_path, domain) | ||
| 306 | - Nostr handler (relay_data_path, domain, NIP-11 info) | ||
| 307 | - Storage layer (both paths) | ||
| 308 | ``` | ||
| 309 | |||
| 310 | --- | ||
| 311 | |||
| 312 | ## Test Architecture | ||
| 313 | |||
| 314 | ``` | ||
| 315 | Integration Test | ||
| 316 | ↓ | ||
| 317 | TestRelay::start() | ||
| 318 | ↓ | ||
| 319 | Spawns ngit-grasp process: | ||
| 320 | - NGIT_BIND_ADDRESS=127.0.0.1:{random_port} | ||
| 321 | - NGIT_DOMAIN=127.0.0.1:{random_port} | ||
| 322 | - NGIT_GIT_DATA_PATH=./test-data/repos | ||
| 323 | - NGIT_RELAY_DATA_PATH=./test-data/relay | ||
| 324 | ↓ | ||
| 325 | Process starts: | ||
| 326 | - actix-web listens on random port | ||
| 327 | - Both Git and Nostr available | ||
| 328 | ↓ | ||
| 329 | Test runs: | ||
| 330 | - Uses grasp-audit library | ||
| 331 | - Connects to ws://127.0.0.1:{port}/ | ||
| 332 | - Runs compliance tests | ||
| 333 | ↓ | ||
| 334 | TestRelay::stop() | ||
| 335 | ↓ | ||
| 336 | Process killed | ||
| 337 | ↓ | ||
| 338 | Test data cleaned up | ||
| 339 | ``` | ||
| 340 | |||
| 341 | --- | ||
| 342 | |||
| 343 | ## File Structure | ||
| 344 | |||
| 345 | ``` | ||
| 346 | ngit-grasp/ | ||
| 347 | ├── src/ | ||
| 348 | │ ├── main.rs # Entry point | ||
| 349 | │ ├── config.rs # Configuration | ||
| 350 | │ ├── http/ # NEW - HTTP server | ||
| 351 | │ │ ├── mod.rs # Server setup | ||
| 352 | │ │ ├── git.rs # Git HTTP handler | ||
| 353 | │ │ └── nostr.rs # Nostr WebSocket handler | ||
| 354 | │ ├── nostr/ | ||
| 355 | │ │ ├── mod.rs | ||
| 356 | │ │ ├── relay.rs # Relay logic (reused) | ||
| 357 | │ │ └── events.rs # Event handling | ||
| 358 | │ └── storage/ | ||
| 359 | │ ├── mod.rs | ||
| 360 | │ └── repository.rs # Git repo management | ||
| 361 | ├── tests/ | ||
| 362 | │ ├── common/ | ||
| 363 | │ │ ├── mod.rs | ||
| 364 | │ │ └── relay.rs # TestRelay fixture | ||
| 365 | │ ├── nip01_compliance.rs # NIP-01 tests | ||
| 366 | │ ├── nip34_announcements.rs # NIP-34 tests | ||
| 367 | │ └── grasp01_git_http.rs # NEW - GRASP-01 Git tests | ||
| 368 | ├── data/ # Runtime data (gitignored) | ||
| 369 | │ ├── repos/ # Git repositories | ||
| 370 | │ └── relay/ # Nostr events | ||
| 371 | └── test-data/ # Test data (gitignored) | ||
| 372 | ├── repos/ | ||
| 373 | └── relay/ | ||
| 374 | ``` | ||
| 375 | |||
| 376 | --- | ||
| 377 | |||
| 378 | ## Comparison: ngit-relay vs ngit-grasp | ||
| 379 | |||
| 380 | ### ngit-relay (Go + nginx) | ||
| 381 | |||
| 382 | ``` | ||
| 383 | nginx (Port 8081) | ||
| 384 | ├── Git HTTP → fcgiwrap → git-http-backend | ||
| 385 | │ ↓ | ||
| 386 | │ pre-receive hook (Go) | ||
| 387 | │ ↓ | ||
| 388 | │ Khatru relay (HTTP API) | ||
| 389 | │ | ||
| 390 | └── Nostr → proxy → Khatru relay (Port 3334) | ||
| 391 | ↓ | ||
| 392 | on_event hook (Go) | ||
| 393 | ↓ | ||
| 394 | provision repos | ||
| 395 | ``` | ||
| 396 | |||
| 397 | **Components:** | ||
| 398 | - nginx (routing) | ||
| 399 | - fcgiwrap (CGI wrapper) | ||
| 400 | - git-http-backend (Git protocol) | ||
| 401 | - pre-receive hook (Go, validates pushes) | ||
| 402 | - post-receive hook (Go, updates HEAD) | ||
| 403 | - Khatru relay (Go, Nostr protocol) | ||
| 404 | - on_event hook (Go, provisions repos) | ||
| 405 | - supervisord (process management) | ||
| 406 | |||
| 407 | ### ngit-grasp (Rust) | ||
| 408 | |||
| 409 | ``` | ||
| 410 | actix-web (Port 8080) | ||
| 411 | ├── Git HTTP → git-http-backend crate | ||
| 412 | │ ↓ | ||
| 413 | │ inline authorization | ||
| 414 | │ ↓ | ||
| 415 | │ Storage (query state) | ||
| 416 | │ | ||
| 417 | └── Nostr → WebSocket upgrade | ||
| 418 | ↓ | ||
| 419 | nostr-sdk relay | ||
| 420 | ↓ | ||
| 421 | on_event (provision repos) | ||
| 422 | ↓ | ||
| 423 | Storage (store events) | ||
| 424 | ``` | ||
| 425 | |||
| 426 | **Components:** | ||
| 427 | - actix-web (routing + HTTP + WebSocket) | ||
| 428 | - git-http-backend crate (Git protocol) | ||
| 429 | - nostr-sdk (Nostr protocol) | ||
| 430 | - Storage (unified storage layer) | ||
| 431 | |||
| 432 | **Advantages:** | ||
| 433 | - Single binary | ||
| 434 | - No external processes | ||
| 435 | - Inline authorization (better errors) | ||
| 436 | - Pure Rust (memory safety) | ||
| 437 | - Easier testing | ||
| 438 | |||
| 439 | --- | ||
| 440 | |||
| 441 | **Last Updated:** November 4, 2025 | ||
| 442 | **Purpose:** Reference for implementation | ||