Wenlan
Wenlan is a source-backed AI knowledge base and LLM wiki for AI work: organize documents and decisions into pages you can find, inspect, and review.
翻訳待ち
No updates detected yet. GitHub releases will appear here.
Loading the full README. The saved excerpt is shown below.
Next.js (App Router) + TypeScript + Tailwind CSS + Supabase. See CLAUDE.md for the plan.
Open http://localhost:3000.Read the full README ↗Next.js (App Router) + TypeScript + Tailwind CSS + Supabase. See CLAUDE.md for the plan.
npm install
cp .env.example .env.local # then fill in the Supabase values
npm run dev
Open http://localhost:3000.
| Variable | Exposure | Purpose |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL | public | Supabase project URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY | public | anon key |
SUPABASE_SERVICE_ROLE_KEY | server-only secret | admin client (lib/supabase-admin.ts); bypasses RLS |
NEXT_PUBLIC_SITE_URL | public | base URL for auth redirect links (magic link, OAuth, email confirm) |
ANTHROPIC_API_KEY | server-only secret | Claude vision extraction |
EXTRACTION_WEBHOOK_SECRET | server-only secret | shared secret for /api/extraction; must match the Supabase Vault secret extraction_webhook_secret |
INTERNAL_TOOLS_EMAILS | server-only | optional CSV allow-list for /internal/* pages |
RESEND_API_KEY | server-only secret | Resend key for reminder email; unset = reminders are logged as skipped, not sent |
REMINDERS_FROM_EMAIL | server-only | From: address for reminder email, on a domain verified in Resend |
CRON_SECRET | server-only secret | bearer token for /api/cron/reminders and /api/cron/school-calendars; Vercel sends it automatically once set |
STRIPE_SECRET_KEY | server-only secret | Stripe key; unset = billing off, every household keeps the paid entitlements |
STRIPE_WEBHOOK_SECRET | server-only secret | signing secret for /api/stripe/webhook; unset = the webhook no-ops |
STRIPE_PRICE_GBP_MONTHLY | server-only | price ID offered to UK households, £7.99/mo |
STRIPE_PRICE_GBP_YEARLY | server-only | price ID offered to UK households, £69/yr |
STRIPE_PRICE_USD_MONTHLY | server-only | price ID offered to US households, $6.99/mo |
STRIPE_PRICE_USD_YEARLY | server-only | price ID offered to US households, $59/yr |
GOOGLE_CLIENT_ID | server-only | OAuth client ID for Gmail read-only import (separate from Supabase sign-in Google) |
GOOGLE_CLIENT_SECRET | server-only secret | OAuth client secret for Gmail import |
Set the secrets in the Vercel project settings (Production + Preview).
NEXT_PUBLIC_SITE_URL must match the deployment origin (https://homeapp-mu.vercel.app).
Migrations live in supabase/migrations/ and are already applied
to the linked project. Tables: households, household_members, properties,
household_invites, documents, document_chunks, reminder_rules, reminders,
reminder_events, subscriptions, renewal_items, household_calendar_feeds; plus a
private documents Storage bucket. Every table has row-level security scoped to household
membership. The subscriptions, renewal_items and household_calendar_feeds
migrations are written but not yet applied.
Read-only Gmail import lets a household scan the last 12 months of inbox PDFs, review candidates, and confirm what to file — nothing is stored until import.
Google Cloud setup (Ross):
https://homeapp-mu.vercel.app/api/gmail/callback (production)http://localhost:3000/api/gmail/callback (local)GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET in .env.local and Vercel.20260914130000_gmail_import.sql if not already applied.The OAuth scope is gmail.readonly only. Tokens are stored server-side; members
disconnect from the Add document sheet.
A new documents row (extraction_status = 'pending') fires a Supabase database
webhook → POST /api/extraction → Claude (claude-sonnet-4-6) vision extraction →
fields + confidence written back, full text chunked into document_chunks. Review and
confirm extracted fields on /documents. /internal/extraction-test is a benchmark
harness (not linked from any nav).
Document email reminders — every extracted or confirmed document with a future
renewal (or, failing that, end) date gets a reminders row, written server-side by
syncRemindersForDocument() in lib/reminders.ts whenever
extraction finishes or a review is confirmed. How far ahead to nudge comes from
reminder_rules, keyed on the category from lib/home-overview.ts and the household's
locale — 60/30/7/0 days by default.
Tracked renewals (phase 9) — passports, MOT, insurance and the like live in
renewal_items, managed on /family and surfaced in Coming up inside each item's
remind window. They do not send email yet; the cron only covers document reminders.
GET /api/cron/reminders runs daily at 08:00 UTC (see vercel.json),
emails every household member whose reminder falls due that day via Resend, and logs
each send in reminder_events — the unique (reminder_id, offset_days) there is what
stops a nudge going out twice. The day-of send closes the reminder off as sent.
GET /api/cron/school-calendars runs daily at 06:15 UTC on the same CRON_SECRET,
re-reading every school's linked ICS feed through syncSchoolCalendar() so term dates
on the dashboard stay fresh. It takes at most 50 schools a run, stalest first, and one
unreadable feed is recorded against that school rather than failing the run.
Free households keep unlimited documents but get three live reminders, no export and (later) no AI answers. Paying lifts all of that: £7.99/mo or £69/yr in the UK, $6.99/mo or $59/yr in the US, cancelled in one click from Stripe's billing portal.
This is the beginning of the README. Read the rest at the original. Read the full README ↗