Skip to content

Data Management Backend

jumalaw98 edited this page May 28, 2026 · 1 revision

'

Data Management & Backend

Database Schema & Migration Guide

Relevant source files

The following files were used as context for generating this wiki page:

Database Schema & Migration Guide

Introduction

The Colabs database is built on PostgreSQL and hosted via Supabase, serving as the primary persistence layer for a React-based single-page application. The system follows a "no custom backend" architecture, where all server-side logic is handled by Supabase Edge Functions, and security is enforced at the database level through Row Level Security (RLS) policies.

This guide outlines the core schema structure, relationship models, and the append-only migration workflow required to maintain data integrity across the platform's features, including project management, gig marketplaces, and GitHub integration.

Sources: CLAUDE.md:13-17, CLAUDE.md:120-125

Database Architecture & Core Entities

The database is structured around several key modules: User Auth/Subscriptions, Gigs (Freelance), Projects (Open-Source), and GitHub Integrations.

Entity Relationship Overview

The following diagram illustrates the primary relationships between the core tables in the public schema.

erDiagram
    projects ||--o{ proposals : "receives"
    proposals ||--o{ proposal_milestones : "contains"
    github_integrations ||--o{ github_repositories : "manages"
    organizations ||--o{ organization_members : "has"
    organizations ||--o{ organization_integrations : "configures"
    teams ||--o{ team_members : "comprises"
    teams ||--o{ team_projects : "works_on"
    projects ||--o{ team_projects : "assigned_to"
Loading

The schema establishes a clear separation between open-source projects and freelance gigs, though both interact with a unified proposal and contribution system.

Sources: src/integrations/supabase/types.ts:47-490, supabase/migrations/20250813062113-.sql:1-30

Table Definitions

1. Projects and Gigs

The platform distinguishes between collaborative projects and paid gigs. Projects support various visibility levels (public, unlisted, invite-only) and types (open-source, private, hybrid).

Table Field Type Constraints Description
projects id UUID PRIMARY KEY Unique identifier for the project.
projects project_type TEXT CHECK (open-source, private, hybrid) The nature of the collaboration.
projects status TEXT CHECK (active, paused, completed, cancelled) Current project lifecycle state.
gigs budget_value NUMBER NOT NULL Numeric representation of the gig's budget.
gigs is_urgent BOOLEAN DEFAULT false Flags high-priority freelance opportunities.

Sources: supabase/migrations/20250903061440_108d275d-5dbc-41ff-9ca7-b72fca7b7707.sql:2-25, src/integrations/supabase/types.ts:117-158

2. Proposals and Milestones

The proposal system allows users to apply for projects or gigs with structured payment terms.

graph TD
    A[Proposals Table] -->|proposal_id| B[Proposal Milestones]
    A -->|user_id| C[Auth Users]
    A -->|project_id| D[Projects/Gigs]
Loading

Proposals Schema Detail:

CREATE TABLE public.proposals (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL,
  project_id TEXT NOT NULL,
  payment_type TEXT NOT NULL CHECK (payment_type IN ('milestone', 'project')),
  total_amount INTEGER,
  status TEXT NOT NULL DEFAULT 'submitted'
);

Sources: supabase/migrations/20250813062113-.sql:2-15, src/integrations/supabase/types.ts:389-415

Security: Row Level Security (RLS)

RLS is the primary security mechanism. Tables are restricted by default, and policies must be explicitly defined to allow access based on auth.uid().

Canonical RLS Patterns

  1. Owner-Only: USING (auth.uid() = user_id)
  2. Public Read: USING (visibility = 'public')
  3. Membership-Based: Using security definer functions like is_team_member(auth.uid(), team_id).

Example: Proposals RLS

ALTER TABLE public.proposals ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Users can view their own proposals"
ON public.proposals FOR SELECT
USING (auth.uid() = user_id);

Sources: CLAUDE.md:120-136, supabase/migrations/20250813062113-.sql:35-43

Migration Workflow

The project uses an append-only migration strategy. Existing migration files must never be edited; instead, new changes must be applied via new SQL files.

Migration Steps

  1. Create New Migration: Run npx supabase migration new <name>.
  2. Define Schema & RLS: Add CREATE TABLE and CREATE POLICY statements in the same file.
  3. Apply Locally: Run npx supabase db push.
  4. Update Types: Regenerate TypeScript definitions to keep the frontend in sync.
# Type generation command
npx supabase gen types typescript --project-id your-project-ref > src/integrations/supabase/types.ts

Sources: CLAUDE.md:196-200, CLAUDE.md:92-95

Storage Buckets

The database schema is complemented by Supabase Storage buckets for handling file uploads.

  • project-logos: Public bucket for storing project branding images.
  • resumes: Private bucket for storing proposal attachments, secured such that users can only access folders named after their auth.uid().

Sources: supabase/migrations/20250903061440_108d275d-5dbc-41ff-9ca7-b72fca7b7707.sql:61-64, supabase/migrations/20250813062113-.sql:82-84

Summary

The Colabs database schema is designed for scalability and security in a serverless environment. By leveraging PostgreSQL's native features like CHECK constraints and RLS, the system ensures that business logic and security are enforced directly at the data layer. Developers must adhere to the append-only migration policy and consistently update the TypeScript types to maintain the integrity of the application's data flow.

Row Level Security (RLS) Patterns

Relevant source files

The following files were used as context for generating this wiki page:

Row Level Security (RLS) Patterns

Row Level Security (RLS) serves as the primary security enforcement layer for the Colabs platform. It is a non-optional architectural requirement where PostgreSQL evaluates security policies against a user's auth.uid() before returning any data. This ensures that data access is restricted at the database level, preventing unauthorized access even if client-side checks are bypassed.

Sources: CLAUDE.md:144-144, CLAUDE.md:147-152

Core Architectural Principles

In the Colabs project, RLS is implemented as a strict security layer with the following mandates:

  • Mandatory Enablement: Every new table must have RLS enabled and at least one policy defined in the same migration file. A table with RLS enabled but no policies will return zero rows to all users.
  • Security Definer Functions: To avoid recursive evaluation and complex subqueries within policies, the system utilizes "Security Definer" functions such as is_team_member().
  • Service Role Bypass: The SUPABASE_SERVICE_ROLE_KEY is the only mechanism that bypasses RLS, and it is strictly reserved for use within Supabase Edge Functions.

Sources: CLAUDE.md:154-157, supabase/migrations/20260302060455_c01aff83-f5d1-4435-ae10-dac74c367ddf.sql:40-54

Data Access Flow

The following diagram illustrates how RLS intercepts a client request to ensure only authorized data is returned.

graph TD
    User[User/Client] --> Query[Supabase Query]
    Query --> Postgres{Postgres Engine}
    Postgres --> RLS_Check{RLS Policy Check}
    RLS_Check -- auth.uid matches --> Allow[Return Data]
    RLS_Check -- No Match --> Empty[Return Empty Array]
    EdgeFn[Edge Function] -- Service Role Key --> Bypass[Bypass RLS]
    Bypass --> Allow
Loading

This diagram shows the decision path for data retrieval where RLS evaluates credentials before data access. Sources: CLAUDE.md:149-150, CLAUDE.md:158-158

Canonical RLS Patterns

The project utilizes four standardized patterns for securing tables based on ownership, visibility, or membership roles.

1. Owner-Only Access

The simplest pattern where access is granted only if the record's user_id or creator_id matches the authenticated user's ID.

-- Pattern for personal data
CREATE POLICY "Users can access own rows"
  ON public.your_table
  USING (auth.uid() = user_id);

Sources: CLAUDE.md:316-321, supabase/migrations/20250813062113-.sql:47-49

2. Public Read / Owner Write

Commonly used for shared entities like "Projects". Anyone can view public records, but only the creator can modify or delete them.

Operation Policy Condition
SELECT USING (visibility = 'public' OR visibility = 'unlisted')
INSERT/UPDATE/DELETE USING (auth.uid() = creator_id)

Sources: supabase/migrations/20250903061440_108d275d-5dbc-41ff-9ca7-b72fca7b7707.sql:40-62, CLAUDE.md:328-330

3. Membership-Based Access

Used for collaborative features where access depends on being part of a specific team. This pattern relies on the is_team_member security definer function.

-- Policy for team-related tables
CREATE POLICY "Members can view their teams" ON public.teams
FOR SELECT USING (public.is_team_member(auth.uid(), id));

Sources: supabase/migrations/20260302060455_c01aff83-f5d1-4435-ae10-dac74c367ddf.sql:61-62, CLAUDE.md:333-333

4. Role-Based Access Control (RBAC)

Grants permissions based on specific roles within an organization, such as 'owner' or 'admin'.

Sources: CLAUDE.md:336-336

Implementation Examples

Project Table Security

The projects table demonstrates a hybrid approach combining public visibility with owner-restricted modifications.

ALTER TABLE public.projects ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Anyone can view public projects"
ON public.projects FOR SELECT
USING (visibility = 'public' OR visibility = 'unlisted');

CREATE POLICY "Users can create projects"
ON public.projects FOR INSERT
WITH CHECK (auth.uid() = creator_id);

Sources: supabase/migrations/20250903061440_108d275d-5dbc-41ff-9ca7-b72fca7b7707.sql:36-53

Storage Security

RLS patterns also extend to Supabase Storage buckets, specifically for project logos and user resumes.

Bucket Operation Security Condition
project-logos SELECT USING (bucket_id = 'project-logos') (Public)
project-logos INSERT WITH CHECK (auth.uid() IS NOT NULL) (Authenticated)
resumes ALL auth.uid()::text = (storage.foldername(name))[1] (Folder-owner only)

Sources: supabase/migrations/20250903061440_108d275d-5dbc-41ff-9ca7-b72fca7b7707.sql:69-85, supabase/migrations/20250813062113-.sql:102-124

Security Definer Functions Logic

Security definer functions are critical for complex checks involving joins to prevent recursive policy evaluation.

sequenceDiagram
    participant User as "Authenticated User"
    participant DB as "PostgreSQL"
    participant Func as "is_team_member (Security Definer)"
    
    User->>DB: SELECT * FROM teams WHERE id = 'XYZ'
    DB->>Func: Call with auth.uid() and team_id
    Note over Func: Checks team_members table OR teams (creator)
    Func-->>DB: Returns Boolean (True/False)
    DB-->>User: Result or Empty Set
Loading

This sequence shows how the security definer function abstracts the membership check away from the primary RLS policy to ensure performance and security. Sources: supabase/migrations/20260302060455_c01aff83-f5d1-4435-ae10-dac74c367ddf.sql:40-54, CLAUDE.md:155-155

Conclusion

The RLS patterns in Colabs establish a robust defense-in-depth strategy. By enforcing security at the database row level and utilizing standardized SQL policies and security definer functions, the project ensures that user data and collaborative environments remain isolated and secure against unauthorized access. Significant enforcement is handled via migrations, ensuring security is updated alongside schema changes.

Sources: CLAUDE.md:147-152, CLAUDE.md:312-314

Data Fetching & TanStack Query

Relevant source files

The following files were used as context for generating this wiki page:

Data Fetching & TanStack Query

Colabs leverages TanStack Query (v5) as its primary asynchronous state management layer to handle data fetching, caching, and synchronization with the Supabase backend. The project adheres to a "Components receive data — they don't fetch it" mental model, where logic is centralized in custom hooks and container components while presentational components remain decoupled from the data lifecycle.

Sources: CLAUDE.md:144-144, CLAUDE.md:164-164

Architecture and Data Flow

The data architecture is built on a "Single Source of Truth" pattern. All server state is managed via TanStack Query hooks, eliminating the need for useEffect and useState for data fetching. Data flows from Supabase (PostgreSQL, Edge Functions, or Storage) through custom hooks into page-level components, which then pass relevant data down to child components.

Core Fetching Lifecycle

flowchart TD
    A[UI Component] -->|Calls Hook| B(Custom Hook)
    B -->|useQuery/useMutation| C{TanStack Query Cache}
    C -->|Cache Miss| D[Supabase Client / Edge Function]
    D -->|PostgreSQL Query| E[(Supabase DB)]
    E -->|Data/Error| D
    D -->|Return Result| C
    C -->|Update State| B
    B -->|Return Data/Loading/Error| A
Loading

The diagram above illustrates the standard request lifecycle where TanStack Query acts as a middle layer between the UI and the Supabase backend.

Sources: CLAUDE.md:18-20, CLAUDE.md:164-166, CLAUDE.md:195-207

Implementation Patterns

Standard Query Pattern

Queries are implemented using the useQuery hook with explicit column selection. SELECT * is strictly forbidden to prevent accidental exposure of sensitive data. Queries are often gated using the enabled property to prevent execution before necessary dependencies (like user IDs or session tokens) are available.

// Example from project documentation
export function useMyData(userId: string | undefined) {
  return useQuery({
    queryKey: ['my-data', userId],
    queryFn: async () => {
      const { data, error } = await supabase
        .from('table')
        .select('id, name, status') // Explicit columns
        .eq('user_id', userId!);
      if (error) throw error;
      return data ?? [];
    },
    enabled: !!userId, // Gated dependency
  });
}

Sources: CLAUDE.md:195-207, CLAUDE.md:218-228

Mutation and Cache Invalidation

State changes are handled via useMutation. Upon successful completion, the queryClient.invalidateQueries method is used to trigger a re-fetch of related data, ensuring the UI stays synchronized with the database.

Mutation Event Action Taken Source
onSuccess Call invalidateQueries for specific keys and show success toast CLAUDE.md:209-216
onError Display error message via toast notification CLAUDE.md:216-216

Sources: CLAUDE.md:209-217

Edge Function Integration

For complex logic or operations requiring the SERVICE_ROLE_KEY (bypassing RLS), the project utilizes Supabase Edge Functions. These are invoked via the client and integrated into TanStack Query hooks.

sequenceDiagram
    participant UI as Page Component
    participant Hook as useGitHubIssues
    participant Supa as Supabase Client
    participant Edge as Edge Function (Deno)
    participant GH as GitHub API
    
    UI->>Hook: useQuery(['github-issues'])
    Hook->>Supa: functions.invoke('github-issues')
    Supa->>Edge: POST request + Auth Header
    Edge->>GH: Fetch repo issues
    GH-->>Edge: JSON Response
    Edge-->>Supa: Transformed Data
    Supa-->>Hook: Return Data
    Hook-->>UI: Render Issues List
Loading

This flow is notably used in the github-issues and github-project-data functions to sync external data into the Colabs dashboard.

Sources: src/pages/Project.tsx:143-152, supabase/functions/github-issues/index.ts:1-120

Query Key Management

The project uses a structured naming convention for query keys to facilitate granular cache invalidation and nesting.

Pattern Example Key Usage
List ["gigs"] General collection fetching
User-scoped ["my-gigs", userId] Authenticated user data
Single Item ["gig", gigId] Detail view fetching
Nested ["proposals", gigId] Related child records

Sources: CLAUDE.md:237-242

Data Models and Components

Key components leverage these fetching patterns to manage complex UI states, such as Kanban boards and multi-step forms.

Component Primary Data Source Handling Logic
IssuesTab useClaimedIssues hook Uses DnD (Drag and Drop) to update status via mutations
AllIssues useGitHubIssues hook Handles filtering and local storage for "saved" issues
ProjectPage projects table + Edge Function Combines direct DB fetching with GitHub API data
SubmitProposal proposals & proposal_milestones Complex mutation handling with file uploads to Supabase Storage

Sources: src/components/dashboard/IssuesTab.tsx:390-410, src/pages/AllIssues.tsx:296-320, src/pages/Project.tsx:117-154, src/pages/SubmitProposal.tsx:115-180

Summary

Data fetching in Colabs is characterized by a strict separation of concerns and a heavy reliance on TanStack Query for state management. By centralizing Supabase interactions within custom hooks and utilizing Edge Functions for third-party integrations (like GitHub), the project maintains a clean, reactive architecture that ensures data consistency across the platform.

Sources: CLAUDE.md:144-144, CLAUDE.md:164-166

Edge Functions & Deno Runtime

Relevant source files

The following files were used as context for generating this wiki page:

Edge Functions & Deno Runtime

Introduction

Edge Functions in the Colabs project serve as the server-side logic layer, executing in a distributed environment powered by the Deno runtime. Unlike traditional Node.js environments, these functions are designed for low-latency execution and are integrated directly with the Supabase ecosystem. They handle complex server-side tasks such as interacting with external APIs (e.g., GitHub API), managing database writes that bypass Row Level Security (RLS) via the service role key, and processing authenticated requests from the React frontend.

The project utilizes these functions to bridge the gap between the client-side application and external services, ensuring that sensitive operations—like fetching GitHub issues or repository metadata—are performed securely and efficiently. All server-side logic resides within the supabase/functions/ directory and follows specific patterns tailored for the Deno environment.

Sources: CLAUDE.md:14-17, README.md:112-120

Deno Runtime Architecture

The Colabs backend relies exclusively on the Deno runtime rather than Node.js. This choice introduces specific architectural patterns for module imports, environment variable access, and HTTP server handling.

Key Differences from Node.js

Feature Deno Implementation (Colabs) Node.js Equivalent
Env Variables Deno.env.get("VAR_NAME") process.env.VAR_NAME
Imports URL-based (e.g., https://esm.sh/...) CommonJS or npm-based import
Server Deno.serve(async (req) => { ... }) app.listen() (Express)

Sources: CLAUDE.md:270-282

Dependency Management

Dependencies are imported directly via URLs, typically using the esm.sh CDN to ensure compatibility with the Deno environment. For example, the Supabase client is initialized using:

import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';

Sources: supabase/functions/github-issues/index.ts:2


Edge Function Implementation Pattern

Every Edge Function in the project follows a standardized structure to ensure security, CORS compliance, and robust error handling.

Request Lifecycle

The following diagram illustrates the standard execution flow of an Edge Function request:

flowchart TD
    Req[Incoming HTTP Request] --> CORS{Is Method OPTIONS?}
    CORS -- Yes --> Preflight[Return CORS Headers]
    CORS -- No --> Auth[Verify JWT/Auth Header]
    Auth -- Invalid --> Err401[Return 401 Unauthorized]
    Auth -- Valid --> Logic[Execute Business Logic]
    Logic --> DB[Supabase DB / External API]
    DB --> Res[JSON Response + CORS]
    Logic -- Exception --> Err500[Return Internal Server Error]
Loading

The logic involves an initial CORS preflight check using Access-Control-Allow-Origin: '*' to allow requests from the frontend application.

Sources: supabase/functions/github-issues/index.ts:4-44, CLAUDE.md:288-310

Security and RLS Bypassing

Edge Functions often use the SUPABASE_SERVICE_ROLE_KEY to initialize a Supabase client. This key allows the function to bypass Row Level Security (RLS) policies, which is necessary for administrative tasks or when the function must access data that the authenticated user cannot reach directly through standard client-side queries.

Sources: CLAUDE.md:300-305, supabase/functions/github-issues/index.ts:41-43


Integration Examples

GitHub Issues Fetching

A primary use case for Edge Functions in Colabs is the github-issues function. This function performs the following steps:

  1. Validates the user's JWT from the Authorization header.
  2. Retrieves the user's active github_integrations and associated access_token from a secured table (github_integration_secrets).
  3. Fetches open issues from repositories where allow_collaboration is enabled.
  4. Transforms GitHub's API response into a unified format including priority and category labels.

Sources: supabase/functions/github-issues/index.ts:46-150

Function Invocation from Frontend

The React frontend invokes these functions using the Supabase client's functions.invoke method. For instance, the ProjectPage component fetches repository data:

const { data, error } = await supabase.functions.invoke('github-project-data', {
  body: { repoUrl: project.github_repo_url },
});

Sources: src/pages/Project.tsx:143-146, CLAUDE.md:255-260


Deployment and Configuration

Edge Functions are managed via the Supabase CLI.

Configuration (config.toml)

Webhook endpoints (like those for GitHub or Stripe) require a specific configuration to disable JWT verification, as they rely on signature verification instead.

# Example config requirement
verify_jwt = false

Sources: CLAUDE.md:323-324

Management Commands

Command Description
npx supabase functions serve <name> Locally test an edge function
npx supabase functions deploy <name> Deploy to the Supabase cloud
npx supabase secrets set KEY=value Set environment variables (secrets)

Sources: CLAUDE.md:104-108

Conclusion

Edge Functions and the Deno runtime form a critical component of the Colabs architecture, enabling secure, server-side processing without the overhead of a dedicated Node.js server. By leveraging Deno's modern features and Supabase's seamless integration, the system handles complex integrations like GitHub synchronization while maintaining strict security through the controlled use of service role keys and JWT validation.

Storage & File Uploads

Relevant source files

The following files were used as context for generating this wiki page:

Storage & File Uploads

Introduction

The Colabs platform utilizes Supabase Storage to manage persistent file assets, specifically focusing on project branding and contributor documentation. The system is designed as a serverless architecture where the React frontend communicates directly with Supabase Storage buckets, governed by PostgreSQL Row Level Security (RLS) policies. This ensures that file access and modifications are strictly controlled based on user authentication and ownership.

The primary use cases for storage include the management of project logos for branding and the submission of resumes/CVs during the proposal process. All uploads are subject to client-side validation and server-side policy enforcement to maintain security and storage efficiency.

Storage Architecture & Buckets

The project defines specific storage buckets within the Supabase ecosystem. Each bucket is configured with distinct visibility and access rules depending on the nature of the data it hosts.

Bucket Definitions

Bucket ID Name Public Access Purpose
project-logos project-logos True Stores branding images for projects; publicly readable.
resumes resumes False Stores sensitive contributor CVs; restricted access.

Sources: supabase/migrations/20250903061440_108d275d-5dbc-41ff-9ca7-b72fca7b7707.sql:53, supabase/migrations/20250813062113-.sql:82

Security & RLS Policies

Storage security is enforced through RLS policies on the storage.objects table. Policies are categorized by bucket ID and user session.

  • Project Logos: Publicly viewable by anyone. Uploads, updates, and deletions are restricted to authenticated users.
  • Resumes: Strictly private. Access is limited to the owner of the file, enforced by checking if the user's auth.uid() matches the first segment of the file path (e.g., user_id/filename).

Sources: supabase/migrations/20250903061440_108d275d-5dbc-41ff-9ca7-b72fca7b7707.sql:56-74, supabase/migrations/20250813062113-.sql:87-111

File Upload Logic

The upload process follows a standardized flow involving client-side validation, direct storage transmission, and database reference updates.

Upload Flow Diagram

The following diagram illustrates the sequence of events when a user uploads a file (e.g., a resume) during a proposal submission.

sequenceDiagram
    participant U as User Interface
    participant S as Supabase Storage
    participant DB as PostgreSQL DB
    
    U->>U: Validate MIME type & size
    U->>S: Upload file to bucket/{uid}/{timestamp}.ext
    S-->>U: Return file path/URL
    U->>DB: Insert record with file_path reference
    DB-->>U: Confirm transaction
Loading

Sources: src/pages/SubmitProposal.tsx:112-167, CLAUDE.md:464-466

Implementation Details: Project Logos

Project logos are handled within the CreateProjectDialog. The system performs specific checks before initiating the upload:

  1. Size Restriction: Maximum 2MB.
  2. MIME Type Validation: Allowed types include image/jpeg, image/png, image/webp, and image/gif.
  3. Naming Convention: Files are named using the pattern ${user.id}-${Date.now()}.${fileExt}.

Sources: src/components/CreateProjectDialog.tsx:119-132, src/components/CreateProjectDialog.tsx:159-170

Implementation Details: Resumes

Resumes are managed in SubmitProposal.tsx. This module implements more stringent validation due to the sensitive nature of the documents:

  1. Size Restriction: Maximum 5MB (frontend UI check) or 10MB (submission logic check).
  2. File Extensions: Restricted to pdf, doc, and docx.
  3. Pathing: Files are stored in the resumes bucket under a folder named after the user's ID: user_id/timestamp.ext.

Sources: src/pages/SubmitProposal.tsx:115-144, src/pages/SubmitProposal.tsx:432-446

Security Best Practices

The project maintains strict security rules for file handling to prevent unauthorized access and malicious uploads:

  • Magic Byte Verification: The system architecture specifies that server-side magic byte checks should be performed (via Edge Functions) to verify file integrity beyond just the Content-Type header.
  • No Client-Side Secrets: All storage interactions use the client's own JWT. Service role keys (which bypass RLS) are strictly confined to Edge Functions and never exposed to the frontend.
  • Path-Based Isolation: Private buckets use path-based isolation where the folder name corresponds to the auth.uid(), preventing users from accessing or overwriting other users' files.

Sources: CLAUDE.md:464-466, CLAUDE.md:214-220, supabase/migrations/20250813062113-.sql:87-111

Summary

Storage and file uploads in Colabs are partitioned into public branding assets (logos) and private contributor documents (resumes). By leveraging Supabase Storage alongside PostgreSQL RLS, the platform ensures that files are served efficiently while maintaining strict ownership boundaries. Validation logic distributed between the React frontend and Supabase policies provides a multi-layered defense against invalid file types and unauthorized access.

Clone this wiki locally