Sereal Docs

Architecture

How the Sereal app, database, and external services fit together.

Sereal is a single Next.js application talking to a Supabase project and a small set of optional external APIs. There is no separate backend service — server work happens inside Next.js (server components, server actions, and a handful of API routes).

Components

PieceRole
Next.js app (App Router, TypeScript)The whole product — UI, server actions for writes, API routes for cron and exports. Runs as one Docker container on port 3000.
Supabase PostgresAll durable data. Row-Level Security scopes every tenant's rows by auth.uid().
Supabase AuthEmail/password login. The owner account is created by the bootstrap script.
Supabase StorageItem photos, in a private sereal-images bucket.
eBay Browse APIOptional. Powers deal polling, Scout, and sold-comp lookups.
Email (Resend or SMTP)Optional. Sends the daily deal digest.

How a request flows

  • Reads are server components querying Supabase directly with the request's authenticated session. Database views (e.g. the dashboard rollup and the grading-pipeline view) do the heavy aggregation in Postgres.
  • Writes go through server actions that self-scope to the current tenant and call atomic RPCs for anything multi-step (recording a sale, finalizing a grade, allocating a break's cost). Defense-in-depth: actions scope by tenant even though RLS would also catch it.
  • Scheduled work (deal polling, the email digest, value-chart snapshots) runs through /api/cron/* routes guarded by a CRON_SECRET header, triggered by an external scheduler you control.

Database migrations are the source of truth

The schema is defined by the ordered migration files in supabase/migrations/, applied with supabase db push --linked. Migrations are immutable once applied — changes always land as a new migration. See Data model for the entity overview and check:migrations for verifying parity.

Design decisions worth reading

The non-obvious "why" behind the operational model is captured in Architecture Decision Records:

  • ADR-001 — External API economics: why operators bring their own eBay credentials rather than sharing a Sereal key.
  • ADR-002 — Tenant cardinality: the schema is multi-tenant, but the self-host flow assumes one operator, one collection.
  • ADR-003 — Self-hosted distribution: the config-flag model (SELF_HOSTED, signup, billing) and how cloud vs. self-host behavior diverges.

All three live in docs/architecture-decisions/.

On this page