System overview
| Part | Role |
|---|---|
| Web app | React 18, TypeScript, Vite, Tailwind CSS, shadcn/ui, TanStack Query, React Router. Pages are lazy-loaded. Holds no secrets: it only knows the Worker's URL and Clerk's public publishable key. |
Cloudflare Worker (workers/news-api) | The only server. Proxies GNews, GDELT, NewsData, Unsplash images and newsletter sign-ups; serves the application API under /api/* (article cache, account profile, admin console, Clerk webhooks); keeps every key server-side; enforces origin checks and rate limits. |
| Neon (Postgres) | Article cache (news_articles), user roles (app_users), admin console data and the audit log. Reached only by the Worker. |
| Clerk | Sign-up, sign-in, email verification, password reset, Google/Microsoft sign-in. The Worker verifies each session token; roles live in Neon, never in Clerk or the browser. |
| Docs | This Docusaurus site, built into the web app's static files at /docs/. |
Until the Neon and Clerk accounts are connected, the Worker answers the /api data routes with 503 and the website shows accounts as temporarily unavailable; the news feed does not depend on either. See Neon + Clerk cutover.
Before (until October 2026)
The browser talked to Supabase directly: Supabase Auth for accounts, the news_articles table for the cache (read and written from the browser) and Edge Functions for the admin console and NewsData. That project is paused and its code is archived under legacy/supabase/.
Hosting
The production domain is served by Lovable hosting (SPA build, no prerender), published from main. Vercel (vercel.json) also builds main with the full pipeline (sitemap generation and Puppeteer prerendering) as a non-production deployment. The Worker is deployed separately with Wrangler.
SEO
Per-route titles, descriptions, and canonicals are set by a useSEO hook. robots.txt, a sitemap index, llms.txt, and JSON-LD structured data (NewsMediaOrganization, WebSite, NewsArticle) describe the site to search engines and AI systems.