Repository navigation
Data Management Backend
'
Relevant source files
The following files were used as context for generating this wiki page:
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
The database is structured around several key modules: User Auth/Subscriptions, Gigs (Freelance), Projects (Open-Source), and GitHub Integrations.
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"
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
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
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]
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
RLS is the primary security mechanism. Tables are restricted by default, and policies must be explicitly defined to allow access based on auth.uid().
-
Owner-Only:
USING (auth.uid() = user_id) -
Public Read:
USING (visibility = 'public') -
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
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.
-
Create New Migration: Run
npx supabase migration new <name>. -
Define Schema & RLS: Add
CREATE TABLEandCREATE POLICYstatements in the same file. -
Apply Locally: Run
npx supabase db push. - 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.tsSources: CLAUDE.md:196-200, CLAUDE.md:92-95
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 theirauth.uid().
Sources: supabase/migrations/20250903061440_108d275d-5dbc-41ff-9ca7-b72fca7b7707.sql:61-64, supabase/migrations/20250813062113-.sql:82-84
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.
Relevant source files
The following files were used as context for generating this wiki page:
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
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_KEYis 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
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
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
The project utilizes four standardized patterns for securing tables based on ownership, visibility, or membership roles.
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
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
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
Grants permissions based on specific roles within an organization, such as 'owner' or 'admin'.
Sources: CLAUDE.md:336-336
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
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 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
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
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
Relevant source files
The following files were used as context for generating this wiki page:
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
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.
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
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
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
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
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
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
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
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
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
Relevant source files
The following files were used as context for generating this wiki page:
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
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.
| 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
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
Every Edge Function in the project follows a standardized structure to ensure security, CORS compliance, and robust error handling.
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]
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
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
A primary use case for Edge Functions in Colabs is the github-issues function. This function performs the following steps:
- Validates the user's JWT from the
Authorizationheader. - Retrieves the user's active
github_integrationsand associatedaccess_tokenfrom a secured table (github_integration_secrets). - Fetches open issues from repositories where
allow_collaborationis enabled. - Transforms GitHub's API response into a unified format including
priorityandcategorylabels.
Sources: supabase/functions/github-issues/index.ts:46-150
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
Edge Functions are managed via the Supabase CLI.
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 = falseSources: CLAUDE.md:323-324
| 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
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.
Relevant source files
The following files were used as context for generating this wiki page:
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.
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 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
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
The upload process follows a standardized flow involving client-side validation, direct storage transmission, and database reference updates.
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
Sources: src/pages/SubmitProposal.tsx:112-167, CLAUDE.md:464-466
Project logos are handled within the CreateProjectDialog. The system performs specific checks before initiating the upload:
- Size Restriction: Maximum 2MB.
-
MIME Type Validation: Allowed types include
image/jpeg,image/png,image/webp, andimage/gif. -
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
Resumes are managed in SubmitProposal.tsx. This module implements more stringent validation due to the sensitive nature of the documents:
- Size Restriction: Maximum 5MB (frontend UI check) or 10MB (submission logic check).
-
File Extensions: Restricted to
pdf,doc, anddocx. -
Pathing: Files are stored in the
resumesbucket 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
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-Typeheader. - 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
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.
colabs.v2 · Built by SpaceyaTech · Live App · Report an Issue · Wiki Home
This wiki is open source. To suggest edits, open an issue or PR on the source repo.
- Introduction to Colabs
- Local Environment Setup
- Configuration & Secrets
- File Tree & Repository Layout
- GitHub OAuth & Repository Sync
- Gig Marketplace Engine
- Project Discovery & Explorer
- Issue Claiming & Kanban Boards
- Database Schema & Migration Guide
- Row Level Security (RLS) Patterns
- Data Fetching & TanStack Query
- Edge Functions & Deno Runtime
- Storage & File Uploads