Supabase & Backend Architecture
FeedbackKit uses Supabase for PostgreSQL, Storage, Authentication, and Edge Functions.
Local Development Stack
Running Supabase locally requires Docker Desktop:
bash
# Start local Supabase containers
supabase start
# Inspect credentials and service endpoints
supabase status -o env
# Reset database and re-apply all migrations from scratch
supabase db reset
# Stop local stack
supabase stopLocal Supabase Studio is accessible at: http://127.0.0.1:54323.
Database Migrations
Migrations are stored in supabase/migrations/ and executed sequentially:
0001_init.sql: Core schema (organizations,projects,feedback_items, RLS policies).0002_storage.sql: Storage bucket policies forfeedback-screenshots.0003_defaults.sql: Default prompt templates per project.0004_fix_membership_recursion.sql: Non-recursive RLS policy optimization.0005_project_key_salt.sql: Cryptographic salting for project keys.0006_attachment.sql: Diagnostic file attachments support.0007_cli_sessions.sql: CLI token sessions tracking.0008_optional_screenshot.sql: Nullable screenshots for pure-text bug reports.0009_billing.sql: Stripe billing schema and customer metadata.
Migration Rule
Never edit an existing migration file in-place once it has been applied to the remote project. Always create a new sequentially numbered migration file (e.g. 0010_my_change.sql).
Edge Functions
Edge Functions run on Deno and TypeScript:
1. ingest-feedback
- Authentication:
verify_jwt = false. The caller is an anonymous iOS/macOS client identified byproject_key. - Logic: Resolves project, checks rate limits, writes raw/annotated screenshots to storage, and writes
feedback_items.
2. create-github-issue
- Authentication: Caller's JWT required.
- Logic: Uses a GitHub App token or user token to create an issue on GitHub populated with formatted diagnostics, screenshot links, and coding agent prompts.
3. Billing Functions
create-checkout-session: Generates Stripe Checkout session.create-portal-session: Generates Stripe Customer Portal session.stripe-webhook: VerifiesStripe-Signatureand synchronizes customer plan status and seat count.create-checkout-session: owner-only, per-seat Team plan (quantity = member count).sync-billing-seats: Called best-effort after membership changes to keep a subscription's quantity equal to the member count.501until Stripe is configured.
4. send-push
- Authentication:
verify_jwt = false; the caller is the database (pg_nettrigger in0017_notifications.sql), authenticated by thex-push-secretheader matchingPUSH_WEBHOOK_SECRET. - Logic: Loads one
notificationsrow and sends it over APNs to the recipient's registered iOS Portal devices, dropping tokens APNs reports as dead. Dormant until the Vault secrets andAPNS_*secrets are set (README, "Turning on push notifications").
Teams and notifications
0016_teams.sql: invitations and every membership change go through SECURITY DEFINER functions (create_invitation,accept_invitation,update_member_role,remove_member,create_organization,delete_organization,organization_members). A client can't writemembershipsdirectly.0017_notifications.sql: triggers onfeedback_items,feedback_eventsandmembershipsfan out onenotificationsrow per member (never to the actor, respectingnotification_preferences.muted_kinds). The table is in thesupabase_realtimepublication for the dashboard's live bell. See DESIGN.md §9.