YeboJobs Product Requirements Document (PRD)
Product: YeboJobs - African Job Matching Platform
Version: 1.0
Last Updated: 2026-03-19
Generated From: Actual Codebase Analysis
1. Vision & Problem Statement
Problem
Africa faces a massive employment disconnect:
- Formal job market: University graduates and professionals struggle to find jobs that match their skills; employers waste time sifting through unqualified applicants
- Informal economy: Skilled workers (plumbers, electricians, beauticians) have no way to build verifiable work credentials; customers can't find trustworthy service providers
- Word of mouth culture: African hiring relies heavily on trust and reputation, but there's no digital way to capture or transfer this trust
- Mobile-first reality: Most job seekers access opportunities via mobile, yet existing platforms are desktop-focused and clunky
Vision
YeboJobs is building Africa's job ecosystem that works for both:
- Formal employment: TikTok-style job discovery with AI-powered matching and interviewing
- Informal services: A trust marketplace where workers earn verifiable credentials (YeboScore) based on real work performance
Core Philosophy: In Africa, word of mouth > formal credentials. Repeat customers = real trust. YeboJobs digitizes this reality.
2. Solution Overview
YeboJobs is a dual-marketplace platform consisting of:
2.1 Formal Jobs Platform (Job Seekers & Employers)
- TikTok-style job discovery: Swipe through jobs with video content
- AI-powered interviews: Okia Service provides automated candidate screening
- Smart matching: Personality and culture fit scoring
- Experience Lab: Micro-credential courses that prove job readiness
2.2 Informal Services Platform (Workers & Clients)
- Service worker profiles: Video-first portfolios showcasing real work
- Client requests: Post service needs, get quotes from matched workers
- YeboScore: Universal work credential based on customer reviews, reliability, repeat business
- In-app messaging: Communicate and negotiate directly
2.3 Supporting Systems
- Credits Economy: Monetization via purchasable credits for actions
- Stripe Subscriptions: Tiered plans for advanced features
- AI Onboarding: Chat-based profile creation via Okia
- Admin Dashboard: Full billing, trial, and promotion management
3. Core Features (Based on Actual Code)
3.1 User Management
User Roles (UserRole enum)
| Role | Description |
|---|---|
job_seeker | Formal job seeker looking for employment |
service_worker | Informal service provider (plumber, cleaner, etc.) |
client | Needs services done |
hybrid | Both worker and client |
User Profile Fields
- Basic: name, email, phone (unique), location, bio, profile picture
- Video: profileVideo (intro video support)
- Matching: personalityMatch[], culturePreferences[]
- Privacy: showInterviewScores (boolean)
- GPS: latitude, longitude (for services)
Authentication
- Phone-based OTP via WhatsApp (NotificationService)
- JWT access + refresh tokens
- Separate auth flows for User vs Employer
- bcrypt password hashing
3.2 Job Marketplace
Job Listings
- Full job details: title, company, location, salary, currency
- Job types: full_time, part_time, contract, internship, remote
- Experience levels: entry, mid, senior, executive
- Rich content: requirements[], benefits[], hashtags[]
- Video: videoContent URL support
- AI Interview config: aiInterviewEnabled, autoInviteOnApply, interviewQuestions, interviewTimeLimit
- Engagement: applicationsCount, savesCount, sharesCount, boostLevel
Swipe System
- TikTok-style discovery: like, dislike, superlike
- Swipe history tracking (SwipeHistory model)
- Saved jobs functionality
Applications
| Status | Description |
|---|---|
| pending | Just applied |
| reviewed | Employer viewed |
| shortlisted | Made it to next round |
| rejected | Not selected |
| hired | Got the job |
- Cover letter support
- CV upload (cvUrl)
- AI Interview integration: interviewSessionId, interviewScore, interviewGrade
Placements
- Tracks successful hires
- Records: hiredDate, startDate, salary, currency
- Links User → Job → Employer → Application
3.3 Employer Portal
Employer Profile
- Company info: companyName, industry, companySize (enum: startup → enterprise)
- Contact: email, phone, whatsappNumber
- Branding: logo, website, description
- Stats: jobsPosted, activeJobs
- Verification: isVerified boolean
Employer Actions
- Post jobs with AI interview configuration
- Review applications
- Invite candidates to AI interviews
- Track hiring funnel
- Access billing/subscription management
3.4 Informal Services Marketplace
Service Categories
- Hierarchical: parent/child relationships
- AI-generated categories from user input
- Examples: plumber, kitchen renovation, electrician
- Usage tracking for trending categories
Service Worker Profile
- Headline & Bio: "Experienced Plumber - 10+ years"
- Skills: Specific abilities like "burst pipe repair", "geyser installation"
- Pricing (African negotiation style):
- priceMin / priceMax (ranges, not fixed!)
- priceNote: "Price depends on job complexity"
- negotiable: Boolean
- currency: Default "SZL" (Eswatini Lilangeni)
- Location & Availability:
- GPS coordinates (latitude, longitude)
- serviceRadius (km willing to travel)
- availableDays[], availableFrom/To (hours)
- locationName: "Manzini, Eswatini"
- Portfolio Media (Video-first!):
- introVideo: Short TikTok-style intro
- portfolioVideos[], portfolioImages[]
- certificateUrls[]
- Trust & Verification:
- isVerified, idVerified, phoneVerified
- Performance Stats:
- jobsCompleted, averageRating, reviewCount
- responseRate (%), responseTimeMin (avg minutes)
- AI Profile:
- onboardingComplete, aiProfileScore (0-100)
Service Listings
- Worker-created service offerings
- Category-linked with subcategory option
- Pricing ranges with notes
- Duration estimates
- Includes/excludes lists
- Requirements (what client provides)
- Stats: viewCount, inquiryCount, bookingCount
Service Requests (Client Posts)
- Client describes what they need
- AI extracts categoryTags from description
- Location with GPS
- Timing: preferredDate, preferredTime, isUrgent
- Budget ranges with notes
- Status: open, in_progress, completed, cancelled
- AI matching: aiMatchedWorkers[] (suggested worker IDs)
Quotes System
- Workers submit quotes on requests
- Pricing: amount (and optional amountMax range)
- Personal message to client
- Availability info: canStartToday, availableDate
- Status: pending, accepted, rejected, expired, withdrawn
Booking Lifecycle
| Status | Description |
|---|---|
| pending | Request awaiting acceptance |
| accepted | Worker confirmed |
| declined | Worker declined |
| in_progress | Work started |
| completed | Work finished |
| cancelled | Called off |
| disputed | Issue raised |
- Full scheduling: date, time, estimated duration
- Location: GPS + address
- Agreed pricing
- Source tracking: isOnPlatform (true = booked via app, false = word-of-mouth)
- Payment tracking (future-ready): paymentStatus, paymentMethod, transactionId, platformFee
Review System
- Ratings (1-5 stars):
- overallRating (required)
- qualityRating (work quality)
- punctualityRating (timeliness)
- communicationRating
- valueRating (value for money)
- Title, comment, images (photos of completed work)
- Worker can respond (workerResponse)
- Verified only after completed booking
3.5 YeboScore: Universal Work Credential
Philosophy: African context considerations:
- Word of mouth > formal credentials
- Repeat customers = real trust
- Community reputation matters
- Showing up and doing good work > fancy certificates
Score Components (Weighted for Africa)
| Component | Weight | Description |
|---|---|---|
| Customer Reviews | 35% | Word of mouth is king |
| Reliability | 25% | Do you show up and finish? |
| Repeat Business | 20% | Do people come back? |
| Response Time | 15% | Are you available? |
| Okia Interview | 5% | Optional, for formal roles |
Tiers
| Tier | Min Score | Requirements |
|---|---|---|
| Platinum | 80+ | 20+ jobs, 4.5+ rating, 50%+ repeat customers |
| Gold | 60+ | 10+ jobs, 4.0+ rating, 30%+ repeat |
| Silver | 40+ | 5+ jobs, 3.5+ rating |
| Bronze | 0+ | New worker |
Badges
top_rated: 4.8+ stars with 10+ reviewstrusted: 50%+ repeat customersfast_responder: <30 min avg response, 90%+ response ratereliable: 95%+ completion rateveteran: 1+ year, 50+ jobsverified: ID verified
3.6 AI Onboarding (Okia Service Integration)
Session Types
worker_onboarding: Set up service worker profile via chatservice_matching: Find right service for needsrequest_creation: AI helps write service requestgeneral_work_interview: Okia interview for YeboScore
Okia Service (Separate Python FastAPI App)
- Located in
okia-service/ - Uses Claude AI for conversations
- Socket.IO for real-time chat
- Webhook callbacks to YeboJobs backend
- Extracts structured data from conversations
3.7 AI Interview System
Integration Flow
- Employer enables AI interview on job posting
- Candidate applies → optionally auto-invited
- Okia creates interview session
- Candidate completes interview via Okia interface
- Okia sends webhook with scores
- YeboJobs updates application with:
- interviewScore (0-100)
- interviewGrade (A+, A, B+, B, C, D, F)
- interviewStatus (pending, in_progress, completed, expired)
Score Categories
- Technical
- Communication
- Problem Solving
- Cultural Fit
Privacy Control
Users can toggle showInterviewScores to hide scores from employers.
3.8 Experience Lab (Gamified Learning)
Tracks
- Categories: customer_service, data_entry, professional_communication
- Difficulty: beginner, intermediate, advanced
- Free or paid tracks
- Can be employer-created
Tasks
- Types: multiple_choice, text_response, file_upload, scenario
- Auto-grading for MCQ and basic text analysis
- XP rewards on completion
- Max attempts limit (default 3)
- Passing score (default 70%)
Progression System
- XP & Levels:
- Level 1: 0 XP
- Level 2: 100 XP
- Level 10: 4,500 XP
- Track Completion: Issues verifiable certificate
- Certificates: Unique verification codes (YJ-XXXXXXXX)
- Badges: first_task, perfect_score, first_try, track_complete_*, etc.
3.9 Credits System (Monetization)
Credit Costs (Actions)
Job Seeker:
| Action | Credits |
|---|---|
| JOB_APPLY_ENTRY | 5 |
| JOB_APPLY_MID | 8 |
| JOB_APPLY_SENIOR | 12 |
| JOB_APPLY_COVER_LETTER | 3 |
| JOB_SAVE | 1 |
| MESSAGE_AFTER_FREE | 3 |
| INTERVIEW_RETAKE | 15 |
| INTERVIEW_TRANSCRIPT | 10 |
Employer:
| Action | Credits |
|---|---|
| POST_JOB | 25 |
| POST_JOB_FEATURED | 50 |
| POST_JOB_URGENT | 35 |
| VIEW_CV | 3 |
| SEND_INTERVIEW_INVITE | 10 |
| ACCESS_CONTACT_INFO | 8 |
| BULK_MESSAGE_10 | 20 |
| HIRING_SUCCESS | 50 |
Service Workers:
| Action | Credits |
|---|---|
| CREATE_WORKER_PROFILE | 10 |
| ADD_EXTRA_CATEGORY | 5 |
| SUBMIT_QUOTE | 2 |
| BOOST_PROFILE_7_DAYS | 30 |
| PREMIUM_BADGE_MONTHLY | 50 |
Clients:
| Action | Credits |
|---|---|
| LIKE_WORKER | 1 |
| POST_SERVICE_REQUEST | 8 |
| POST_SERVICE_REQUEST_URGENT | 20 |
| MESSAGE_WORKER_AFTER_FREE | 2 |
| BOOK_WORKER_DIRECT | 5 |
Credit Rewards
| Reward | Credits |
|---|---|
| SIGNUP | 5 |
| VERIFY_PHONE | 5 |
| VERIFY_EMAIL | 3 |
| COMPLETE_PROFILE | 10 |
| ADD_PROFILE_PHOTO | 3 |
| CONNECT_WHATSAPP | 5 |
| FIRST_CV_UPLOAD | 5 |
| FIRST_INTERVIEW_COMPLETED | 10 |
| ADD_INTRO_VIDEO | 10 |
| REFERRAL_SIGNUP | 15 |
| REFERRAL_FIRST_PURCHASE | 10 |
| FIVE_STAR_REVIEW | 2 |
| DAILY_STREAK_7 | 5 |
| DAILY_STREAK_30 | 25 |
| YEBOSCORE_SILVER | 20 |
| YEBOSCORE_GOLD | 50 |
| YEBOSCORE_PLATINUM | 100 |
Multi-Currency Support
- Currencies table with PPP-adjusted pricing
- Credit rate per currency
- Tier system (1-5) for regional pricing
- Supported: USD, ZAR, SZL, KES, NGN, etc.
Credit Packages
- Multiple packages: Starter, Popular, Pro, Business
- Base credits + bonus credits
- Multi-currency prices
Payment Flow (Manual)
- User selects package and currency
- Payment request created (48h expiry)
- User pays via local method (MTN MoMo, bank transfer, M-Pesa, etc.)
- User submits payment reference
- Admin confirms → credits added
- Full audit trail via CreditTransaction
Worker Cashout
- Minimum 100 credits
- Freeze credits during processing
- Platform fee: 15% on bookings
- Multiple payout methods
3.10 Stripe Billing System
Subscription Tiers
| Tier | Description |
|---|---|
| free | Basic access |
| pro | Advanced features |
| business | Full platform access |
| enterprise | Custom pricing |
Subscription Status
- active, trialing, past_due, canceled, unpaid, paused
Admin Controls
- Free Trials: Admin can grant custom trial periods
- Vouchers: Create discount codes with:
- Types: percentage, fixed_amount, free_trial, credits
- Scope: all_users, new_users_only, specific_users
- Usage limits, date ranges, stackability rules
- Promotions: Site-wide banners with voucher links
Billing Features
- StripeCustomer linking (User or Employer)
- Multiple payment methods on file
- Invoice tracking
- Webhook event idempotency (WebhookEvent model)
3.11 Messaging System
Conversation Types
| Type | Context |
|---|---|
| job_inquiry | About a job application |
| booking_inquiry | About a service booking/quote |
Features
- Multi-participant conversations
- Message types: text, image, system
- Status tracking: sent, delivered, read
- Unread counts per participant
- Reply-to threading
- Typing indicators (lastTypingAt)
- Mute, pin, archive, delete (soft)
3.12 CV Management
AI-Generated CVs
- Created via Okia chat sessions
- Structured data extraction:
- personal_info: full_name, email, phone, location, profile_summary
- experience: company, position, dates, achievements
- education: institution, degree, field, graduation
- skills: technical[], soft[]
- languages: language, proficiency
- certifications: name, issuer, year
CV Features
- Multiple CVs per user
- Default CV flag
- Privacy control (isPublic)
- Source tracking: ai_chat, manual, import
3.13 WhatsApp Alerts
Alert Types
- new_job_match
- booking_update
- new_quote
- review_received
Integration
- Uses shared Eneza notification worker
- HTTP client with retry logic (exponential backoff)
- Status tracking: pending, sent, failed
3.14 Blog System
- Full CMS with BlogPost model
- Slug-based URLs
- Categories, tags
- Scheduled publishing
- AI author support
4. User Journeys
4.1 Job Seeker Journey
1. SIGNUP
├── Enter phone number
├── Receive OTP via WhatsApp
├── Verify and create account
└── Receive 5 signup credits
2. PROFILE SETUP
├── Basic info (name, location)
├── Upload profile picture (+3 credits)
├── Add education & experience
├── Complete AI onboarding (+10 credits)
└── Upload/generate CV (+5 credits)
3. JOB DISCOVERY
├── Browse TikTok-style job feed
├── Swipe right (like) / left (dislike) / up (superlike)
├── Save interesting jobs
└── View job details and videos
4. APPLICATION
├── Apply with CV (-5 to -12 credits based on level)
├── Optional: Add cover letter (-3 credits)
├── If AI interview enabled → invited
└── Track application status
5. AI INTERVIEW
├── Receive interview invitation
├── Complete via Okia interface
├── Get scored (0-100)
└── Optionally hide scores from employers
6. HIRED
├── Employer marks as hired
├── Placement record created
└── Update profile with new experience4.2 Employer Journey
1. SIGNUP
├── Company registration (email-based)
├── Set up company profile
└── Select subscription tier
2. POST JOB
├── Job details + requirements
├── Set salary and benefits
├── Configure AI interview (optional)
├── Pay credits (-25 to -50)
└── Job goes live
3. REVIEW APPLICATIONS
├── Browse applicant profiles
├── View CVs (-3 credits per view)
├── Check AI interview scores
└── Shortlist candidates
4. HIRE
├── Send interview invites (-10 credits)
├── Conduct additional interviews
├── Mark successful candidate as hired
└── Complete placement
5. MANAGE BILLING
├── View subscription status
├── Purchase credit packages
├── Apply voucher codes
└── Download invoices4.3 Service Worker Journey
1. SIGNUP
├── Phone verification
├── Choose role: service_worker
└── Receive signup credits
2. PROFILE SETUP (via AI Onboarding)
├── Chat with Okia
├── Describe skills & experience
├── Set pricing ranges
├── Upload intro video
├── Add portfolio images/videos
└── AI generates profile
3. CREATE LISTINGS
├── Define services offered
├── Set pricing with negotiation notes
├── Specify what's included/excluded
└── Add service images
4. FIND WORK
├── Swipe through client requests
├── Submit quotes (-2 credits)
├── Respond to direct messages
└── Accept bookings
5. COMPLETE JOBS
├── Arrive on time
├── Mark job started
├── Complete work
├── Mark job completed
└── Receive payment
6. BUILD YEBOSCORE
├── Get client reviews
├── Build repeat customer base
├── Improve response time
├── Earn tier upgrades
└── Unlock badges
7. CASHOUT
├── Request cashout (min 100 credits)
├── Select payment method
├── Admin processes
└── Receive funds (minus 15% fee)4.4 Client Journey
1. SIGNUP
├── Phone verification
├── Choose role: client
└── Receive signup credits
2. FIND WORKERS
├── Browse service worker profiles
├── Filter by category, location, rating
├── Watch intro videos
├── Check YeboScore
└── Like workers (-1 credit)
3. POST REQUEST
├── Describe what you need
├── AI extracts category tags
├── Set budget range
├── Set preferred date/time
├── Mark urgent if needed
├── Pay credits (-8 or -20)
└── AI matches relevant workers
4. RECEIVE QUOTES
├── Workers submit quotes
├── Compare pricing & availability
├── Chat with workers
└── Negotiate if needed
5. BOOK SERVICE
├── Accept a quote
├── Confirm booking details
├── Worker accepts/declines
└── Job scheduled
6. AFTER SERVICE
├── Worker completes job
├── Mark as completed
├── Submit review (detailed ratings)
├── Upload photos of work
└── Optionally tip/recommend4.5 Admin Journey
1. BILLING MANAGEMENT
├── Review pending payment requests
├── Confirm or reject payments
├── Process cashout requests
├── Manage subscriptions
└── Issue refunds
2. TRIAL MANAGEMENT
├── Grant free trials to users
├── Set custom duration
├── Send expiry reminders
├── Extend or revoke trials
└── Track conversions
3. VOUCHER MANAGEMENT
├── Create voucher codes
├── Set discount rules
├── Limit to specific users
├── Track usage
└── Deactivate expired vouchers
4. PROMOTIONS
├── Create site-wide banners
├── Link to vouchers
├── Target specific user types
├── Schedule start/end dates
└── A/B test messaging
5. ANALYTICS
├── Revenue reports
├── Subscription analytics
├── Trial conversion rates
├── Voucher performance
└── User breakdowns5. Data Models (Complete)
5.1 Core User Models
User
model User {
id String @id @default(cuid())
name String
email String?
password String
phone String @unique
location String
bio String?
profilePicture String?
profileVideo String?
personalityMatch String[] @default([])
culturePreferences String[] @default([])
isActive Boolean @default(true)
lastLogin DateTime?
refreshToken String?
showInterviewScores Boolean @default(true)
role UserRole @default(job_seeker)
latitude Float?
longitude Float?
subscriptionTier SubscriptionTier @default(free)
subscriptionStatus SubscriptionStatus?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}Employer
model Employer {
id String @id @default(cuid())
companyName String
email String @unique
password String
industry String
companySize CompanySize
description String
phone String
whatsappNumber String?
logo String?
website String?
location String
isVerified Boolean @default(false)
jobsPosted Int @default(0)
activeJobs Int @default(0)
joinedDate DateTime @default(now())
refreshToken String?
subscriptionTier SubscriptionTier @default(free)
subscriptionStatus SubscriptionStatus?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}5.2 Job Models
Job (All Fields)
model Job {
id String @id @default(cuid())
title String
company String
location String
salary Decimal @db.Decimal(12, 2)
currency String @default("USD")
description String
requirements String[] @default([])
benefits String[] @default([])
jobType JobType // full_time, part_time, contract, internship, remote
experienceLevel ExperienceLevel // entry, mid, senior, executive
applicationsCount Int @default(0)
savesCount Int @default(0)
sharesCount Int @default(0)
videoContent String?
isActive Boolean @default(true)
postedDate DateTime @default(now())
expiryDate DateTime
hashtags String[] @default([])
trending Boolean @default(false)
boostLevel Int @default(0) @db.SmallInt
cultureFit String[] @default([])
personalityMatch String[] @default([])
whatsappContact String?
email String
employerId String
aiInterviewEnabled Boolean @default(false)
autoInviteOnApply Boolean @default(false)
interviewQuestions Int @default(10)
interviewTimeLimit Int @default(15)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}Application
model Application {
id String @id @default(cuid())
userId String
jobId String
employerId String
status ApplicationStatus @default(pending)
coverLetter String?
cvUrl String?
appliedDate DateTime @default(now())
lastUpdated DateTime @default(now()) @updatedAt
interviewSessionId String?
interviewStatus String? // pending, in_progress, completed, expired
interviewScore Int? // 0-100
interviewGrade String? // A+, A, B+, B, C, D, F
interviewCompletedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([userId, jobId])
}5.3 Services Models
ServiceWorkerProfile (All Fields)
model ServiceWorkerProfile {
id String @id @default(cuid())
userId String @unique
headline String
bio String?
skills String[] @default([])
yearsExperience Int @default(0)
priceMin Decimal? @db.Decimal(10, 2)
priceMax Decimal? @db.Decimal(10, 2)
priceNote String?
currency String @default("SZL")
negotiable Boolean @default(true)
latitude Float?
longitude Float?
locationName String
serviceRadius Int @default(25)
isAvailable Boolean @default(true)
availableDays String[] @default(["monday","tuesday","wednesday","thursday","friday"])
availableFrom String? @default("08:00")
availableTo String? @default("17:00")
introVideo String?
portfolioVideos String[] @default([])
portfolioImages String[] @default([])
certificateUrls String[] @default([])
isVerified Boolean @default(false)
idVerified Boolean @default(false)
phoneVerified Boolean @default(true)
jobsCompleted Int @default(0)
averageRating Decimal @default(0) @db.Decimal(2, 1)
reviewCount Int @default(0)
responseRate Int @default(100)
responseTimeMin Int @default(60)
onboardingComplete Boolean @default(false)
aiProfileScore Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}ServiceBooking (All Fields)
model ServiceBooking {
id String @id @default(cuid())
clientId String
workerId String
listingId String?
requestId String?
categoryId String?
description String
categoryTags String[] @default([])
scheduledDate DateTime
scheduledTime String?
estimatedDuration String?
latitude Float
longitude Float
locationName String
address String
agreedPrice Decimal @db.Decimal(10, 2)
currency String @default("SZL")
priceNotes String?
status BookingStatus @default(pending)
acceptedAt DateTime?
startedAt DateTime?
completedAt DateTime?
cancelledAt DateTime?
clientPhone String
workerPhone String
notes String?
isOnPlatform Boolean @default(true)
sourceNote String?
paymentStatus String @default("unpaid")
paymentMethod String?
transactionId String?
platformFee Decimal? @db.Decimal(10, 2)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}YeboScore (All Fields)
model YeboScore {
id String @id @default(cuid())
userId String @unique
generalScore Int? // Okia interview (0-100)
generalGrade String? // A+, A, B+, B, C, D, F
skillScores Json? // {"plumbing": 85, "electrical": null}
lastInterviewAt DateTime?
reliabilityScore Int @default(50)
responseScore Int @default(50)
customerRating Decimal @default(0) @db.Decimal(2, 1)
reviewCount Int @default(0)
overallScore Int @default(0)
tier YeboTier @default(bronze)
badges String[] @default([])
lastCalculatedAt DateTime @default(now())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}5.4 Billing Models
UserCredits
model UserCredits {
id String @id @default(cuid())
userId String @unique
balance Int @default(0)
frozenBalance Int @default(0) // In escrow
totalPurchased Int @default(0)
totalSpent Int @default(0)
totalEarned Int @default(0)
totalBonuses Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}CreditTransaction
model CreditTransaction {
id String @id @default(cuid())
userId String
type String // purchase, spend, earn, refund, freeze, unfreeze, bonus, referral
amount Int // Positive = add, Negative = deduct
action String // job_apply, post_job, booking, signup, etc.
description String
referenceType String?
referenceId String?
balanceBefore Int
balanceAfter Int
createdAt DateTime @default(now())
}Subscription
model Subscription {
id String @id @default(cuid())
stripeSubscriptionId String? @unique
stripeCustomerId String
tier SubscriptionTier @default(free)
status SubscriptionStatus @default(active)
priceId String?
currentPeriodStart DateTime?
currentPeriodEnd DateTime?
billingInterval BillingInterval?
trialStart DateTime?
trialEnd DateTime?
isAdminGrantedTrial Boolean @default(false)
trialGrantedBy String?
trialNote String?
cancelAtPeriodEnd Boolean @default(false)
canceledAt DateTime?
cancelReason String?
featuresJson Json?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}Voucher (All Fields)
model Voucher {
id String @id @default(cuid())
code String @unique
name String
description String?
type VoucherType // percentage, fixed_amount, free_trial, credits
discountValue Decimal? @db.Decimal(10, 2)
maxDiscountAmount Decimal? @db.Decimal(10, 2)
bonusCredits Int @default(0)
trialDays Int @default(0)
scope VoucherScope @default(all_users)
applicableTiers SubscriptionTier[] @default([])
applicableIntervals BillingInterval[] @default([])
subscriberTypes SubscriberType[] @default([user, employer])
maxTotalUses Int?
maxUsesPerUser Int @default(1)
currentUses Int @default(0)
isActive Boolean @default(true)
startsAt DateTime @default(now())
expiresAt DateTime?
isStackable Boolean @default(false)
isExclusive Boolean @default(false)
stripeCouponId String?
createdBy String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}5.5 Experience Lab Models
ExperienceTrack
model ExperienceTrack {
id String @id @default(cuid())
name String
slug String @unique
description String
category String // customer_service, data_entry, etc.
difficulty String // beginner, intermediate, advanced
estimatedHours Float
iconUrl String?
isActive Boolean @default(true)
isFree Boolean @default(true)
employerId String? // null = YeboJobs official
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}ExperienceTask
model ExperienceTask {
id String @id @default(cuid())
trackId String
orderIndex Int
title String
description String
instructions String // markdown
taskType String // multiple_choice, text_response, file_upload, scenario
taskData Json // questions, options, rubric
estimatedMinutes Int
passingScore Int @default(70)
maxAttempts Int @default(3)
resources Json? // [{title, url}]
xpReward Int @default(50)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([trackId, orderIndex])
}5.6 All Enums
enum CompanySize { startup, small, medium, large, enterprise }
enum JobType { full_time, part_time, contract, internship, remote }
enum ExperienceLevel { entry, mid, senior, executive }
enum ApplicationStatus { pending, reviewed, shortlisted, rejected, hired }
enum SwipeAction { like, dislike, superlike }
enum UserRole { job_seeker, service_worker, client, hybrid }
enum BookingStatus { pending, accepted, declined, in_progress, completed, cancelled, disputed }
enum YeboTier { bronze, silver, gold, platinum }
enum SubscriptionTier { free, pro, business, enterprise }
enum SubscriptionStatus { active, trialing, past_due, canceled, unpaid, paused }
enum SubscriberType { user, employer }
enum VoucherType { percentage, fixed_amount, free_trial, credits }
enum VoucherScope { all_users, new_users_only, specific_users }
enum PromotionStatus { draft, scheduled, active, ended, paused }
enum TrialStatus { active, expired, converted, revoked }
enum BillingInterval { monthly, yearly }
enum MessageStatus { sent, delivered, read }
enum MessageType { text, image, system }
enum ConversationType { job_inquiry, booking_inquiry }6. API Reference
6.1 Authentication Routes (/api/auth)
| Method | Endpoint | Description |
|---|---|---|
| POST | /register | User registration with phone OTP |
| POST | /login | User login (phone + password) |
| POST | /employer/register | Employer registration |
| POST | /employer/login | Employer login (email + password) |
| POST | /refresh | Refresh access token |
| POST | /logout | Invalidate refresh token |
| POST | /verify-otp | Verify phone OTP |
| POST | /resend-otp | Resend OTP code |
| POST | /forgot-password | Password reset request |
| POST | /reset-password | Complete password reset |
6.2 User Routes (/api/user)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /profile | User | Get own profile |
| PUT | /profile | User | Update profile |
| GET | /profile/:id | Optional | Get user public profile |
| POST | /profile/picture | User | Upload profile picture |
| POST | /education | User | Add education |
| PUT | /education/:id | User | Update education |
| DELETE | /education/:id | User | Delete education |
| POST | /experience | User | Add work experience |
| PUT | /experience/:id | User | Update experience |
| DELETE | /experience/:id | User | Delete experience |
| GET | /applications | User | Get user's applications |
6.3 Job Routes (/api/jobs)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | / | Optional | List jobs (with filters) |
| GET | /feed | Optional | TikTok-style job feed |
| GET | /:id | Optional | Get job details |
| POST | / | Employer | Create job posting |
| PUT | /:id | Employer | Update job |
| DELETE | /:id | Employer | Delete job |
| POST | /:id/swipe | User | Swipe on job |
| POST | /:id/save | User | Save job |
| DELETE | /:id/save | User | Unsave job |
| GET | /saved | User | Get saved jobs |
6.4 Application Routes (/api/applications)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | / | User | Apply for job |
| GET | / | User | Get user's applications |
| GET | /:id | User/Employer | Get application details |
| PUT | /:id/status | Employer | Update application status |
| DELETE | /:id | User | Withdraw application |
6.5 Employer Routes (/api/employer)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /profile | Employer | Get company profile |
| PUT | /profile | Employer | Update company profile |
| GET | /jobs | Employer | List employer's jobs |
| GET | /applications | Employer | List all applications |
| GET | /stats | Employer | Get hiring stats |
6.6 Services Routes (/api/services)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /categories | Public | List service categories |
| GET | /categories/:slug | Public | Get category by slug |
| POST | /worker/profile | User | Create worker profile |
| PUT | /worker/profile | User | Update worker profile |
| GET | /worker/profile/:id | Public | Get worker profile |
| GET | /workers | Public | Search workers |
| GET | /workers/feed | User | TikTok-style worker feed |
| POST | /workers/:id/swipe | User | Swipe on worker |
| POST | /listings | Worker | Create service listing |
| GET | /listings/:id | Public | Get listing details |
| PUT | /listings/:id | Worker | Update listing |
| DELETE | /listings/:id | Worker | Delete listing |
6.7 Booking Routes (/api/bookings)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | / | User | Create booking |
| GET | / | User | List user's bookings |
| GET | /:id | User | Get booking details |
| PUT | /:id/status | User/Worker | Update booking status |
| POST | /:id/complete | Worker | Mark completed |
| POST | /:id/review | Client | Submit review |
6.8 Reviews Routes (/api/reviews)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /worker/:workerId | Public | Get worker reviews |
| POST | /:bookingId | User | Create review |
| PUT | /:id | User | Update review |
| POST | /:id/respond | Worker | Worker response |
6.9 Credits Routes (/api/credits)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /balance | User | Get credit balance |
| GET | /transactions | User | Get transaction history |
| GET | /packages | Public | List credit packages |
| POST | /purchase | User | Create payment request |
| POST | /purchase/:id/reference | User | Submit payment reference |
| GET | /currencies | Public | List supported currencies |
| POST | /cashout | User | Request cashout |
| GET | /cashout | User | Get cashout history |
6.10 Billing Routes (/api/billing)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /subscription | User | Get subscription status |
| POST | /checkout | User | Create Stripe checkout session |
| POST | /manage | User | Create Stripe portal session |
| GET | /plans | Public | List subscription plans |
| POST | /voucher/validate | User | Validate voucher code |
| POST | /voucher/apply | User | Apply voucher |
| GET | /invoices | User | Get invoice history |
6.11 Subscription Routes (/api/subscriptions)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | / | User | Get active subscription |
| POST | /cancel | User | Cancel subscription |
| POST | /resume | User | Resume cancelled subscription |
6.12 Interview Routes (/api/interviews)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /invite | Employer | Invite to AI interview |
| GET | /status/:applicationId | User/Employer | Get interview status |
| GET | /pending | User | Get pending interviews |
| GET | / | User | Get all interviews |
| GET | /session/:applicationId | User | Get interview session URL |
| PUT | /privacy | User | Update score visibility |
| GET | /employer | Employer | Get applications with interviews |
| POST | /webhook/completed | System | Okia webhook handler |
6.13 Experience Routes (/api/experience)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /tracks | Public | List all tracks |
| GET | /tracks/:slug | Public | Get track by slug |
| POST | /tracks/:id/enroll | User | Enroll in track |
| GET | /enrollments | User | Get user enrollments |
| GET | /tasks/:id | User | Get task with progress |
| POST | /tasks/:id/submit | User | Submit task |
| GET | /certificates | User | Get user certificates |
| GET | /certificates/verify/:code | Public | Verify certificate |
| GET | /progress | User | Get full progress summary |
| GET | /leaderboard | Public | Get XP leaderboard |
6.14 AI Onboarding Routes (/api/ai-onboarding)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /session | User | Start AI onboarding session |
| GET | /session/:token | User | Get session status |
| POST | /session/:token/message | User | Send message to AI |
| POST | /session/:token/complete | User | Complete session |
6.15 Messages Routes (/api/messages)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /conversations | User | List conversations |
| POST | /conversations | User | Create conversation |
| GET | /conversations/:id | User | Get conversation messages |
| POST | /conversations/:id/messages | User | Send message |
| PUT | /conversations/:id/read | User | Mark as read |
| PUT | /conversations/:id/archive | User | Archive conversation |
6.16 Placement Routes (/api/placements)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | / | Employer | Create placement |
| GET | /employer | Employer | Get employer placements |
| GET | /user | User | Get user placements |
| GET | /:id | Any | Get placement details |
6.17 Dashboard Routes (/api/dashboard)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /metrics | Dashboard | Get dashboard metrics |
6.18 Admin Billing Routes (/api/admin/billing)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | /subscriptions | Admin | List subscriptions |
| POST | /subscriptions/:id/cancel | Admin | Cancel subscription |
| POST | /subscriptions/:id/refund | Admin | Refund subscription |
| GET | /trials | Admin | List free trials |
| POST | /trials | Admin | Grant free trial |
| PUT | /trials/:id | Admin | Extend trial |
| DELETE | /trials/:id/revoke | Admin | Revoke trial |
| GET | /vouchers | Admin | List vouchers |
| POST | /vouchers | Admin | Create voucher |
| PUT | /vouchers/:id | Admin | Update voucher |
| DELETE | /vouchers/:id | Admin | Deactivate voucher |
| GET | /promotions | Admin | List promotions |
| POST | /promotions | Admin | Create promotion |
| GET | /analytics/* | Admin | Various analytics endpoints |
6.19 Webhook Routes (/api/webhooks)
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /stripe | Stripe Signature | Stripe webhook handler |
7. Service Architecture
7.1 Backend Structure
yebojobs/backend/
├── prisma/
│ └── schema.prisma # Database schema
├── src/
│ ├── config/
│ │ ├── prisma.ts # Prisma client
│ │ └── stripe.ts # Stripe configuration
│ ├── controllers/ # Request handlers
│ ├── services/ # Business logic
│ ├── routes/ # API routes
│ ├── middleware/
│ │ ├── auth.middleware.ts # JWT auth
│ │ └── validation.middleware.ts
│ ├── utils/
│ │ ├── ApiResponse.ts # Standardized responses
│ │ └── jwt.ts # Token utilities
│ └── app.ts # Express setup7.2 External Services
- Okia Service: AI interviews (Python/FastAPI + Claude)
- Eneza Notifications: WhatsApp messaging
- Stripe: Payment processing
- Cloudflare R2: File storage (implied)
- GCP Cloud Run: Hosting
7.3 Key Services
YeboScoreService
calculateScore(userId): Calculates weighted scoreupdateInterviewScore(): Updates from OkiagetScoreWithBreakdown(): Full score details
CreditsService
spendCredits(): Deduct creditsearnCredits(): Add earned creditsfreezeCredits(): Escrow for bookingsreleaseEscrow(): Complete booking paymentaddBonusCredits(): Reward system
NotificationService
sendVerificationCode(): WhatsApp OTP- Retry with exponential backoff
ExperienceService
- Track/task management
- Auto-grading (MCQ, text analysis)
- XP/leveling system
- Certificate generation
8. Authentication & Authorization
8.1 Authentication Methods
- Users: Phone + OTP + Password
- Employers: Email + Password
8.2 Token System
- Access Token: Short-lived JWT
- Refresh Token: Long-lived, stored in DB
- Decoded payload:
{ id, type: 'user' | 'employer' }
8.3 Middleware
| Middleware | Description |
|---|---|
authMiddleware | Requires valid JWT |
userAuth | Requires type === 'user' |
employerAuth | Requires type === 'employer' |
optionalAuth | Sets user if token valid, doesn't require |
dashboardAuthMiddleware | Admin dashboard access |
8.4 OTP Flow
- Request OTP → WhatsApp via Eneza notification service
- OTP code hashed with bcrypt, stored in VerificationCode
- Max 5 attempts, 10-minute expiry
- Verify → Create account / Reset password
9. Payment/Billing
9.1 Dual Payment System
Manual Credits (Africa-focused)
- Credit packages with multi-currency pricing
- Local payment methods: MTN MoMo, M-Pesa, bank transfer, Airtel Money
- Manual confirmation by admin
- 48-hour payment window
Stripe (International)
- Subscription management
- Card payments
- Webhook-based updates
- Automatic renewal
9.2 Platform Fee
- 15% on service bookings
- Deducted when escrow released to worker
9.3 Escrow System
- Client books service → credits frozen
- Worker completes job → marked complete
- Escrow released: worker gets 85%, platform 15%
- If cancelled: full refund to client
10. Matching Algorithm
10.1 Job Matching (Implicit)
- Location-based filtering
- Job type and experience level matching
- Personality/culture fit arrays (for future scoring)
- Hashtag matching potential
10.2 Service Worker Matching
- GPS-based radius search (
serviceRadiuskm) - Category matching via tags
- AI extraction of
categoryTagsfrom request description - Availability filtering (days, hours)
- Rating/YeboScore sorting
10.3 AI Matching (Service Requests)
aiMatchedWorkers[]field on ServiceRequest- Populated by AI analysis of request vs worker profiles
- Considers: skills, location, availability, ratings
11. Notifications
11.1 WhatsApp Alerts
- Sent via Eneza notification worker
- Types: new_job_match, booking_update, new_quote, review_received
- Status tracking: pending → sent/failed
11.2 Notification Triggers
- New job matching user profile
- Booking status changes
- New quotes on requests
- Review received
- Interview invitations
12. Technical Stack
12.1 Backend
- Runtime: Node.js with TypeScript
- Framework: Express.js
- ORM: Prisma
- Database: PostgreSQL (Neon serverless)
- Auth: JWT (jsonwebtoken)
- Validation: Joi
- Payments: Stripe SDK
12.2 Frontend
- Framework: React 18 with TypeScript
- Build Tool: Vite
- Styling: Tailwind CSS
- UI Components: Headless UI
- Animation: Framer Motion
- State: React Context (implied)
- Real-time: Socket.io client
12.3 Admin Dashboard
- Separate React app (
yebojobs-admin/) - Full billing/trial/voucher management
- Analytics dashboards
12.4 Okia Service (AI Interviews)
- Language: Python
- Framework: FastAPI
- AI: Claude (Anthropic)
- Real-time: Socket.IO
- Database: PostgreSQL (SQLAlchemy/Alembic)
12.5 Infrastructure
- Hosting: GCP Cloud Run
- Database: Neon (serverless Postgres)
- Files: Cloudflare R2 (implied)
- Notifications: Eneza notification service
- CI/CD: GCP Cloud Build
13. Gaps & What's Missing
13.1 Not Yet Implemented
- Real-time chat: Socket.IO for messages (client exists, server implementation unclear)
- Push notifications: Mobile app push (only WhatsApp currently)
- Video upload processing: No video transcoding pipeline visible
- Search: Full-text search enabled in Prisma but implementation unclear
- Escrow payment integration: Credits system ready, but no mobile money API integration
- Referral tracking: Reward logic exists but referral link generation missing
- Analytics events: User behavior tracking for recommendations
13.2 Future Enhancements Indicated in Code
- Service matching AI:
aiMatchedWorkersfield exists, needs implementation - Daily streak tracking: Reward constants exist, tracking logic needed
- Payment method storage: Schema ready for saved payment methods
- Employer job analytics: View counts, application funnel
- Worker calendar/scheduling: Availability exists, calendar view needed
13.3 Admin Features Needed
- User/employer management UI
- Content moderation (reviews, profiles)
- Dispute resolution workflow
- Financial reconciliation
13.4 Mobile App
- Frontend is web-only currently
- Progressive Web App or native needed for full experience
13.5 Documentation
- API docs (Swagger/OpenAPI) not found
- Developer onboarding docs missing
Appendix A: Environment Variables
# Database
DATABASE_URL=postgresql://...
DIRECT_URL=postgresql://...
# Auth
JWT_SECRET=...
JWT_REFRESH_SECRET=...
# Stripe
STRIPE_SECRET_KEY=sk_...
STRIPE_PUBLISHABLE_KEY=pk_...
STRIPE_WEBHOOK_SECRET=whsec_...
# Okia Integration
OKIA_SERVICE_URL=https://okia-service-xxx.run.app
OKIA_WEBHOOK_SECRET=...
# Notifications
NOTIFICATION_SERVICE_URL=https://notifications.eneza.app
NOTIFICATION_SERVICE_API_KEY=...
# Environment
NODE_ENV=production
PORT=8080Appendix B: Database Indexes
Key performance indexes defined in schema:
users: phone, location, (latitude, longitude)jobs: location, employerId, isActive+postedDate, expiryDateapplications: employerId+status, appliedDate, interviewSessionIdservice_worker_profiles: (latitude, longitude), isAvailable+averageRating, locationNameservice_bookings: clientId+status, workerId+status, scheduledDatereviews: workerId+overallRating, workerId+createdAtcredit_transactions: userId+createdAt, action, typeyebo_scores: tier+overallScore
This PRD represents the actual implemented state of YeboJobs as of the codebase analysis date. Features marked as "exists" are present in the code; gaps are identified based on incomplete implementations or missing integrations.