Below md width, the app now forces view-only (same canEdit mechanism as a
shared view-only diagram) rather than trying to support touch editing:
palette and inspector panels hide, editing controls disable, and the top
bar collapses to just Diagrams + Account. A bottom tab bar swaps between a
full-screen canvas and a full-screen Bill of Materials, since there's no
room for both side by side. Canvas gets a few mobile-specific trims too:
MiniMap and the interactivity lock button hide whenever canEdit is false
(the lock button doesn't actually grant editing either way — nodesDraggable/
nodesConnectable already override it — so leaving it visible would just be
misleading), and h-screen is replaced with h-dvh throughout so the layout
doesn't get clipped by a mobile browser's collapsing address bar.
Also fixes quick-add's anti-stack offset (24px — far smaller than a device
node) to actually tile devices apart instead of leaving them nearly
overlapping, and logs a deferred "Auto-arrange" layout feature in
organized-ideas.md, surfaced by mobile visitors having no way to fix an
overlapping diagram themselves.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017DUU6CnxECCDeqDNYJgr5x
CompleteProfileScreen threw a raw PostgrestError (not an Error instance),
so `err instanceof Error` was false and the real message got swallowed.
LoginScreen's Mailpit hint was showing in production; gated behind DEV.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017DUU6CnxECCDeqDNYJgr5x
- Migration: profiles.username is now nullable -- Google's OAuth
redirect can't collect a username up front the way the email/password
signup form does, so a first-time Google sign-in's profile is created
with no username.
- supabase/config.toml: [auth.external.google] enabled, credentials via
env() substitution (SUPABASE_AUTH_EXTERNAL_GOOGLE_CLIENT_ID/_SECRET
in .env.local, which the CLI auto-loads). skip_nonce_check is on,
which Supabase's own docs call out as required for local sign-in.
- LoginScreen: "Continue with Google" alongside the existing
email/password form.
- CompleteProfileScreen: one-time gate for a signed-in user with no
username yet (i.e. first Google sign-in) -- same hard-gate spirit as
email verification, nothing else is usable until a username is set.
- App.tsx now checks profiles.username after establishing a session and
routes to CompleteProfileScreen before AppShell when it's missing.
RLS test suite re-run clean (23/23) after the schema change.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017DUU6CnxECCDeqDNYJgr5x
- DiagramRepository (renamed from ProjectRepository, per the
organized-ideas.md §8 naming decision) now has a Supabase-backed
implementation as the active repository. LocalStorageDiagramRepository
stays in the codebase as a reference implementation / fallback, just
no longer wired in. Only the storage layer's naming changed here --
the domain type, store, and UI copy still say "Project"; that's a
separate, larger mechanical rename tracked on its own.
- Minimal email/password auth gate (src/components/auth/LoginScreen.tsx)
since Supabase RLS requires a real signed-in user to do anything --
this is NOT the Phase 2 experience (Google SSO, polished signup),
just enough of the same schema (username + email + password) to make
the backend foundation usable end to end before that phase exists.
Respects the hard email-verification gate from config.toml.
- .env.example documents the required VITE_SUPABASE_URL /
VITE_SUPABASE_ANON_KEY (local dev values, not secrets); .env.local
has the actual local values and is gitignored.
Verified end-to-end against the local stack: signup creates a
confirmed-pending user, the handle_new_user trigger creates their
profile, sign-in is blocked until confirmed, and a signed-in session
can upsert/read back its own diagram row exactly as the app's
save()/load() do it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017DUU6CnxECCDeqDNYJgr5x