Initial commit (history squashed)
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Build Test Deploy / authority-container (push) Has been cancelled
				
			
		
			
				
	
				Build Test Deploy / docs (push) Has been cancelled
				
			
		
			
				
	
				Build Test Deploy / deploy (push) Has been cancelled
				
			
		
			
				
	
				Build Test Deploy / build-test (push) Has been cancelled
				
			
		
			
				
	
				Docs CI / lint-and-preview (push) Has been cancelled
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Build Test Deploy / authority-container (push) Has been cancelled
				
			Build Test Deploy / docs (push) Has been cancelled
				
			Build Test Deploy / deploy (push) Has been cancelled
				
			Build Test Deploy / build-test (push) Has been cancelled
				
			Docs CI / lint-and-preview (push) Has been cancelled
				
			This commit is contained in:
		
							
								
								
									
										93
									
								
								docs/30_QUOTA_ENFORCEMENT_FLOW1.md
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										93
									
								
								docs/30_QUOTA_ENFORCEMENT_FLOW1.md
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,93 @@ | ||||
| # Quota Enforcement — Flow Diagram (rev 2.1) | ||||
|  | ||||
| > **Scope** – this document explains *how* the free‑tier limits are enforced   | ||||
| > inside the scanner service.  For policy rationale and legal aspects see   | ||||
| > [`33_333_QUOTA_OVERVIEW.md`](33_333_QUOTA_OVERVIEW.md). | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 0 · Key parameters (rev 2.1) | ||||
|  | ||||
| | Symbol | Value | Meaning | | ||||
| |--------|-------|---------| | ||||
| | `L_anon` | **{{ quota_anon }}** | Daily ceiling for anonymous users | | ||||
| | `L_jwt`  | **{{ quota_token }}** | Daily ceiling for token holders | | ||||
| | `T_warn` | `200` | Soft reminder threshold | | ||||
| | `D_soft` | `5 000 ms` | Delay for *first 30* over‑quota scans | | ||||
| | `D_hard` | `60 000 ms` | Delay for all scans beyond the soft window | | ||||
|  | ||||
| `L_active` is `L_jwt` if a valid token is present; else `L_anon`. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 1 · Sequence diagram | ||||
|  | ||||
| ```mermaid | ||||
| sequenceDiagram | ||||
|     participant C as Client | ||||
|     participant API as Scanner API | ||||
|     participant REDIS as Redis (quota) | ||||
|     C->>API: /scan | ||||
|     API->>REDIS: INCR quota:<key> | ||||
|     REDIS-->>API: new_count | ||||
|     alt new_count ≤ L_active | ||||
|         API-->>C: 202 Accepted (no delay) | ||||
|     else new_count ≤ L_active + 30 | ||||
|         API->>C: wait D_soft | ||||
|         API-->>C: 202 Accepted | ||||
|     else | ||||
|         API->>C: wait D_hard | ||||
|         API-->>C: 202 Accepted | ||||
|     end | ||||
| ```` | ||||
|  | ||||
| *Counters auto‑expire **24 h** after first increment (00:00 UTC reset).* | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 2 · Redis key layout | ||||
|  | ||||
| | Key pattern            | TTL  | Description                       | | ||||
| | ---------------------- | ---- | --------------------------------- | | ||||
| | `quota:ip:<sha256>`    | 24 h | Anonymous quota per *hashed* IP   | | ||||
| | `quota:tid:<sha256>`   | 24 h | Token quota per *hashed* token‑ID | | ||||
| | `quota:ip:<sha256>:ts` | 24 h | First‑seen timestamp (ISO 8601)   | | ||||
|  | ||||
| Keys share a common TTL for efficient mass expiry via `redis-cli --scan`. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 3 · Pseudocode (Go‑style) | ||||
|  | ||||
| ```go | ||||
| func gate(key string, limit int) (delay time.Duration) { | ||||
|     cnt, _ := rdb.Incr(ctx, key).Result() | ||||
|  | ||||
|     switch { | ||||
|     case cnt <= limit: | ||||
|         return 0             // under quota | ||||
|     case cnt <= limit+30: | ||||
|         return 5 * time.Second | ||||
|     default: | ||||
|         return 60 * time.Second | ||||
|     } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| *The middleware applies `time.Sleep(delay)` **before** processing the scan | ||||
| request; it never returns `HTTP 429` under the free tier.* | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 4 · Metrics & monitoring | ||||
|  | ||||
| | Metric                         | PromQL sample                              | Alert                 | | ||||
| | ------------------------------ | ------------------------------------------ | --------------------- | | ||||
| | `stella_quota_soft_hits_total` | `increase(...[5m]) > 50`                   | Many users near limit | | ||||
| | `stella_quota_hard_hits_total` | `rate(...[1h]) > 0.1`                      | Potential abuse       | | ||||
| | Average delay per request      | `histogram_quantile(0.95, sum(rate(...)))` | P95 < 1 s expected    | | ||||
|  | ||||
| --- | ||||
|  | ||||
|  | ||||
| *Generated {{ "now" | date: "%Y‑%m‑%d" }} — values pulled from central constants.* | ||||
		Reference in New Issue
	
	Block a user