Learn the system

Architecture, trust model, and Luckee OSS conventions for tracking Vercel Web Analytics across many projects.

Who this is for

My Many Domains is open-source software for developers who deploy multiple sites on Vercel and want pageviews and visitors from Vercel Web Analytics in one dashboard, without giving a hosted SaaS your Vercel API token. The public website handles marketing and Luckee sign-in; website lists and analytics calls run on your machine through a small Express companion API.

You might use this if…

  • You track more than one Vercel project and are tired of switching dashboards.
  • You already enabled Web Analytics on those Vercel projects.
  • You are comfortable running Postgres and Node locally on your machine.

You should not expect…

  • A fully hosted multi-tenant analytics SaaS on mymanydomains.com in v1.
  • Google Analytics, Plausible, or non-Vercel sources — Vercel-only today.
  • Storing your Vercel token in the cloud web app or any hosted backend.

Free Luckee account

A free Luckee account unlocks GitHub clone URLs on the marketing site and syncs profile metadata for sign-in. Analytics itself is not behind a paid plan.

For coding agents

  • Start on this page, then read my-vercel-analytics-web/.cursor/rules/AGENTS.md and ADR 022 (local-first cloud surface).
  • Product split: my-vercel-analytics-web (UI) | my-vercel-analytics-express-server (websites + Vercel on your machine).

Reference: Web ADR 022 — Local-first cloud surface

What you get (v1)

CapabilityIn the UIBackend
Multi-site overview chart/dashboard (local surface)GET /api/websites/analytics/overview
Per-site analytics chart/website-detail-pageGET /api/websites/:websiteId/analytics
Tracked websites list/projectsGET /api/websites
Add / import from VercelDashboard add formPOST /api/websites, GET /api/websites/discover
Cloud onboarding + health probe/app (cloud surface)GET /api/health
Marketing + auth/, /login, /signupSupabase + POST /api/account/sync

Website fields: hostname, display name, Vercel project and team ids, L7/L30 pageview rollups, and analyticsFetchedAt on each website row.

v1 non-goals

  • Encrypted Vercel tokens in Supabase or Railway
  • Proxying Vercel Web Analytics through the cloud API
  • Syncing the websites table to cloud Postgres
  • UI to paste or upload a Vercel API token in the web app

Two different “Vercel Analytics”

Your projects: Vercel Web Analytics API via the local companion and your VERCEL_ACCESS_TOKEN.

This marketing site: optional @vercel/analytics on the Vercel-hosted web app (mymanydomains.com traffic only). See ADR 039.

Repositories

GitHub org: Luckee-Core

RepositoryRuns onOwnsDoes not own
my-vercel-analytics-webVercel (cloud) + local devUI, APP_SURFACE, browser auth, API clientsPostgres, Vercel token, website rows
my-vercel-analytics-express-serverYour machine (default port 3009)Postgres schema, websites CRUD, Vercel API callsHosted marketing site, Luckee auth infrastructure

Deploy flow

  1. Browser loads my-vercel-analytics-web (cloud or local surface).
  2. Sign-in uses Luckee Supabase; profile metadata syncs over NEXT_PUBLIC_CMS_URL when configured.
  3. Dashboard analytics calls go to the companion on localhost (NEXT_PUBLIC_LOCAL_API_URL).
  4. Companion reads/writes local Postgres and calls Vercel Web Analytics with VERCEL_ACCESS_TOKEN.

Full env and route tables: my-vercel-analytics-express-server/docs/oss/wire-contract.md in a full clone.

ADRs: Web 022 (local-first surface), Express 011 (local companion only).

Trust and security

Three zones: browser, local companion, and Luckee-operated cloud services. Your Vercel token never belongs in the web app or hosted backends.

Zone 1 — Browser

Only NEXT_PUBLIC_* variables are visible to client code. The browser may hold a Supabase anon JWT. On the local surface it calls the companion directly; on cloud /app it probes GET /api/health on localhost only — not your project analytics.

Zone 2 — Local companion

Holds VERCEL_ACCESS_TOKEN and DATABASE_URL. CORS uses WEB_ORIGIN; development allows localhost and 127.0.0.1. Exits on Railway unless ALLOW_COMPANION_IN_CLOUD=true. There is no auth on /api/websites/* in v1 — treat it as localhost-trusted.

Zone 3 — Cloud

Luckee-operated hosted services handle Supabase auth, optional account profile sync, and transactional email. They never store your Vercel token or website analytics rows.

Where secrets live

Secret / dataAllowedNever
VERCEL_ACCESS_TOKENCompanion .envWeb app, Vercel web env, hosted backends
Website rowsLocal PostgresCloud Postgres (v1)
Supabase service roleHosted account API (server-side only)Browser
Email provider / auth hook secretsLuckee hosted auth email pipelineMMD web or companion

Auth email

Sign-up, resend, and magic-link email are not composed in the browser. Supabase Auth delivers messages through Luckee-hosted infrastructure. See web SECURITY.md for operator notes.

Further reading

  • Web SECURITY.md — SECURITY.md (web repo root)
  • Companion SECURITY.md — my-vercel-analytics-express-server/SECURITY.md
  • ADR 022 — .cursor/architecture/022-local-first-cloud-surface.md

Cloud vs local

NEXT_PUBLIC_APP_SURFACE is cloud or local. Production Vercel sets cloud; local dev defaults to local when unset.

ValueTypical deployNotes
cloudVercel production (mymanydomains.com)Set explicitly in production
localnpm run dev on your machineDefault when NEXT_PUBLIC_APP_SURFACE is unset in development

Routes

PathCloudLocal
/Marketing landingMarketing or local home
/login, /signup, /auth/callbackAuthAuth (when configured)
/appSigned-in onboarding + companion probeNot the primary entry
/dashboard, /projects, /website-detail-pageRedirect to /app (LocalSurfaceRouteGuard)Full dashboard
/docs/apiWorks if companion reachable from browserPrimary API reference UI
/learnStatic documentationSame

Companion probe on /app

Cloud /app runs probeLocalCompanionThunk: checking → ready or unavailable. Ready shows a banner to run the web app locally with NEXT_PUBLIC_APP_SURFACE=local — it does not embed the full dashboard on the hosted origin.

Web environment (summary)

VariableSurfacePurpose
NEXT_PUBLIC_APP_SURFACEbothcloud or local
NEXT_PUBLIC_LOCAL_API_URLbothCompanion base URL (default http://127.0.0.1:3009)
NEXT_PUBLIC_SUPABASE_URLcloudAuth
NEXT_PUBLIC_SUPABASE_ANON_KEYcloudAuth
NEXT_PUBLIC_CMS_URLcloudAccount API base
NEXT_PUBLIC_SITE_URLcloudEmail redirect origin

Data flow

From Vercel token in the companion .env to charts in the local dashboard — no analytics upload through the hosted origin.

Steps

  1. Create a Vercel access token with permission to read analytics; place it in the companion .env only.
  2. Run Postgres and the companion; apply schema from sql/ in the express-server repo (see companion README).
  3. Add a website manually or use Discover — the companion calls Vercel and returns import candidates.
  4. Save a website — the companion inserts a row in the local websites table.
  5. Open the dashboard — overview and per-site charts call the companion, which fetches Vercel Web Analytics and may cache snapshots (analyticsFetchedAt).
  6. The web app renders JSON in charts; Redux holds dumps and current* slices (ADR 001).

When something goes wrong

  • Companion not running — /app probe fails; local dashboard API calls error.
  • Invalid or revoked Vercel token — analytics errors; check companion logs.
  • Web Analytics not enabled on the Vercel project — empty data or errors from Vercel (see Vercel docs).

Vercel project setup: Vercel Analytics docs

Common questions

Does the hosted site call Vercel for my projects?

No. Only your local companion uses your Vercel token. The cloud site checks that the companion is running via a localhost health probe.

Where are website rows stored?

In your local Postgres on the companion. v1 does not sync websites to cloud Postgres.

Can I use the full dashboard on mymanydomains.com?

The full dashboard runs on your machine with APP_SURFACE=local. Production hosts marketing, auth, and setup.

HTTP contract

Success: { success: true, data }. Error: { success: false, error: string, message? }. Health: GET /api/health → success + data.status.

Local companion routes

MethodPathPurpose
GET/api/healthLiveness
GET/api-docs.jsonAPI docs catalog for /docs/api
GET/api/websitesList tracked websites
POST/api/websitesCreate website
GET/api/websites/discoverVercel import candidates
GET/api/websites/analytics/overviewMulti-site chart (timeFrame, groupBy)
GET/api/websites/:websiteId/analyticsPer-site analytics

Interactive catalog when the companion is running: /docs/api

Hosted account API (NEXT_PUBLIC_CMS_URL)

MethodPathPurpose
GET/api/healthLiveness
GET/api/accountAccount profile (JWT)
POST/api/account/syncUpsert user from JWT

Companion environment

VariableScopePurpose
PORTcompanionListen port (default 3009)
DATABASE_URLcompanionLocal PostgreSQL
VERCEL_ACCESS_TOKENcompanionVercel API (required for analytics)
VERCEL_TEAM_IDcompanionOptional default team scope
WEB_ORIGINcompanionCORS allowlist

Full env and route tables: my-vercel-analytics-express-server/docs/oss/wire-contract.md in a full clone.

Stack

Versions follow each repo's package.json at release time.

Web (my-vercel-analytics-web)

  • Next.js App Router (next ^16)
  • React 19, Redux Toolkit, manual thunks
  • Tailwind CSS 4
  • @supabase/supabase-js (browser auth)
  • recharts (dashboard charts)
  • @vercel/analytics (hosted marketing site only)
  • Node 22.x

Companion (my-vercel-analytics-express-server)

  • Express 5, TypeScript
  • pg (PostgreSQL)
  • cors, dotenv
  • Node 22.x

How the web app is built

Luckee Next.js template conventions. Full ADRs: .cursor/architecture/ in the web repo.

Folder map

  • src/app/**/page.tsx — thin routes
  • src/packages/<feature>/ — feature UI (dashboard, landing, learn, …)
  • src/store/thunks — async side effects only
  • src/api/local — companion client
  • src/api/account — cloud account client
  • src/model — Website and analytics DTO types
  • src/config — APP_SURFACE, routes, Supabase

ADR quick reference

ADRSummaryMMD
001Redux: flat dumps/current/builders; manual thunks; no selector functionsYes
002Thin app routes; features in src/packages/Yes
003Styles object + Tailwind template literalsYes
004src/api clients; thunks call APIsYes — local vs account split
008Static /website-detail-page + currentWebsiteYes
011src/model entity typesYes
012Form inputs under packages; zero-prop modalsYes — add website form
014Stripe Checkout returnN/A
022Local-first cloud surfaceYes — product core
039Vercel Analytics component on hosted webYes — marketing only

How the companion API is built

Express server template: thin routers, handlers, and processX() business logic. No src/domains/.

Folder map

  • src/services/websites/ — router, handlers, processX
  • src/data/websites/ — CRUD only
  • src/model/website.ts — row types
  • src/services/managed/vercel-config.ts — token from env at startup
  • sql/ — schema migrations
  • docs/oss/wire-contract.md — pair contract

ADR quick reference

ADRSummaryMMD
001–002Services + router factory; handlers → processX()Yes
003src/data/{table}/ CRUD onlyYes — websites
004Managed clients at startupYes — Vercel config
006Emoji logging; success/error JSONYes
010No SQL functions; updated_at in CRUDYes
009Stripe CheckoutN/A
011Local companion onlyYes — product core

Luckee OSS patterns

My Many Domains is one slice in a family of Next.js + Express repos that share ADR numbering and agent rules. Product-specific decisions (local companion, account-only cloud API) sit on top of the same templates.

Governance and contracts

  • mentorai-server data/open-source — release checklists, security audits, wire contract template
  • oss-api-docs-pattern.md — companion GET /api-docs.json + web /docs/api
  • Filled wire contract — express-server docs/oss/wire-contract.md

Stripe Checkout ADRs (web 014, express 009) are template placeholders — not used in My Many Domains.

Glossary

TermMeaning
Companionmy-vercel-analytics-express-server on your machine; owns Postgres and Vercel API calls.
APP_SURFACENEXT_PUBLIC_APP_SURFACE: cloud (hosted marketing/auth) or local (full dashboard).
ProbeBrowser GET /api/health against localhost from /app; does not upload analytics.
Web Analytics (product)Vercel Web Analytics API data for your projects via the companion.
Web Analytics (marketing)@vercel/analytics on the mymanydomains.com deployment (ADR 039).
Account syncPOST /api/account/sync on NEXT_PUBLIC_CMS_URL with Supabase JWT — profile only, not analytics.
LuckeeShared auth and OSS template family; free sign-in for clone URLs and profile sync.

Next steps

Agents: after this page, open .cursor/rules/AGENTS.md in the repo you are editing.