Files
git.stella-ops.org/docs/30_QUOTA_ENFORCEMENT_FLOW1.md
2025-08-30 21:05:34 +00:00

94 lines
3.0 KiB
Markdown
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# QuotaEnforcement — Flow Diagram (rev2.1)
> **Scope** this document explains *how* the freetier 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 (rev2.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` | `5000ms` | Delay for *first 30* overquota scans |
| `D_hard` | `60000ms` | 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 autoexpire **24h** after first increment (00:00UTC reset).*
---
## 2·Redis key layout
| Key pattern | TTL | Description |
| ---------------------- | ---- | --------------------------------- |
| `quota:ip:<sha256>` | 24h | Anonymous quota per *hashed* IP |
| `quota:tid:<sha256>` | 24h | Token quota per *hashed* tokenID |
| `quota:ip:<sha256>:ts` | 24h | Firstseen timestamp (ISO8601) |
Keys share a common TTL for efficient mass expiry via `redis-cli --scan`.
---
## 3·Pseudocode (Gostyle)
```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 `HTTP429` 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 < 1s expected |
---
*Generated {{ "now" | date: "%Y%m%d" }} — values pulled from central constants.*