Security & Multi-Tenancy
FeedbackKit relies strictly on PostgreSQL Row Level Security (RLS) for data isolation and access control.
Multi-Tenancy Model
FeedbackKit organizes data around Organizations, Projects, and Feedback Items:
┌────────────────┐
│ auth.users │ (Managed by Supabase Auth / GitHub OAuth)
└───────┬────────┘
│
▼
┌────────────────┐ 1:N ┌────────────────────────┐
│ organizations │─────│ organization_members │ (user_id, org_id, role)
└───────┬────────┘ └────────────────────────┘
│ 1:N
▼
┌────────────────┐
│ projects │ (project_key, name, default_prompt_template)
└───────┬────────┘
│ 1:N
▼
┌────────────────┐
│ feedback_items │ (text, screen_name, annotations, environment)
└────────────────┘Tenancy Principles
- No Manual Client-Side Filtering: Dashboard mutations and queries do not implement application-level tenancy checks. The Supabase client forwards the user's JWT, and PostgreSQL RLS filters all rows at the database engine level.
- Organization-Scoped Policies: A user can only select, insert, update, or delete projects and feedback items if their
auth.uid()appears inorganization_membersfor that organization. - Project API Keys: Each project generates a public
project_key(e.g.fbk_live_...). This key is baked into the client app bundle and is used solely to route incoming reports to the correct project.
Authentication Boundaries
1. Ingestion Edge Function (ingest-feedback)
- Anonymous Callers: Incoming requests originate from mobile apps and desktop clients where embedding a secret database password or user token is unacceptable.
- Service Role Bypass: The Edge Function runs with
verify_jwt = falseinsupabase/config.toml. It validates theproject_key, resolves the matching project, uploads screenshots to the project storage bucket, and writes thefeedback_itemsrecord using Supabase'sservice_rolekey.
2. Dashboard Access (web/)
- GitHub OAuth Only: User authentication is strictly GitHub OAuth (
supabase.auth.signInWithOAuth({ provider: "github" })). Email/password registration is disabled. - Client-Side Auth: The dashboard is a static SPA. Sessions are stored in
localStorageand refreshed automatically by@supabase/supabase-js.
3. CLI & MCP Access (cli/)
- Browser Handshake: The CLI never asks users for passwords or master API keys. Instead, running
feedbackkit loginstarts a temporary local HTTP server, opens the browser to/cli-auth, and receives the authenticated user's session JWT. - Auditable Sessions: Every CLI authorization logs a record in
cli_sessions, visible and revocable from the web dashboard.
Storage Security Policies
Screenshots and diagnostics are stored in Supabase Storage under the feedback-screenshots bucket:
feedback-screenshots/
└── {project_id}/
└── {feedback_id}/
├── raw.png
├── annotated.png
└── attachment/
└── diagnostic_log.txtThe storage RLS policy inspects the first path segment (project_id). Users can only generate signed URLs or read files if they belong to the organization owning that project_id.