first commit
Made-with: Cursor
This commit is contained in:
359
context/backend_overview.md
Normal file
359
context/backend_overview.md
Normal file
@@ -0,0 +1,359 @@
|
||||
# backend_overview.md
|
||||
|
||||
## 1. Purpose
|
||||
|
||||
This document defines the complete backend architecture and behavior for the Sats Faucet application.
|
||||
|
||||
The backend is responsible for:
|
||||
|
||||
* Verifying NIP-98 signed authentication.
|
||||
* Enforcing all eligibility rules.
|
||||
* Fetching and caching Nostr account data.
|
||||
* Enforcing cooldowns and anti-abuse constraints.
|
||||
* Generating and locking entropy payout quotes.
|
||||
* Executing Lightning payouts via LNbits.
|
||||
* Maintaining transparency statistics.
|
||||
* Providing operational safety controls.
|
||||
|
||||
This backend must be production-safe, abuse-resistant, and configurable entirely via environment variables.
|
||||
|
||||
---
|
||||
|
||||
## 2. Tech Stack Requirements
|
||||
|
||||
Recommended stack:
|
||||
|
||||
* Language: Go, TypeScript (Node/Express), or Python (FastAPI)
|
||||
* Database: PostgreSQL
|
||||
* Optional: Redis (rate limiting + nonce replay protection)
|
||||
* LNbits for Lightning payments
|
||||
* Reverse proxy with TLS (nginx or Caddy)
|
||||
|
||||
The backend must be stateless except for database persistence.
|
||||
|
||||
---
|
||||
|
||||
## 3. Environment Variables
|
||||
|
||||
All logic must be driven via .env configuration.
|
||||
|
||||
Key categories:
|
||||
|
||||
### 3.1 Security
|
||||
|
||||
* JWT_SECRET
|
||||
* HMAC_IP_SECRET
|
||||
* NIP98_MAX_SKEW_SECONDS
|
||||
* NONCE_TTL_SECONDS
|
||||
* TRUST_PROXY
|
||||
* ALLOWED_ORIGINS
|
||||
|
||||
### 3.2 Faucet Economics
|
||||
|
||||
* FAUCET_ENABLED
|
||||
* EMERGENCY_STOP
|
||||
* FAUCET_MIN_SATS
|
||||
* FAUCET_MAX_SATS
|
||||
* PAYOUT_WEIGHT_SMALL
|
||||
* PAYOUT_WEIGHT_MEDIUM
|
||||
* PAYOUT_WEIGHT_LARGE
|
||||
* PAYOUT_WEIGHT_JACKPOT
|
||||
* PAYOUT_SMALL_SATS
|
||||
* PAYOUT_MEDIUM_SATS
|
||||
* PAYOUT_LARGE_SATS
|
||||
* PAYOUT_JACKPOT_SATS
|
||||
* DAILY_BUDGET_SATS
|
||||
* MAX_CLAIMS_PER_DAY
|
||||
* MIN_WALLET_BALANCE_SATS
|
||||
|
||||
### 3.3 Eligibility
|
||||
|
||||
* MIN_ACCOUNT_AGE_DAYS
|
||||
* MIN_ACTIVITY_SCORE
|
||||
* MIN_NOTES_COUNT
|
||||
* MIN_FOLLOWING_COUNT
|
||||
* MIN_FOLLOWERS_COUNT
|
||||
* ACTIVITY_LOOKBACK_DAYS
|
||||
|
||||
### 3.4 Cooldowns
|
||||
|
||||
* COOLDOWN_DAYS
|
||||
* IP_COOLDOWN_DAYS
|
||||
* MAX_CLAIMS_PER_IP_PER_PERIOD
|
||||
|
||||
### 3.5 Nostr
|
||||
|
||||
* NOSTR_RELAYS
|
||||
* RELAY_TIMEOUT_MS
|
||||
* MAX_EVENTS_FETCH
|
||||
* METADATA_CACHE_HOURS
|
||||
|
||||
### 3.6 LNbits
|
||||
|
||||
* LNBITS_BASE_URL
|
||||
* LNBITS_ADMIN_KEY
|
||||
* LNBITS_WALLET_ID
|
||||
* DEPOSIT_LIGHTNING_ADDRESS
|
||||
* DEPOSIT_LNURLP
|
||||
|
||||
---
|
||||
|
||||
## 4. Database Schema
|
||||
|
||||
### 4.1 users
|
||||
|
||||
* pubkey (PK)
|
||||
* nostr_first_seen_at
|
||||
* notes_count
|
||||
* followers_count
|
||||
* following_count
|
||||
* activity_score
|
||||
* last_metadata_fetch_at
|
||||
* created_at
|
||||
* updated_at
|
||||
|
||||
### 4.2 claims
|
||||
|
||||
* id (PK)
|
||||
* pubkey (FK users.pubkey)
|
||||
* claimed_at
|
||||
* payout_sats
|
||||
* ip_hash
|
||||
* payout_destination_hash
|
||||
* status (pending, paid, failed)
|
||||
* lnbits_payment_hash
|
||||
* error_message
|
||||
|
||||
### 4.3 ip_limits
|
||||
|
||||
* ip_hash (PK)
|
||||
* last_claimed_at
|
||||
* claim_count_period
|
||||
|
||||
### 4.4 quotes
|
||||
|
||||
* quote_id (PK)
|
||||
* pubkey
|
||||
* payout_sats
|
||||
* created_at
|
||||
* expires_at
|
||||
* status (active, consumed, expired)
|
||||
|
||||
### 4.5 daily_stats (optional)
|
||||
|
||||
* date (PK)
|
||||
* total_paid_sats
|
||||
* total_claims
|
||||
* unique_pubkeys
|
||||
|
||||
All IP addresses must be stored as HMAC(IP, HMAC_IP_SECRET).
|
||||
|
||||
---
|
||||
|
||||
## 5. NIP-98 Authentication
|
||||
|
||||
Every protected endpoint must:
|
||||
|
||||
1. Extract NIP-98 header or payload.
|
||||
2. Verify signature against pubkey.
|
||||
3. Verify HTTP method and URL match signed payload.
|
||||
4. Verify timestamp within allowed skew.
|
||||
5. Verify nonce not previously used.
|
||||
6. Reject if invalid.
|
||||
|
||||
Nonces must be stored in Redis or DB for NONCE_TTL_SECONDS.
|
||||
|
||||
---
|
||||
|
||||
## 6. IP Resolution
|
||||
|
||||
If TRUST_PROXY=true:
|
||||
|
||||
* Read first valid IP from X-Forwarded-For.
|
||||
Else:
|
||||
* Use request remote address.
|
||||
|
||||
Then:
|
||||
|
||||
* Hash IP using HMAC_IP_SECRET.
|
||||
* Never store raw IP.
|
||||
|
||||
---
|
||||
|
||||
## 7. Eligibility Engine
|
||||
|
||||
Eligibility flow:
|
||||
|
||||
1. Check FAUCET_ENABLED.
|
||||
2. Check EMERGENCY_STOP.
|
||||
3. Check LNbits wallet balance >= MIN_WALLET_BALANCE_SATS.
|
||||
4. Check pubkey cooldown.
|
||||
5. Check IP cooldown.
|
||||
6. Fetch or load cached Nostr profile.
|
||||
7. Compute account age.
|
||||
8. Compute activity score.
|
||||
9. Compare with thresholds.
|
||||
|
||||
Return structured result with denial code if failed.
|
||||
|
||||
---
|
||||
|
||||
## 8. Nostr Data Fetching
|
||||
|
||||
For a given pubkey:
|
||||
|
||||
1. Query relays in parallel.
|
||||
2. Fetch:
|
||||
|
||||
* kind 0 (metadata)
|
||||
* kind 1 (notes)
|
||||
* kind 3 (contacts)
|
||||
3. Compute:
|
||||
|
||||
* earliest created_at
|
||||
* notes count in ACTIVITY_LOOKBACK_DAYS
|
||||
* following count
|
||||
|
||||
Cache results for METADATA_CACHE_HOURS.
|
||||
|
||||
If no events found:
|
||||
|
||||
* Deny as account_too_new.
|
||||
|
||||
---
|
||||
|
||||
## 9. Activity Scoring
|
||||
|
||||
Example scoring logic:
|
||||
|
||||
* Has metadata: +10
|
||||
* Notes >= MIN_NOTES_COUNT: +20
|
||||
* Following >= MIN_FOLLOWING_COUNT: +10
|
||||
* Followers >= MIN_FOLLOWERS_COUNT: +10
|
||||
|
||||
Score must be deterministic and logged.
|
||||
|
||||
---
|
||||
|
||||
## 10. Entropy Payout System
|
||||
|
||||
Weighted random selection:
|
||||
|
||||
1. Build array based on configured weights.
|
||||
2. Generate secure random number.
|
||||
3. Select payout bucket.
|
||||
|
||||
Before finalizing quote:
|
||||
|
||||
* Check daily spend.
|
||||
* Check MAX_CLAIMS_PER_DAY.
|
||||
|
||||
If budget exceeded:
|
||||
|
||||
* Either deny or downgrade payout to FAUCET_MIN_SATS.
|
||||
|
||||
---
|
||||
|
||||
## 11. Claim Flow
|
||||
|
||||
### 11.1 POST /claim/quote
|
||||
|
||||
Input:
|
||||
|
||||
* lightning_address
|
||||
|
||||
Steps:
|
||||
|
||||
* Run eligibility engine.
|
||||
* If eligible, generate payout.
|
||||
* Insert quote record with expiry (e.g., 60 seconds).
|
||||
* Return quote_id and payout_sats.
|
||||
|
||||
### 11.2 POST /claim/confirm
|
||||
|
||||
Input:
|
||||
|
||||
* quote_id
|
||||
|
||||
Steps:
|
||||
|
||||
* Verify quote exists and active.
|
||||
* Re-check cooldown and budget.
|
||||
* Execute LNbits payment.
|
||||
* Update claim record.
|
||||
* Mark quote consumed.
|
||||
|
||||
Must be idempotent.
|
||||
|
||||
---
|
||||
|
||||
## 12. LNbits Integration
|
||||
|
||||
Payout flow:
|
||||
|
||||
1. Resolve Lightning address to LNURL.
|
||||
2. Fetch LNURL payRequest.
|
||||
3. Call callback with amount in millisats.
|
||||
4. Handle success/failure response.
|
||||
5. Store payment hash.
|
||||
|
||||
On failure:
|
||||
|
||||
* Mark claim failed.
|
||||
* Do not lock cooldown unless configured.
|
||||
|
||||
---
|
||||
|
||||
## 13. Public Endpoints
|
||||
|
||||
GET /health
|
||||
GET /config
|
||||
GET /stats
|
||||
GET /deposit
|
||||
|
||||
No authentication required.
|
||||
|
||||
---
|
||||
|
||||
## 14. Logging and Monitoring
|
||||
|
||||
Each claim attempt must log:
|
||||
|
||||
* pubkey
|
||||
* ip_hash
|
||||
* eligibility result
|
||||
* payout amount
|
||||
* payment status
|
||||
|
||||
Metrics to track:
|
||||
|
||||
* denial reasons count
|
||||
* payout distribution
|
||||
* daily spend
|
||||
|
||||
---
|
||||
|
||||
## 15. Security Hard Requirements
|
||||
|
||||
* Strict CORS
|
||||
* Rate limit /claim endpoints
|
||||
* Nonce replay protection
|
||||
* HMAC IP hashing
|
||||
* Admin keys never exposed
|
||||
* All secrets loaded from env
|
||||
|
||||
---
|
||||
|
||||
## 16. Production Readiness Checklist
|
||||
|
||||
Backend is complete when:
|
||||
|
||||
* NIP-98 auth fully verified.
|
||||
* Pubkey and IP cooldown enforced.
|
||||
* Account age check enforced.
|
||||
* Activity score enforced.
|
||||
* Entropy payout cannot be rerolled.
|
||||
* Daily budget cannot be exceeded.
|
||||
* LNbits payout works and errors handled safely.
|
||||
* Emergency stop disables claims instantly.
|
||||
* Logs clearly show denial reasons.
|
||||
Reference in New Issue
Block a user