Skip to content

Repository files navigation

21.gifts — api

Docker Hub Image size (beta) Image size (latest) Pulls License: MIT

Backend service for 21.gifts — a peer-to-peer Bitcoin Lightning donation platform with NOSTR as the invisible communication substrate.

This repository is the canonical home for project-level documentation (see CONCEPT.md). The implemented HTTP surface is documented in SPEC.md. The frontend lives at 21gifts/app.

🐳 Docker images

Pre-built images are published to Docker Hub on every push to develop (:beta) and main (:latest).

Tag Source Deploy target Public URL
21gifts/api:beta develop DEV https://dev-api.21.gifts
21gifts/api:latest main PRD https://api.21.gifts

Pull and run locally:

docker run --rm -p 3000:3000 21gifts/api:beta
# → http://localhost:3000/healthz

Full image list and history: hub.docker.com/r/21gifts/api.

What this service does

The api is the "thick server" in a thin-client / thick-server architecture. It handles everything that doesn't have to run client-side:

  • NOSTR fan-out — accepts signed events from clients, verifies signatures, publishes to the shared nostr.space relay
  • NOSTR aggregation — subscribes to the relay, indexes events, exposes paginated reads
  • LN-Address resolution + caching — LUD-16 endpoints health-checked and normalized
  • Discovery — recent campaigns, ordering, future categories / search
  • Anti-abuse — rate-limiting, spam scoring, malformed-event rejection

It explicitly does not hold keys or sign events for the non-custodial target (v1 signs custodial identities server-side). Guest Donate LNURL-pay stays in the browser; the spend-worker path is the exception (POST /invoices fetches a recipient BOLT11, this api still does not pay).

Stack

Layer Choice
Runtime Bun ≥ 1.3
Language TypeScript (strict)
Framework Hono
Test runner Vitest + @vitest/coverage-v8
Lint ESLint (flat config) + Prettier
Validation Zod

All non-trivial functions ship with TSDoc. Coverage is hard-gated at 100% (lines, branches, functions, statements) on the activated surface — CI red otherwise.

Quick start

git clone https://github.com/21gifts/api.git
cd api
bun install
bun run dev    # → http://localhost:3000/healthz

Local checks (the same gates CI runs)

bun run typecheck       # tsc --noEmit
bun run lint            # eslint + prettier --check
bun run handbook:check  # every function and HTTP endpoint must be documented
bun run e2e:check       # every HTTP endpoint request and Function: <Name> title
bun run test:coverage   # vitest with 100% threshold
bun run build           # bun build to dist/
bun run e2e             # Playwright against bun src/index.ts

Runtime configuration

Variable Required Purpose
WEBAUTHN_RP_ID For passkey login WebAuthn RP ID (21.gifts / dev.21.gifts / localhost). Missing → passkey routes return 500; process still boots. Not a secret.
WEBAUTHN_RP_NAME no Human-readable RP name (default 21.gifts).
CORS_ALLOWED_ORIGINS no Comma-separated browser origins. Passkey finish allows those whose hostname is the RP ID or app.<rpId> only.

Documentation

Doc Purpose
CONCEPT.md Project vision, architecture, principles, decisions
SPEC.md Implemented HTTP surface (request/response contracts)
FLOWS.md Core UI journeys (sign-in → profile → donate → recurring → message)
docs/handbook/ Mandatory: every function and HTTP endpoint
CONTRIBUTING.md Dev setup, conventions, workflow
SECURITY.md Reporting vulnerabilities

License

MIT — see LICENSE.

About

Backend service + canonical project docs for 21.gifts — a peer-to-peer Bitcoin Lightning donation platform with NOSTR-native communication

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages