Nexus - Full Talent Marketplace System

cgen-8b270903186d4504a665f8736c70ab1c
This commit is contained in:
Builder.io 2025-11-12 03:32:29 +00:00
parent 2e7a74bee8
commit 813b33437c

View file

@ -0,0 +1,406 @@
-- Nexus: Talent Marketplace
-- Commercial bridge between Foundation (community) and Corp (clients)
-- Includes: Creator Profiles, Opportunities, Applications, Messaging, Payments/Commissions
create extension if not exists "pgcrypto";
-- ============================================================================
-- CREATOR PROFILES & PORTFOLIO
-- ============================================================================
create table if not exists public.nexus_creator_profiles (
user_id uuid primary key references public.user_profiles(id) on delete cascade,
headline text, -- e.g., "Game Developer | Unreal Engine Specialist"
bio text,
profile_image_url text,
skills text[] not null default '{}', -- e.g., ['Unreal Engine', 'C++', 'Game Design']
experience_level text not null default 'intermediate' check (experience_level in ('beginner', 'intermediate', 'advanced', 'expert')),
hourly_rate numeric(10, 2),
portfolio_url text,
availability_status text not null default 'available' check (availability_status in ('available', 'busy', 'unavailable')),
availability_hours_per_week int,
verified boolean not null default false,
total_earnings numeric(12, 2) not null default 0,
rating numeric(3, 2), -- average rating
review_count int not null default 0,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create index if not exists nexus_creator_profiles_verified_idx on public.nexus_creator_profiles (verified);
create index if not exists nexus_creator_profiles_availability_idx on public.nexus_creator_profiles (availability_status);
create index if not exists nexus_creator_profiles_skills_gin on public.nexus_creator_profiles using gin (skills);
create index if not exists nexus_creator_profiles_rating_idx on public.nexus_creator_profiles (rating desc);
-- Creator Portfolio Projects
create table if not exists public.nexus_portfolio_items (
id uuid primary key default gen_random_uuid(),
user_id uuid not null references public.user_profiles(id) on delete cascade,
title text not null,
description text,
project_url text,
image_url text,
skills_used text[] not null default '{}',
featured boolean not null default false,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create index if not exists nexus_portfolio_items_user_idx on public.nexus_portfolio_items (user_id);
create index if not exists nexus_portfolio_items_featured_idx on public.nexus_portfolio_items (featured);
-- Creator Endorsements (peer-to-peer skill validation)
create table if not exists public.nexus_skill_endorsements (
id uuid primary key default gen_random_uuid(),
creator_id uuid not null references public.user_profiles(id) on delete cascade,
endorsed_by uuid not null references public.user_profiles(id) on delete cascade,
skill text not null,
created_at timestamptz not null default now(),
unique(creator_id, endorsed_by, skill)
);
create index if not exists nexus_skill_endorsements_creator_idx on public.nexus_skill_endorsements (creator_id);
create index if not exists nexus_skill_endorsements_endorsed_by_idx on public.nexus_skill_endorsements (endorsed_by);
-- ============================================================================
-- OPPORTUNITIES (JOBS/COLLABS)
-- ============================================================================
create table if not exists public.nexus_opportunities (
id uuid primary key default gen_random_uuid(),
posted_by uuid not null references public.user_profiles(id) on delete cascade,
title text not null,
description text not null,
category text not null, -- 'development', 'design', 'audio', 'marketing', etc.
required_skills text[] not null default '{}',
budget_type text not null check (budget_type in ('hourly', 'fixed', 'range')),
budget_min numeric(12, 2),
budget_max numeric(12, 2),
timeline_type text not null default 'flexible' check (timeline_type in ('urgent', 'short-term', 'long-term', 'ongoing', 'flexible')),
duration_weeks int,
location_requirement text default 'remote' check (location_requirement in ('remote', 'onsite', 'hybrid')),
required_experience text default 'any' check (required_experience in ('any', 'beginner', 'intermediate', 'advanced', 'expert')),
company_name text,
status text not null default 'open' check (status in ('open', 'in_progress', 'filled', 'closed', 'cancelled')),
application_count int not null default 0,
selected_creator_id uuid references public.user_profiles(id) on delete set null,
views int not null default 0,
is_featured boolean not null default false,
published_at timestamptz not null default now(),
closed_at timestamptz,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create index if not exists nexus_opportunities_posted_by_idx on public.nexus_opportunities (posted_by);
create index if not exists nexus_opportunities_status_idx on public.nexus_opportunities (status);
create index if not exists nexus_opportunities_category_idx on public.nexus_opportunities (category);
create index if not exists nexus_opportunities_skills_gin on public.nexus_opportunities using gin (required_skills);
create index if not exists nexus_opportunities_featured_idx on public.nexus_opportunities (is_featured);
create index if not exists nexus_opportunities_created_idx on public.nexus_opportunities (created_at desc);
-- ============================================================================
-- APPLICATIONS & MATCHING
-- ============================================================================
create table if not exists public.nexus_applications (
id uuid primary key default gen_random_uuid(),
opportunity_id uuid not null references public.nexus_opportunities(id) on delete cascade,
creator_id uuid not null references public.user_profiles(id) on delete cascade,
status text not null default 'submitted' check (status in ('submitted', 'reviewing', 'accepted', 'rejected', 'hired', 'archived')),
cover_letter text,
proposed_rate numeric(12, 2),
proposal text, -- detailed proposal/pitch
application_questions jsonb, -- answers to custom questions if any
viewed_at timestamptz,
responded_at timestamptz,
response_message text,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique(opportunity_id, creator_id)
);
create index if not exists nexus_applications_opportunity_idx on public.nexus_applications (opportunity_id);
create index if not exists nexus_applications_creator_idx on public.nexus_applications (creator_id);
create index if not exists nexus_applications_status_idx on public.nexus_applications (status);
create index if not exists nexus_applications_created_idx on public.nexus_applications (created_at desc);
-- Application Reviews/Ratings
create table if not exists public.nexus_reviews (
id uuid primary key default gen_random_uuid(),
application_id uuid not null references public.nexus_applications(id) on delete cascade,
opportunity_id uuid not null references public.nexus_opportunities(id) on delete cascade,
reviewer_id uuid not null references public.user_profiles(id) on delete cascade,
creator_id uuid not null references public.user_profiles(id) on delete cascade,
rating int not null check (rating between 1 and 5),
review_text text,
created_at timestamptz not null default now(),
unique(application_id, reviewer_id)
);
create index if not exists nexus_reviews_creator_idx on public.nexus_reviews (creator_id);
create index if not exists nexus_reviews_reviewer_idx on public.nexus_reviews (reviewer_id);
-- ============================================================================
-- CONTRACTS & ORDERS
-- ============================================================================
create table if not exists public.nexus_contracts (
id uuid primary key default gen_random_uuid(),
opportunity_id uuid references public.nexus_opportunities(id) on delete set null,
creator_id uuid not null references public.user_profiles(id) on delete cascade,
client_id uuid not null references public.user_profiles(id) on delete cascade,
title text not null,
description text,
contract_type text not null check (contract_type in ('one-time', 'retainer', 'hourly')),
total_amount numeric(12, 2) not null,
aethex_commission_percent numeric(5, 2) not null default 20,
aethex_commission_amount numeric(12, 2) not null default 0,
creator_payout_amount numeric(12, 2) not null default 0,
status text not null default 'pending' check (status in ('pending', 'active', 'completed', 'disputed', 'cancelled')),
start_date timestamptz,
end_date timestamptz,
milestone_count int default 1,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create index if not exists nexus_contracts_creator_idx on public.nexus_contracts (creator_id);
create index if not exists nexus_contracts_client_idx on public.nexus_contracts (client_id);
create index if not exists nexus_contracts_status_idx on public.nexus_contracts (status);
-- Milestones (for progressive payments)
create table if not exists public.nexus_milestones (
id uuid primary key default gen_random_uuid(),
contract_id uuid not null references public.nexus_contracts(id) on delete cascade,
milestone_number int not null,
description text,
amount numeric(12, 2) not null,
due_date timestamptz,
status text not null default 'pending' check (status in ('pending', 'submitted', 'approved', 'paid', 'rejected')),
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique(contract_id, milestone_number)
);
-- Payments & Commission Tracking
create table if not exists public.nexus_payments (
id uuid primary key default gen_random_uuid(),
contract_id uuid not null references public.nexus_contracts(id) on delete cascade,
milestone_id uuid references public.nexus_milestones(id) on delete set null,
amount numeric(12, 2) not null,
creator_payout numeric(12, 2) not null,
aethex_commission numeric(12, 2) not null,
payment_method text not null default 'stripe', -- stripe, bank_transfer, paypal
payment_status text not null default 'pending' check (payment_status in ('pending', 'processing', 'completed', 'failed', 'refunded')),
payment_date timestamptz,
payout_date timestamptz,
stripe_payment_intent_id text,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create index if not exists nexus_payments_contract_idx on public.nexus_payments (contract_id);
create index if not exists nexus_payments_status_idx on public.nexus_payments (payment_status);
-- Commission Ledger (financial tracking)
create table if not exists public.nexus_commission_ledger (
id uuid primary key default gen_random_uuid(),
payment_id uuid references public.nexus_payments(id) on delete set null,
period_start date,
period_end date,
total_volume numeric(12, 2) not null,
total_commission numeric(12, 2) not null,
creator_payouts numeric(12, 2) not null,
aethex_revenue numeric(12, 2) not null,
status text not null default 'pending' check (status in ('pending', 'settled', 'disputed')),
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
-- ============================================================================
-- MESSAGING & COLLABORATION
-- ============================================================================
create table if not exists public.nexus_messages (
id uuid primary key default gen_random_uuid(),
conversation_id uuid,
sender_id uuid not null references public.user_profiles(id) on delete cascade,
recipient_id uuid not null references public.user_profiles(id) on delete cascade,
opportunity_id uuid references public.nexus_opportunities(id) on delete set null,
contract_id uuid references public.nexus_contracts(id) on delete set null,
message_text text not null,
is_read boolean not null default false,
read_at timestamptz,
created_at timestamptz not null default now()
);
create index if not exists nexus_messages_sender_idx on public.nexus_messages (sender_id);
create index if not exists nexus_messages_recipient_idx on public.nexus_messages (recipient_id);
create index if not exists nexus_messages_opportunity_idx on public.nexus_messages (opportunity_id);
create index if not exists nexus_messages_created_idx on public.nexus_messages (created_at desc);
-- Conversations (threads)
create table if not exists public.nexus_conversations (
id uuid primary key default gen_random_uuid(),
participant_1 uuid not null references public.user_profiles(id) on delete cascade,
participant_2 uuid not null references public.user_profiles(id) on delete cascade,
opportunity_id uuid references public.nexus_opportunities(id) on delete set null,
contract_id uuid references public.nexus_contracts(id) on delete set null,
subject text,
last_message_at timestamptz,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique(participant_1, participant_2, opportunity_id)
);
create index if not exists nexus_conversations_participants_idx on public.nexus_conversations (participant_1, participant_2);
-- ============================================================================
-- DISPUTES & RESOLUTION
-- ============================================================================
create table if not exists public.nexus_disputes (
id uuid primary key default gen_random_uuid(),
contract_id uuid not null references public.nexus_contracts(id) on delete cascade,
reported_by uuid not null references public.user_profiles(id) on delete cascade,
reason text not null,
description text,
evidence_urls text[] default '{}',
status text not null default 'open' check (status in ('open', 'reviewing', 'resolved', 'escalated')),
resolution_notes text,
resolved_by uuid references public.user_profiles(id) on delete set null,
resolved_at timestamptz,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create index if not exists nexus_disputes_contract_idx on public.nexus_disputes (contract_id);
create index if not exists nexus_disputes_status_idx on public.nexus_disputes (status);
-- ============================================================================
-- RLS POLICIES
-- ============================================================================
alter table public.nexus_creator_profiles enable row level security;
alter table public.nexus_portfolio_items enable row level security;
alter table public.nexus_skill_endorsements enable row level security;
alter table public.nexus_opportunities enable row level security;
alter table public.nexus_applications enable row level security;
alter table public.nexus_reviews enable row level security;
alter table public.nexus_contracts enable row level security;
alter table public.nexus_milestones enable row level security;
alter table public.nexus_payments enable row level security;
alter table public.nexus_commission_ledger enable row level security;
alter table public.nexus_messages enable row level security;
alter table public.nexus_conversations enable row level security;
alter table public.nexus_disputes enable row level security;
-- Creator Profiles: verified visible, own editable
create policy "Verified creator profiles visible to all" on public.nexus_creator_profiles
for select using (verified = true or auth.uid() = user_id or exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin'));
create policy "Users manage own creator profile" on public.nexus_creator_profiles
for all using (auth.uid() = user_id) with check (auth.uid() = user_id);
-- Portfolio: public for verified creators
create policy "Portfolio items visible when creator verified" on public.nexus_portfolio_items
for select using (
exists(select 1 from public.nexus_creator_profiles where user_id = user_id and verified = true) or
auth.uid() = user_id
);
create policy "Users manage own portfolio" on public.nexus_portfolio_items
for all using (auth.uid() = user_id) with check (auth.uid() = user_id);
-- Endorsements: all visible
create policy "Endorsements readable by all authenticated" on public.nexus_skill_endorsements
for select using (auth.role() = 'authenticated');
create policy "Users can endorse skills" on public.nexus_skill_endorsements
for insert with check (auth.uid() = endorsed_by);
-- Opportunities: open ones visible, own/applied visible to creator
create policy "Open opportunities visible to all" on public.nexus_opportunities
for select using (status = 'open' or auth.uid() = posted_by or
exists(select 1 from public.nexus_applications where opportunity_id = id and creator_id = auth.uid()));
create policy "Clients post opportunities" on public.nexus_opportunities
for insert with check (auth.uid() = posted_by);
create policy "Clients manage own opportunities" on public.nexus_opportunities
for update using (auth.uid() = posted_by);
-- Applications: involved parties see
create policy "Applications visible to applicant and poster" on public.nexus_applications
for select using (auth.uid() = creator_id or auth.uid() in (select posted_by from public.nexus_opportunities where id = opportunity_id));
create policy "Creators submit applications" on public.nexus_applications
for insert with check (auth.uid() = creator_id);
create policy "Applicants/posters update applications" on public.nexus_applications
for update using (auth.uid() = creator_id or auth.uid() in (select posted_by from public.nexus_opportunities where id = opportunity_id));
-- Reviews: visible to parties, admin
create policy "Reviews visible to involved" on public.nexus_reviews
for select using (auth.uid() = creator_id or auth.uid() = reviewer_id or exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin'));
-- Contracts: involved parties only
create policy "Contracts visible to parties" on public.nexus_contracts
for select using (auth.uid() = creator_id or auth.uid() = client_id or exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin'));
-- Messages: involved parties
create policy "Messages visible to parties" on public.nexus_messages
for select using (auth.uid() = sender_id or auth.uid() = recipient_id);
create policy "Users send messages" on public.nexus_messages
for insert with check (auth.uid() = sender_id);
-- Conversations: participants
create policy "Conversations visible to participants" on public.nexus_conversations
for select using (auth.uid() in (participant_1, participant_2));
-- Disputes: involved parties
create policy "Disputes visible to involved" on public.nexus_disputes
for select using (auth.uid() in (select creator_id from public.nexus_contracts where id = contract_id union select client_id from public.nexus_contracts where id = contract_id) or exists(select 1 from public.user_profiles where id = auth.uid() and user_type = 'admin'));
-- ============================================================================
-- TRIGGERS
-- ============================================================================
create or replace function public.set_updated_at()
returns trigger as $$
begin
new.updated_at = now();
return new;
end;
$$ language plpgsql;
create trigger nexus_creator_profiles_set_updated_at before update on public.nexus_creator_profiles for each row execute function public.set_updated_at();
create trigger nexus_portfolio_items_set_updated_at before update on public.nexus_portfolio_items for each row execute function public.set_updated_at();
create trigger nexus_opportunities_set_updated_at before update on public.nexus_opportunities for each row execute function public.set_updated_at();
create trigger nexus_applications_set_updated_at before update on public.nexus_applications for each row execute function public.set_updated_at();
create trigger nexus_contracts_set_updated_at before update on public.nexus_contracts for each row execute function public.set_updated_at();
create trigger nexus_milestones_set_updated_at before update on public.nexus_milestones for each row execute function public.set_updated_at();
create trigger nexus_payments_set_updated_at before update on public.nexus_payments for each row execute function public.set_updated_at();
create trigger nexus_commission_ledger_set_updated_at before update on public.nexus_commission_ledger for each row execute function public.set_updated_at();
create trigger nexus_conversations_set_updated_at before update on public.nexus_conversations for each row execute function public.set_updated_at();
create trigger nexus_disputes_set_updated_at before update on public.nexus_disputes for each row execute function public.set_updated_at();
-- ============================================================================
-- COMMENTS
-- ============================================================================
comment on table public.nexus_creator_profiles is 'Creator profiles with skills, rates, portfolio';
comment on table public.nexus_portfolio_items is 'Creator portfolio/project showcase';
comment on table public.nexus_skill_endorsements is 'Peer endorsements for skill validation';
comment on table public.nexus_opportunities is 'Job/collaboration postings by clients';
comment on table public.nexus_applications is 'Creator applications to opportunities';
comment on table public.nexus_reviews is 'Reviews/ratings for completed work';
comment on table public.nexus_contracts is 'Signed contracts with AeThex commission split';
comment on table public.nexus_milestones is 'Contract milestones for progressive payments';
comment on table public.nexus_payments is 'Payment transactions and commission tracking';
comment on table public.nexus_commission_ledger is 'Financial ledger for AeThex revenue tracking';
comment on table public.nexus_messages is 'Marketplace messaging between parties';
comment on table public.nexus_conversations is 'Message conversation threads';
comment on table public.nexus_disputes is 'Dispute resolution for contracts';