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.

infrastructuresearch

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.

So what Worth a look if you need a ready-made Supabase schema for user-scoped doc-Q&A, a clean AGPL/proprietary directory split, or a reusable batch-embed ingest skeleton. Skip if your deployment is Windows-native (the tar dependency bites you) or if you need Norwegian-free error strings.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

2 commits from fpvetleseter/mike, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
da75ade7 chore(day1): AGPL separation, deps, env templates, schema migration, helmet security fpvetleseter 2026-05-08 ↗ GitHub
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
13e47eab feat(day2): auth middleware, rate limiting, Supabase types, Lovdata ingestion script fpvetleseter 2026-05-08 ↗ GitHub
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-204.md from inside the repo you want the changes in.

⬇ Download capture-thread-204.md