Two-day backend scaffold: AGPL split, auth middleware, rate limiting, Lovdata ingest
fpvetleseter built the entire Juridisk backend in two commits - schema, auth, rate limiting, and a 298-line Lovdata ingestion script. Several pieces are generic enough to pull into any mike fork regardless of whether you're targeting Norway.
Day 1 (da75ade) sets the foundation. The frontend/src/core/ and frontend/src/proprietary/ split, each with a README, is the cleanest pattern here for forks that need to layer closed-source code on top of the AGPL upstream. Supabase migration 001_initial_schema.sql lands five tables - profiles, documents, document_chunks, conversations, messages - with pgvector(1536), an HNSW index, RLS on every user-owned table, and an auth.users trigger that creates profiles on signup. New deps: helmet, stripe, zod, node-cache. Body limit drops from 50MB to 10MB; tabular and workflows routes are stripped.
Day 2 (13e47ea) adds behavior on top. backend/src/lib/supabase.ts now throws at startup if SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY are absent (with a backward-compat fallback to the legacy SUPABASE_SECRET_KEY name). Auth is moved to a dedicated backend/src/middleware/auth.ts that validates JWTs and attaches userId/userEmail strictly from the token, with an explicit SECURITY comment blocking body-injected identity. Rate limiting lives in backend/src/middleware/ratelimit.ts and uses a security definer RPC increment_queries_today (migration 003) against a profiles.queries_today counter; free tier defaults to 10 queries/day with a Retry-After: 86400 response. ingest-lovdata.ts (298 lines) downloads two .tar.bz2 archives from Lovdata's public API, walks the HTML with cheerio, SHA-256 hashes each section, embeds with text-embedding-3-small in batches of 100, and idempotently upserts.
Things worth lifting independently: the AGPL/proprietary directory split is a cheap pattern copy. The requireAuth rewrite is strictly cleaner than the upstream - removes inline duplication, enforces JWT-only identity. The rate-limit RPC pattern is reusable as-is. The ingest script's cheerio→hash→batch-embed→upsert skeleton applies to any HTML corpus; Norwegian law is the target here but the pattern is generic.
Watch points: requireAuth changes the error envelope from { detail: ... } to { data: null, error: ... } in Norwegian, which breaks any client expecting the old shape. The rate-limit counter resets on a rolling 24h window, not at midnight Oslo time as the AGENTS.md claims. database.ts is hand-maintained with a // TODO: regenerate note - it will drift; use supabase gen types instead. ingest-lovdata.ts shells out to tar -xjf, which fails on Windows runners without msys2 or git-bash on PATH. Both commits carry Co-Authored-By: Claude Opus 4.7 - review AI-generated code with the usual attention.
Spotted something wrong? Or know the PR text has fresher detail than the writeup above?