API and milestone engine for Disciplr: programmable time-locked capital vaults on Stellar.
- Health:
GET /api/health— service status and timestamp. - Vaults:
GET /api/vaults— list all vaults (in-memory placeholder).POST /api/vaults— create a vault (body:creator,amount,endTimestamp,successDestination,failureDestination).GET /api/vaults/:id— get a vault by id.
- Background jobs (custom worker queue):
GET /api/jobs/health— queue status (ok,degraded,down) and failure-rate snapshot.GET /api/jobs/metrics— detailed queue metrics by job type.POST /api/jobs/enqueue— enqueue a typed job.
- Health:
GET /api/health- service status and timestamp. - Auth:
POST /api/auth/login- mock login and audit logging.POST /api/auth/users/:id/role- role changes (admin only) with audit logging.
- Vaults:
GET /api/vaults- list all vaults with pagination, sorting, and filtering.POST /api/vaults- create a vault (body:creator,amount,endTimestamp,successDestination,failureDestination, optionalmilestones).GET /api/vaults/:id- get a vault by id.POST /api/vaults/:id/milestones/:mid/validate- validate an assigned milestone as verifier.POST /api/vaults/:id/cancel- cancel a vault (creator/admin) with audit logging.GET /api/health/security- abuse monitoring metrics snapshot.
- Transactions:
GET /api/transactions- list all transactions with pagination, sorting, and filtering.GET /api/transactions/:id- get a transaction by id.
- Analytics:
GET /api/analytics- list analytics views with pagination, sorting, and filtering.
- Admin:
POST /api/admin/overrides/vaults/:id/cancel- admin override to cancel vault with audit logging.GET /api/admin/audit-logs- admin-only audit log query endpoint.GET /api/admin/audit-logs/:id- admin-only single audit log lookup.
All list endpoints support consistent query parameters for pagination (page, pageSize), sorting (sortBy, sortOrder), and filtering (endpoint-specific fields). See API Patterns Documentation for details.
Data is stored in memory for now. Production would use PostgreSQL, a Horizon listener for on-chain events, and a proper milestone/verification engine.
- Enforces verifier role via
x-user-role: verifierheader. - Enforces assigned verifier via
x-user-idmatching milestoneverifierId. - Persists validation event in
vault.validationEvents. - Updates milestone state (
pending->validated) andvalidatedAt/validatedBy. - Emits domain events in
vault.domainEvents:milestone.validatedfor every successful validation.vault.state_changedwhen all milestones are validated and vault transitions tocompleted.
This project tracks sensitive actions in an in-memory audit_logs table shape:
idactor_user_idactiontarget_typetarget_idmetadatacreated_at
Current audited actions:
auth.loginauth.role_changedvault.createdvault.cancelledadmin.override
Admin-only access requirements for audit query endpoints:
x-user-role: adminx-user-id: <admin-user-id>
All timestamps are stored, transmitted, and returned in UTC (ISO 8601 with Z suffix). Input timestamps must include a timezone designator. See Timezone Contract for the full specification.
The backend now includes a generic background processor built as a custom in-memory queue/worker with:
- Typed job registration and validation.
- Configurable worker concurrency and polling interval.
- Retry handling with exponential backoff.
- Queue health and metrics endpoints.
- Recurring scheduled jobs for deadline checks and analytics recompute.
notification.senddeadline.checkoracle.callanalytics.recompute
curl -X POST http://localhost:3000/api/jobs/enqueue \
-H "Content-Type: application/json" \
-d '{
"type": "notification.send",
"payload": {
"recipient": "user@example.com",
"subject": "Disciplr reminder",
"body": "You have a milestone due soon."
},
"maxAttempts": 3,
"delayMs": 0
}'JOB_WORKER_CONCURRENCY(default:2)JOB_QUEUE_POLL_INTERVAL_MS(default:250)JOB_HISTORY_LIMIT(default:50)ENABLE_JOB_SCHEDULER(falsedisables recurring jobs)DEADLINE_CHECK_INTERVAL_MS(default:60000)ANALYTICS_RECOMPUTE_INTERVAL_MS(default:300000)
- Node.js + TypeScript
- Express
- Helmet + CORS
- PostgreSQL migrations via Knex
Prerequisites:
- Node.js 18+
- npm
Install and run:
npm install
npm run devAPI runs at http://localhost:3000.
| Command | Description |
|---|---|
npm run dev |
Run with tsx watch |
npm run build |
Compile TypeScript to dist/ |
npm run start |
Run compiled dist/index.js |
npm run lint |
Run ESLint on src |
npm run test |
Run Jest test suite |
npm run test:watch |
Run Jest in watch mode |
npm run test:api-keys |
Run API key route tests |
npm run migrate:make <name> |
Create migration file in db/migrations |
npm run migrate:latest |
Apply all pending migrations |
npm run migrate:rollback |
Roll back the latest migration batch |
npm run migrate:status |
Show migration status |
The backend includes abuse-oriented security instrumentation middleware.
GET /api/health/securityreturns:- failed login attempts seen by auth/login paths (
401or403) - rate limit triggers (
429) - suspicious pattern alerts by category
- top active source IPs in current windows
- failed login attempts seen by auth/login paths (
- Structured JSON logs are emitted for:
security.failed_login_attemptsecurity.rate_limit_triggeredsecurity.suspicious_pattern
| Env var | Default | Meaning |
|---|---|---|
SECURITY_RATE_LIMIT_WINDOW_MS |
60000 |
Rate-limit lookback window |
SECURITY_RATE_LIMIT_MAX_REQUESTS |
120 |
Max requests per IP in rate-limit window |
SECURITY_SUSPICIOUS_WINDOW_MS |
300000 |
Lookback window for suspicious pattern checks |
SECURITY_SUSPICIOUS_404_THRESHOLD |
20 |
404 count threshold for endpoint scan detection |
SECURITY_SUSPICIOUS_DISTINCT_PATH_THRESHOLD |
12 |
Distinct 404 path threshold for endpoint scan detection |
SECURITY_SUSPICIOUS_BAD_REQUEST_THRESHOLD |
30 |
400 count threshold for repeated bad request detection |
SECURITY_SUSPICIOUS_HIGH_VOLUME_THRESHOLD |
300 |
Total request threshold for high-volume bursts |
SECURITY_FAILED_LOGIN_WINDOW_MS |
900000 |
Lookback window for failed login burst checks |
SECURITY_FAILED_LOGIN_BURST_THRESHOLD |
5 |
Failed login threshold per IP before alert |
SECURITY_ALERT_COOLDOWN_MS |
300000 |
Minimum time between repeated alerts per IP/pattern |
No dedicated monitoring stack is wired in this repo yet. If your environment has one (Datadog, CloudWatch, Grafana Loki, ELK), create alerts on these log events:
security.rate_limit_triggered: alert on sustained frequency or concentration from a single IP.security.suspicious_patternwherepatternis:endpoint_scanhigh_volumerepeated_bad_requestsfailed_login_burst
Recommended initial alert policy:
- Warning: any
security.suspicious_patternevent. - Critical:
security.rate_limit_triggeredover 20 times in 5 minutes from one IP.
Migration tooling is standardized with Knex and PostgreSQL.
- Config:
knexfile.cjs - Baseline migration:
db/migrations/20260225190000_initial_baseline.cjs - Full process (authoring, rollout, rollback, CI/CD):
docs/database-migrations.md
disciplr-backend/
├── src/
│ ├── jobs/
│ │ ├── handlers.ts
│ │ ├── queue.ts
│ │ ├── system.ts
│ │ └── types.ts
│ ├── routes/
│ │ ├── health.ts
│ │ ├── jobs.ts
│ │ └── vaults.ts
│ └── index.ts
├── package.json
├── tsconfig.json
└── README.md
|- src/
| |- routes/
| | |- health.ts
| | |- vaults.ts
| | |- transactions.ts
| | |- analytics.ts
| | |- auth.ts
| | `- admin.ts
| | `- privacy.ts
| |- middleware/
| | |- queryParser.ts
| | `- privacy-logger.ts
| |- security/
| | `- abuse-monitor.ts
| |- utils/
| | `- pagination.ts
| |- types/
| | `- pagination.ts
| `- index.ts
|- docs/
| `- database-migrations.md
|- package.json
|- tsconfig.json
`- README.md
Required env var:
DATABASE_URL(PostgreSQL connection string)
Quick start:
npm run migrate:latest
npm run migrate:status