Softmaple requires Node.js 24.12 or newer, pnpm 11, a Supabase project, and
PostgreSQL credentials for that project.
Architecture
The monorepo contains a Next.js 16 web app, a horizontally scalable Nitro WebSocket service, Prisma/Supabase migrations, the Lexical editor, and the EG-walker collaboration packages.public.documents. Document bodies exist only as
immutable EG-walker event batches; no Markdown or editor JSON shadow column is
stored. Markdown, preview, and LaTeX are derived from the current Lexical state.
Storage roles
Local setup
apps/web/.env:
packages/db/.env for migrations:
NEXT_PUBLIC_* variables.
Password reset emails
In the Supabase dashboard, open Authentication → Email Templates → Reset Password and point the link at the app’s confirm route:/auth/confirm verifies the token on the server, so the link works on any
device or browser. The default {{ .ConfirmationURL }} link still works, via
/auth/callback, but only in the browser that requested it: its PKCE code
verifier is a cookie there. {{ .SiteURL }} is the project’s Site URL
(Authentication → URL Configuration), which should match
NEXT_PUBLIC_APP_URL.
Database
Prisma migrations are the single schema source of truth.packages/db/src/database.types.ts whenever the public
schema or RPC surface changes. The avatars bucket accepts JPEG, PNG, and WebP
up to 2 MB; the web action also rejects images above 2048 × 2048.
Run and verify
pnpm dev starts Web and Collab through Turborepo. Browser WebSockets always
use the web origin at /collab/document and /collab/presence; the browser
must never receive a direct backend URL or Redis credentials.
Stock next dev does not forward /collab/* WebSocket upgrades. For local
same-origin sockets use either:
- Playwright’s
apps/web/scripts/e2e-collab-router.mjs, or vercel devwith the rootvercel.jsonServices routing.
Real E2E
Playwright uses dynamic ports, starts both services plus the local collab router, and refuses to reuse an existing server. Core E2E never uses a mock Supabase client or a forged cookie. It requires a dedicated, non-production Supabase project:core.spec.ts, password-reset.spec.ts,
workspace-settings.spec.ts) form the chromium-seeded Playwright project.
The Isolated Supabase E2E workflow runs it on demand; its GitHub environment
stores these secrets and requires approval. Every other spec is in the
chromium project, needs no credentials, and runs on each pull request as
Chromium Smoke:
Deployment
- Set the Vercel project framework to Services and use the repository root
(so root
vercel.jsonis applied). - Provision Upstash Redis from the Vercel Marketplace and connect it so
REDIS_URLis available to the collab service. - Set collab env vars:
DATABASE_URL,SUPABASE_URL,SUPABASE_PUBLISHABLE_KEY,COLLAB_ALLOWED_ORIGINS, andREDIS_URL. - Confirm root routing:
- Origin-checked WebSocket upgrades for document and Presence paths;
- unknown-origin rejection and reconnect/repair behavior;
- public read-only access and immediate revocation;
- avatar upload, public delivery, replacement, and removal;
- two browser contexts editing the same document through
/collab/documentwith presence on/collab/presenceacross Fluid instances.