-
Notifications
You must be signed in to change notification settings - Fork 1
Supabase Sync
Rubric Maker works entirely offline via localStorage. The Supabase sync layer is an opt-in feature that adds:
- Cross-device sync — your rubrics, students, and grades are available on every device you sign in to.
- Colleague sharing — share a rubric or class with another teacher account (read-only or editable).
- File storage offload — attachments and export templates are stored in Supabase Storage instead of base64 strings in localStorage, removing the 5–10 MB browser storage limit for files.
localStorage remains the synchronous primary store. Supabase syncs in the background and the app loads instantly from localStorage even when offline or disconnected.
Browser
└── AppContext (localStorage — primary, synchronous)
└── StorageSync singleton (background, async)
├── SupabaseAdapter — Supabase client wrapper
└── AttachmentSync — file upload/download via Supabase Storage
The AppContext reducer is unchanged — components never talk to Supabase directly. StorageSync subscribes to state changes, mirrors them to Supabase, and hydrates localStorage from the DB on reconnect.
- Supabase CLI installed
- Docker Desktop running
# Start a local Supabase stack
supabase startThe CLI prints something like:
API URL: http://127.0.0.1:54321
anon key: eyJhbGci...
Studio: http://127.0.0.1:54323
In the app, go to Settings → Database → Connect & Sync and paste the URL and anon key.
Alternatively, add them to .env.local to pre-fill the form automatically:
VITE_SUPABASE_URL=http://127.0.0.1:54321
VITE_SUPABASE_ANON_KEY=eyJhbGci...
.env.localis gitignored. Never commit real credentials to the repository.
supabase stopGo to supabase.com and create a new project.
Region: Choose eu-central-1 (Frankfurt) for AVG/GDPR compliance when serving EU users.
The four migration files in supabase/migrations/ set up the full schema. Run them in order using the Supabase dashboard SQL editor, or push them via the CLI:
supabase db push --db-url "postgresql://postgres:<password>@<host>:5432/postgres"| Migration | What it does |
|---|---|
001_initial_schema.sql |
Creates all tables (rubrics, students, classes, student_rubrics, attachments, etc.) |
002_rls_policies.sql |
Enables Row Level Security — each user can only read/write their own rows |
003_storage_buckets.sql |
Creates the attachments and templates storage buckets with RLS |
004_profile_trigger.sql |
Auto-creates a profiles row when a new auth user signs up |
In the app, go to Settings → Database → Connect & Sync and enter your project URL and anon key (found in Project Settings → API in the Supabase dashboard).
All tables follow the same pattern: id (text, primary key), owner_id (uuid, FK to profiles), and a data JSONB column holding the full entity. This avoids complex camelCase ↔ snake_case column mapping while keeping RLS policies simple.
| Table | Description |
|---|---|
profiles |
One row per auth user; auto-created by trigger |
rubrics |
Rubric definitions |
classes |
Class definitions |
class_members |
Many-to-many: classes shared with other teachers (viewer or editor role) |
students |
Student records, linked to a class |
student_rubrics |
Graded rubrics + peer reviews (distinguished by is_peer_review) |
attachments |
Attachment metadata; the file lives in Supabase Storage |
comment_bank |
Reusable feedback snippets |
export_templates |
Word mail-merge template metadata; file in Storage |
grade_scales |
Custom grade scale definitions |
comment_snippets |
Individual comment snippet entries |
favorite_standards |
Saved CSP standard codes |
| Stage | Mechanism |
|---|---|
| First connect | Anonymous session — no email required |
| Upgrade to named account | Email magic-link (OTP) sign-in via Settings |
| Sharing rubrics/classes | Both parties must have a named (non-anonymous) account |
Anonymous sessions persist across browser restarts via the Supabase auth cookie. Upgrading to a named account merges the anonymous data into the new user's account.
Once signed in with a named account:
- Open a rubric or class in the app.
- Go to Share and enter a colleague's email address.
- Choose Viewer (read-only) or Editor access.
- The colleague sees the shared item appear in their list on next sync.
Sharing is managed via the class_members table and RLS policies that grant read access to shared rows.
If you have existing data in localStorage and want to move it to Supabase:
- Connect to Supabase (Settings → Database → Connect & Sync).
- Click Push local → database to bulk-upload all localStorage data to Supabase.
| Variable | Description | Required |
|---|---|---|
VITE_SUPABASE_URL |
Your Supabase project URL (e.g. https://xyz.supabase.co) |
No — can be entered in UI |
VITE_SUPABASE_ANON_KEY |
Supabase anon (public) key | No — can be entered in UI |
Copy .env.example to .env.local and fill in the values. .env.local is never committed to version control.
- Check that the URL starts with
https://(cloud) orhttp://127.0.0.1:54321(local). - Check that the anon key is the full JWT string.
- For local: confirm
supabase startis running and Docker is up.
Click Pull Now in Settings → Database. The initial hydration runs automatically on connect, but can be triggered manually.
After a long offline period, Supabase may have newer data than localStorage. Use Pull Now to overwrite localStorage with the DB state, or Push local → database to do the reverse.