419 lines
14 KiB
Markdown
419 lines
14 KiB
Markdown
# 🌿 Cashumints.space API
|
|
|
|
A production-ready, decentralized observability, discovery, and reputation API for the Cashu mint ecosystem.
|
|
|
|
## Features
|
|
|
|
- **Mint Discovery** - Track and index Cashu mints across the ecosystem
|
|
- **Uptime Monitoring** - Continuous probing with full historical data
|
|
- **Metadata Tracking** - NUT-06 compliant metadata with version history
|
|
- **Nostr Reviews** - NIP-87 based review ingestion from configurable relays
|
|
- **Trust Scores** - Transparent, explainable reputation scoring (0-100)
|
|
- **Analytics** - Pageviews, trending mints, and popularity metrics
|
|
- **Admin API** - Full mint curation and system management
|
|
- **OpenAPI Docs** - Interactive Swagger UI documentation
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
# Clone and install
|
|
git clone <repo>
|
|
cd cashumints-api
|
|
npm install
|
|
|
|
# Configure
|
|
cp env.example .env
|
|
openssl rand -hex 32 # Generate admin key, add to .env
|
|
|
|
# Initialize database
|
|
npm run migrate
|
|
|
|
# Start API server
|
|
npm start
|
|
|
|
# View documentation
|
|
open http://localhost:3000/docs
|
|
```
|
|
|
|
## Production Deployment
|
|
|
|
### Prerequisites
|
|
|
|
- Node.js 18+
|
|
- Nginx (reverse proxy)
|
|
- systemd (process management)
|
|
- Let's Encrypt (SSL)
|
|
|
|
### Installation
|
|
|
|
```bash
|
|
# Create user
|
|
sudo useradd -r -s /bin/false cashumints
|
|
|
|
# Clone to /opt
|
|
sudo git clone <repo> /opt/cashumints-api
|
|
cd /opt/cashumints-api
|
|
|
|
# Install dependencies
|
|
sudo npm install --production
|
|
|
|
# Configure
|
|
sudo cp env.example .env
|
|
sudo openssl rand -hex 32 # Add to .env as ADMIN_API_KEY
|
|
sudo nano .env
|
|
|
|
# Create data directory
|
|
sudo mkdir -p data
|
|
sudo chown cashumints:cashumints data
|
|
|
|
# Initialize database
|
|
sudo -u cashumints npm run migrate
|
|
```
|
|
|
|
### Systemd Services
|
|
|
|
```bash
|
|
# Install service files
|
|
sudo cp deploy/cashumints-api.service /etc/systemd/system/
|
|
sudo cp deploy/cashumints-workers.service /etc/systemd/system/
|
|
|
|
# Reload and enable
|
|
sudo systemctl daemon-reload
|
|
sudo systemctl enable cashumints-api cashumints-workers
|
|
|
|
# Start services
|
|
sudo systemctl start cashumints-api
|
|
sudo systemctl start cashumints-workers
|
|
|
|
# Check status
|
|
sudo systemctl status cashumints-api
|
|
sudo systemctl status cashumints-workers
|
|
|
|
# View logs
|
|
sudo journalctl -u cashumints-api -f
|
|
sudo journalctl -u cashumints-workers -f
|
|
```
|
|
|
|
### Nginx Setup
|
|
|
|
```bash
|
|
# Install nginx config
|
|
sudo cp deploy/nginx.conf /etc/nginx/sites-available/cashumints-api
|
|
sudo ln -s /etc/nginx/sites-available/cashumints-api /etc/nginx/sites-enabled/
|
|
|
|
# Get SSL certificate
|
|
sudo certbot --nginx -d api.cashumints.space
|
|
|
|
# Test and reload
|
|
sudo nginx -t
|
|
sudo systemctl reload nginx
|
|
```
|
|
|
|
## API Documentation
|
|
|
|
Interactive API documentation is available at:
|
|
|
|
- **Swagger UI**: `http://localhost:3000/docs`
|
|
- **OpenAPI JSON**: `http://localhost:3000/openapi.json`
|
|
|
|
## API Endpoints
|
|
|
|
Base URL: `/v1`
|
|
|
|
### System
|
|
|
|
| Method | Endpoint | Description |
|
|
|--------|----------|-------------|
|
|
| GET | `/health` | Health check |
|
|
| GET | `/stats` | System statistics |
|
|
| GET | `/reviews` | Global reviews feed (filterable) |
|
|
| GET | `/analytics/uptime` | Ecosystem uptime analytics |
|
|
| GET | `/analytics/versions` | Mint version distribution |
|
|
| GET | `/analytics/nuts` | NUT support analytics |
|
|
|
|
### Admin (requires `X-Admin-Api-Key` header)
|
|
|
|
| Method | Endpoint | Description |
|
|
|--------|----------|-------------|
|
|
| POST | `/admin/mints` | Manually add a mint |
|
|
| POST | `/admin/mints/{id}/urls` | Add URL to mint |
|
|
| POST | `/admin/mints/merge` | Merge two mints |
|
|
| POST | `/admin/mints/split` | Undo a merge |
|
|
| POST | `/admin/mints/{id}/disable` | Hide from listings |
|
|
| POST | `/admin/mints/{id}/enable` | Re-enable mint |
|
|
| POST | `/admin/mints/{id}/metadata/refresh` | Force metadata fetch |
|
|
| POST | `/admin/mints/{id}/trust/recompute` | Force trust recalc |
|
|
| POST | `/admin/mints/{id}/status/reset` | Reset stuck state |
|
|
| POST | `/admin/mints/{id}/probe` | Force immediate probe |
|
|
| GET | `/admin/mints/{id}/visibility` | Get visibility status |
|
|
| GET | `/admin/jobs` | View job queue |
|
|
| GET | `/admin/system/metrics` | System health |
|
|
| GET | `/admin/audit` | Audit log (filter by mint_id) |
|
|
|
|
Admin endpoints also support `/admin/mints/by-url?url=` variants for all operations.
|
|
|
|
### Mints
|
|
|
|
| Method | Endpoint | Description |
|
|
|--------|----------|-------------|
|
|
| GET | `/mints` | List all mints (paginated, filterable) |
|
|
| GET | `/mints/trending` | Get trending mints by popularity |
|
|
| GET | `/mints/{mint_id}` | Get mint by ID |
|
|
| GET | `/mints/by-url?url=` | Get mint by URL |
|
|
| POST | `/mints/submit` | Submit new mint for tracking |
|
|
|
|
### Mint Details
|
|
|
|
All endpoints support both `/{mint_id}` and `/by-url?url=` variants:
|
|
|
|
| Endpoint | Description |
|
|
|----------|-------------|
|
|
| `/urls` | All URLs for mint (clearnet, Tor, mirrors) |
|
|
| `/metadata` | NUT-06 metadata |
|
|
| `/metadata/history` | Metadata change history |
|
|
| `/status` | Lightweight current status |
|
|
| `/uptime?window=24h\|7d\|30d` | Uptime statistics |
|
|
| `/uptime/timeseries?window=&bucket=` | Timeseries for charting |
|
|
| `/incidents` | Downtime incidents |
|
|
| `/trust` | Trust score with breakdown |
|
|
| `/reviews` | Nostr reviews (NIP-87) |
|
|
| `/views` | Pageview statistics |
|
|
| `/features` | Derived features (NUTs, Bolt11, etc.) |
|
|
|
|
## Configuration
|
|
|
|
Copy `env.example` to `.env` and configure:
|
|
|
|
```bash
|
|
# Server
|
|
PORT=3000
|
|
HOST=0.0.0.0
|
|
NODE_ENV=production
|
|
|
|
# Admin (REQUIRED - generate with: openssl rand -hex 32)
|
|
ADMIN_API_KEY=your-secure-key-here
|
|
|
|
# Database (SQLite)
|
|
DATABASE_PATH=./data/cashumints.db
|
|
|
|
# Probing
|
|
PROBE_TIMEOUT_MS=10000
|
|
PROBE_INTERVAL_ONLINE_MS=300000 # 5 minutes
|
|
PROBE_INTERVAL_OFFLINE_MS=900000 # 15 minutes
|
|
CONSECUTIVE_FAILURES_OFFLINE=3
|
|
ABANDONED_AFTER_DAYS=30
|
|
|
|
# Nostr Relays (comma-separated)
|
|
NOSTR_RELAYS=wss://relay.damus.io,wss://relay.nostr.band,wss://nos.lol
|
|
|
|
# Trust Score Weights (out of 100)
|
|
TRUST_WEIGHT_UPTIME=40
|
|
TRUST_WEIGHT_SPEED=25
|
|
TRUST_WEIGHT_REVIEWS=20
|
|
TRUST_WEIGHT_IDENTITY=10
|
|
TRUST_PENALTY_MAX=15
|
|
|
|
# Rate Limiting
|
|
RATE_LIMIT_WINDOW_MS=60000
|
|
RATE_LIMIT_MAX_REQUESTS=100
|
|
```
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Nginx (Reverse Proxy) │
|
|
│ • SSL termination • Rate limiting • Caching │
|
|
└────────────────────────────┬────────────────────────────────┘
|
|
│
|
|
┌────────────────────────────┴────────────────────────────────┐
|
|
│ HTTP API (Express.js) │
|
|
│ • REST endpoints • Swagger UI • Admin API │
|
|
│ • CORS enabled • Compression • Helmet security │
|
|
└────────────────────────────┬────────────────────────────────┘
|
|
│
|
|
┌────────────────────────────┴────────────────────────────────┐
|
|
│ SQLite Database │
|
|
│ mints │ mint_urls │ probes │ metadata │ reviews │ scores │
|
|
│ incidents │ pageviews │ jobs │ uptime_rollups │ audit_log │
|
|
└────────────────────────────┬────────────────────────────────┘
|
|
│
|
|
┌────────────────────────────┴────────────────────────────────┐
|
|
│ Background Workers │
|
|
│ Probe │ Metadata │ Nostr │ Rollup │ Trust │ Cleanup │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Trust Score
|
|
|
|
Trust scores (0-100) are computed from:
|
|
|
|
| Component | Max Points | Based On |
|
|
|-----------|------------|----------|
|
|
| Uptime | 40 | 30-day uptime percentage |
|
|
| Speed | 25 | Average response time (RTT) |
|
|
| Reviews | 20 | Nostr review quantity & rating |
|
|
| Identity | 10 | Metadata completeness |
|
|
| Penalties | -15 | Offline status, incidents, instability |
|
|
|
|
**Trust Levels:**
|
|
- **Excellent**: 85-100
|
|
- **High**: 70-84
|
|
- **Medium**: 50-69
|
|
- **Low**: 25-49
|
|
- **Unknown**: 0-24
|
|
|
|
## Mint Lifecycle
|
|
|
|
```
|
|
┌─────────────┐
|
|
Discovery ───▶ │ unknown │
|
|
└──────┬──────┘
|
|
│ successful probe
|
|
┌──────▼──────┐
|
|
│ online │ ◀──────────┐
|
|
└──────┬──────┘ │
|
|
│ slow response │ recovery
|
|
┌──────▼──────┐ │
|
|
│ degraded │ ───────────┤
|
|
└──────┬──────┘ │
|
|
│ consecutive │
|
|
│ failures │
|
|
┌──────▼──────┐ │
|
|
│ offline │ ───────────┘
|
|
└──────┬──────┘
|
|
│ > 30 days
|
|
┌──────▼──────┐
|
|
│ abandoned │
|
|
└─────────────┘
|
|
```
|
|
|
|
## Nostr Integration (NIP-87)
|
|
|
|
The API ingests these event kinds from configured relays:
|
|
|
|
| Kind | Description |
|
|
|------|-------------|
|
|
| 38172 | Cashu mint announcements (self-published by mints) |
|
|
| 38173 | Fedimint announcements |
|
|
| 38000 | Recommendations/reviews (with `#k` tag referencing 38172) |
|
|
|
|
Reviews are parsed for:
|
|
- Mint URL (from `u` or `d` tags, with or without protocol)
|
|
- Rating 1-5 (from `rating` tag or `quality` tag like `"1/1"` recommend / `"0/1"` not recommend)
|
|
- Content (review text)
|
|
|
|
## Admin API
|
|
|
|
All admin actions are audited. Never deletes raw data.
|
|
|
|
```bash
|
|
# Add a mint manually
|
|
curl -X POST http://localhost:3000/v1/admin/mints \
|
|
-H "X-Admin-Api-Key: $ADMIN_API_KEY" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"mint_url": "https://mint.example.com", "notes": "Trusted operator"}'
|
|
|
|
# Get system metrics
|
|
curl http://localhost:3000/v1/admin/system/metrics \
|
|
-H "X-Admin-Api-Key: $ADMIN_API_KEY"
|
|
|
|
# Force trust recalculation
|
|
curl -X POST http://localhost:3000/v1/admin/mints/{mint_id}/trust/recompute \
|
|
-H "X-Admin-Api-Key: $ADMIN_API_KEY"
|
|
|
|
# View audit log
|
|
curl http://localhost:3000/v1/admin/audit \
|
|
-H "X-Admin-Api-Key: $ADMIN_API_KEY"
|
|
```
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
cashumints-api/
|
|
├── src/
|
|
│ ├── index.js # Server entry point
|
|
│ ├── config.js # Configuration
|
|
│ ├── db/
|
|
│ │ ├── connection.js # Database connection
|
|
│ │ ├── migrate.js # Migration runner
|
|
│ │ ├── schema.sql # Main schema
|
|
│ │ └── schema-admin.sql # Admin schema
|
|
│ ├── docs/
|
|
│ │ └── openapi.js # OpenAPI specification
|
|
│ ├── middleware/
|
|
│ │ ├── adminAuth.js # Admin authentication
|
|
│ │ ├── errorHandler.js # Error handling
|
|
│ │ └── rateLimit.js # Rate limiting
|
|
│ ├── routes/
|
|
│ │ ├── admin.js # Admin endpoints
|
|
│ │ ├── mints.js # Mint endpoints
|
|
│ │ └── system.js # System endpoints
|
|
│ ├── services/
|
|
│ │ ├── AdminService.js # Admin operations
|
|
│ │ ├── MintService.js # Mint CRUD
|
|
│ │ ├── ProbeService.js # HTTP probing
|
|
│ │ ├── MetadataService.js # NUT-06 metadata
|
|
│ │ ├── UptimeService.js # Uptime rollups
|
|
│ │ ├── TrustService.js # Trust scoring
|
|
│ │ ├── ReviewService.js # Nostr reviews
|
|
│ │ ├── PageviewService.js # Analytics
|
|
│ │ └── JobService.js # Background jobs
|
|
│ ├── utils/
|
|
│ │ ├── url.js # URL normalization
|
|
│ │ ├── crypto.js # Hashing
|
|
│ │ └── time.js # Time utilities
|
|
│ └── workers/
|
|
│ ├── index.js # Combined runner
|
|
│ ├── probe.js # Mint probing
|
|
│ ├── metadata.js # Metadata fetching
|
|
│ ├── nostr.js # Nostr ingestion
|
|
│ ├── rollup.js # Uptime aggregation
|
|
│ └── trust.js # Trust calculation
|
|
├── deploy/
|
|
│ ├── cashumints-api.service # API systemd service
|
|
│ ├── cashumints-workers.service # Workers systemd service
|
|
│ └── nginx.conf # Nginx configuration
|
|
├── data/ # SQLite database (auto-created)
|
|
├── env.example # Configuration template
|
|
├── package.json # Dependencies
|
|
└── README.md # This file
|
|
```
|
|
|
|
## Development
|
|
|
|
```bash
|
|
# Install dependencies
|
|
npm install
|
|
|
|
# Run in development mode (auto-reload)
|
|
npm run dev
|
|
|
|
# Run specific worker
|
|
npm run worker:probe
|
|
npm run worker:metadata
|
|
npm run worker:nostr
|
|
npm run worker:rollup
|
|
npm run worker:trust
|
|
```
|
|
|
|
## Design Principles
|
|
|
|
1. **History is never erased** - All raw data is stored and aggregated. Nothing is overwritten.
|
|
2. **Offline ≠ dead** - Mints transition through states. Recovery is always possible.
|
|
3. **URL ≠ identity** - Mint identity is stable. Multiple URLs can point to the same mint.
|
|
4. **Trust is derived** - Every trust signal is computed from stored data with full breakdown.
|
|
5. **Self-hostable** - SQLite by default. No Redis or external queues required.
|
|
6. **Admin transparency** - Every admin action is audited. No hidden mutations.
|
|
|
|
## License
|
|
|
|
MIT
|
|
|
|
## Links
|
|
|
|
- [Cashu Protocol](https://cashu.space)
|
|
- [Cashu Documentation](https://docs.cashu.space)
|
|
- [NIP-87 Specification](https://github.com/nostr-protocol/nips/blob/master/87.md)
|
|
- [Cashu-TS Library](https://cashu-ts.dev)
|