Skip to content

Supabase Integration

IndieStack deeply integrates Supabase for authentication, database, and real-time backend services.

Client Types

ClientFileUsageFeature
Server Clientsrc/lib/supabase/server.tsServer Components, Route Handlers, Server ActionsCookie-based session, auto token refresh
Browser Clientsrc/lib/supabase/client.tsClient ComponentsBrowser-side queries, auto session cookie
Admin Clientsrc/lib/supabase/admin.tsServer privileged operationsService Role Key, bypass RLS
Middlewaresrc/lib/supabase/middleware.tsNext.js MiddlewareRequest-level session refresh

Database Tables

profiles

Auto-created via database trigger when a user registers in Supabase Auth:

sql
id         UUID PRIMARY KEYauth.users(id)
email      TEXT
full_name  TEXT
avatar_url TEXT
role       TEXT'user' | 'admin'

teams (Multi-tenant)

Multi-tenant architecture supporting team-based access:

  • owner: Full permissions
  • admin: Team management
  • member: Read/write projects
  • viewer: Read-only

team_members

User-team association with roles:

sql
id         UUID PRIMARY KEY
team_id    UUID → teams(id)
user_id    UUID → auth.users(id)
role       TEXT'owner' | 'admin' | 'member' | 'viewer'

projects

Team-linked projects with status management.

subscriptions

Stripe subscription status storage.

Migrations

FileContent
001_initial_schema.sqlBase tables, triggers, RLS policies
002_rbac_audit.sqlRBAC tables, audit logs, permission functions
003_projects_notifications_indexes.sqlNotifications, index optimization
025_notifications_realtime.sqlEnables notifications INSERT delivery in the Realtime publication

Realtime notifications

The dashboard notification list subscribes to postgres_changes INSERT events for public.notifications, filtered by user_id=eq.<current-user-id>. Events are coalesced for 120ms and the server-rendered list is refreshed. Supabase applies the notifications RLS policy before delivering an event, and the client displays connecting, live, or offline without blocking initial data when Realtime is unavailable.

Mock mode does not open a WebSocket. It exposes the same event/filter contract through a local event bridge so unit and Playwright tests can exercise the complete refresh path.

RLS Policies

All tables use Row Level Security:

  • profiles: Users read/write own data (id = auth.uid())
  • teams: Members read, owner/admin write
  • team_members: Users see own teams
  • projects: Team members access team projects
  • subscriptions: Owner/admin only

Mock Mode

When NEXT_PUBLIC_MOCK_ENABLED=true, no real Supabase needed:

  • src/lib/mock/index.ts: Mock query builder simulating PostgREST
  • src/lib/mock/data.ts: @faker-js/faker generated data
  • Supports eq, order, range, limit, single queries

Generate Types

bash
pnpm db:types
# supabase gen types typescript --linked > src/lib/supabase/database.types.ts

基于 MIT 协议开源