Wire the app to the Supabase backend, replacing localStorage-only

- 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
This commit is contained in:
2026-09-05 00:33:28 -05:00
co-authored by Claude Sonnet 5
parent 8cea3f8b92
commit 1ae967c8a4
13 changed files with 411 additions and 20 deletions
+8 -5
View File
@@ -3,12 +3,15 @@ import { create } from 'zustand'
import { validateConnection } from '../domain/compatibility'
import { allDeviceTemplates, createDeviceFromTemplate, createEmptyProject, incrementPortName } from '../domain/project'
import type { CableType, Connection, Device, DeviceCategory, DeviceTemplate, Port, PortType, Project } from '../domain/types'
import { LocalStorageProjectRepository } from '../data/LocalStorageProjectRepository'
import type { ProjectRepository } from '../data/ProjectRepository'
import type { DiagramRepository } from '../data/DiagramRepository'
import { SupabaseDiagramRepository } from '../data/SupabaseDiagramRepository'
// Swapping to a backend later means constructing a different repository here
// (or injecting one) — nothing else in the store changes.
const repository: ProjectRepository = new LocalStorageProjectRepository()
// This is exactly the swap the repository pattern was built for: only this
// one line changed to move off localStorage-only and onto real (locally
// self-hosted, for now) Supabase persistence — nothing else in the store or
// UI layers needed to change. LocalStorageDiagramRepository is still in the
// codebase as a reference implementation / fallback, just no longer active.
const repository: DiagramRepository = new SupabaseDiagramRepository()
interface ProjectStoreState {
project: Project