robustness: split jetstream into own container, add cursor persistence

Jetstream was running backgrounded in the same container as the API server,
so crashes went undetected and Docker never restarted it. Now each process
runs as a separate docker-compose service with independent restart policies.

Also adds cursor persistence to SQLite (saved every 5s) so restarts resume
from where they left off, moves event destructuring inside try/catch blocks,
and adds global unhandled error/rejection handlers for crash visibility.
This commit is contained in:
Julien Calixte
2026-02-17 01:17:42 +01:00
parent 1a7841b728
commit c84b4c5f97
9 changed files with 108 additions and 35 deletions

View File

@@ -1,13 +1,19 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This file provides guidance to Claude Code (claude.ai/code) when working with
code in this repository.
## Project Overview
litenote-jetstream is the backend for Remanso, a blogging platform built on the AT Protocol (Bluesky ecosystem). It has two processes:
litenote-jetstream is the backend for Remanso, a blogging platform built on the
AT Protocol (Bluesky ecosystem). It has two processes:
1. **Jetstream listener** (`jetstream.ts`) — Subscribes to the AT Protocol firehose via `@skyware/jetstream`, filtering for `space.remanso.note` records. On create/update events, it upserts notes into a local SQLite database.
2. **HTTP API server** (`server.ts`) — An Oak (Deno HTTP framework) server on port 8080 that exposes read-only endpoints to query stored notes.
1. **Jetstream listener** (`jetstream.ts`) — Subscribes to the AT Protocol
firehose via `@skyware/jetstream`, filtering for `space.remanso.note`
records. On create/update events, it upserts notes into a local SQLite
database.
2. **HTTP API server** (`server.ts`) — An Oak (Deno HTTP framework) server on
port 8080 that exposes read-only endpoints to query stored notes.
Both processes share the same SQLite database (`src/data/db.ts`).
@@ -35,9 +41,13 @@ deno fmt
## Architecture
- **Runtime**: Deno (not Bun, despite the README). Uses `deno.json` for task definitions and import maps.
- **Database**: SQLite via `https://deno.land/x/sqlite/mod.ts`. DB path is configurable via `SQLITE_PATH` env var, defaults to `notes.db`.
- **Note schema**: Defined as an AT Protocol lexicon in `lexicons/space/remanso/note.json`. Notes have `title`, optional `images` (blob refs), `publishedAt`, and `createdAt`. Primary key is `(did, rkey)`.
- **Runtime**: Deno (not Bun, despite the README). Uses `deno.json` for task
definitions and import maps.
- **Database**: SQLite via `https://deno.land/x/sqlite/mod.ts`. DB path is
configurable via `SQLITE_PATH` env var, defaults to `notes.db`.
- **Note schema**: Defined as an AT Protocol lexicon in
`lexicons/space/remanso/note.json`. Notes have `title`, optional `images`
(blob refs), `publishedAt`, and `createdAt`. Primary key is `(did, rkey)`.
- **API endpoints**:
- `GET /notes?cursor=&limit=` — paginated notes (all users)
- `GET /:did/notes?cursor=&limit=` — paginated notes for a specific DID