Skip to main content

Opportunities Service

The Opportunities Service is a comprehensive system for managing job offers, project requests, and collaboration opportunities within the Ring platform. It provides full CRUD operations with advanced filtering, authentication, and internationalization support.

Overviewโ€‹

The opportunities system connects companies, professionals, and projects through a structured marketplace that supports:

  • Job Opportunities - Full-time and part-time positions
  • Project Requests - Freelance and contract work
  • Collaboration Offers - Partnership and joint venture opportunities
  • Confidential Opportunities - Premium opportunities for verified members
  • Multi-language Support - Ukrainian and English localization
  • File Attachments - Supporting documents and portfolios

API Endpointsโ€‹

Core Opportunity Managementโ€‹

GET /api/opportunitiesโ€‹

Retrieve a paginated list of opportunities with filtering and search capabilities.

Query Parameters:

  • page (number, optional) - Page number for pagination (default: 1)
  • limit (number, optional) - Items per page (default: 10, max: 50)
  • category (string, optional) - Filter by opportunity category
  • type (string, optional) - Filter by opportunity type (job, project, collaboration)
  • budget_min (number, optional) - Minimum budget filter
  • budget_max (number, optional) - Maximum budget filter
  • location (string, optional) - Location filter
  • remote (boolean, optional) - Remote work filter
  • search (string, optional) - Search in title and description
  • entity_id (string, optional) - Filter by posting entity
  • sort (string, optional) - Sort field (created_at, budget, title)
  • order (string, optional) - Sort order (asc, desc)

Response:

{
"opportunities": [
{
"id": "opp_123",
"title": "Senior Full-Stack Developer",
"description": "We are looking for an experienced full-stack developer...",
"short_description": "Senior developer position with modern tech stack",
"category": "Software Development",
"type": "job",
"budget": {
"min": 3000,
"max": 5000,
"currency": "USD",
"per": "month"
},
"location": {
"city": "Kyiv",
"country": "Ukraine",
"remote": true
},
"requirements": [
"5+ years of experience",
"React, Node.js proficiency",
"English B2+"
],
"benefits": [
"Flexible schedule",
"Health insurance",
"Professional development"
],
"entity": {
"id": "entity_456",
"name": "TechCorp Ukraine",
"logo": "https://storage.com/logos/techcorp.png"
},
"attachments": [
{
"name": "job_description.pdf",
"url": "https://storage.com/attachments/job_desc.pdf",
"size": 245760
}
],
"application_process": {
"method": "email",
"contact": "hr@techcorp.ua",
"instructions": "Send CV and cover letter"
},
"tags": ["react", "nodejs", "typescript", "remote"],
"status": "active",
"created_at": "2024-01-15T10:00:00Z",
"updated_at": "2024-01-16T14:30:00Z",
"expires_at": "2024-03-15T23:59:59Z",
"views": 245,
"applications": 12
}
],
"pagination": {
"current_page": 1,
"total_pages": 15,
"total_items": 147,
"per_page": 10,
"has_next": true,
"has_prev": false
},
"filters": {
"categories": ["Software Development", "Design", "Marketing"],
"types": ["job", "project", "collaboration"],
"locations": ["Kyiv", "Lviv", "Kharkiv", "Remote"]
}
}

GET /api/opportunities/[id]โ€‹

Retrieve detailed information about a specific opportunity.

Path Parameters:

  • id (string, required) - Opportunity identifier

Response:

{
"opportunity": {
"id": "opp_123",
"title": "Senior Full-Stack Developer",
"description": "Detailed job description with full requirements...",
"short_description": "Senior developer position with modern tech stack",
"category": "Software Development",
"type": "job",
"budget": {
"min": 3000,
"max": 5000,
"currency": "USD",
"per": "month"
},
"location": {
"city": "Kyiv",
"country": "Ukraine",
"remote": true,
"timezone": "Europe/Kiev"
},
"requirements": [
"5+ years of full-stack development experience",
"Expert knowledge of React and Node.js",
"TypeScript proficiency",
"English B2+ level"
],
"benefits": [
"Flexible working hours",
"Health and dental insurance",
"Professional development budget",
"Modern office in city center"
],
"entity": {
"id": "entity_456",
"name": "TechCorp Ukraine",
"logo": "https://storage.com/logos/techcorp.png",
"website": "https://techcorp.ua",
"employee_count": "50-100"
},
"contact_person": {
"name": "Anna Kovalenko",
"position": "HR Manager",
"email": "anna@techcorp.ua",
"phone": "+380123456789"
},
"application_process": {
"method": "form",
"instructions": "Please fill out the application form and attach your CV",
"required_documents": ["CV", "Cover Letter", "Portfolio"]
},
"attachments": [
{
"id": "att_789",
"name": "detailed_job_description.pdf",
"url": "https://storage.com/attachments/detailed_job.pdf",
"size": 512000,
"uploaded_at": "2024-01-15T10:00:00Z"
}
],
"tags": ["react", "nodejs", "typescript", "remote", "fintech"],
"status": "active",
"created_at": "2024-01-15T10:00:00Z",
"updated_at": "2024-01-16T14:30:00Z",
"expires_at": "2024-03-15T23:59:59Z",
"views": 245,
"applications": 12,
"is_featured": false,
"visibility": "public"
}
}

POST /api/opportunities/createโ€‹

Create a new opportunity. Requires authentication and appropriate permissions.

Authentication: Required (Member role or higher)

Request Body:

{
"title": "Senior Full-Stack Developer",
"description": "We are looking for an experienced full-stack developer to join our growing team...",
"short_description": "Senior developer position with modern tech stack",
"category": "Software Development",
"type": "job",
"budget": {
"min": 3000,
"max": 5000,
"currency": "USD",
"per": "month"
},
"location": {
"city": "Kyiv",
"country": "Ukraine",
"remote": true
},
"requirements": [
"5+ years of experience",
"React, Node.js proficiency",
"English B2+"
],
"benefits": [
"Flexible schedule",
"Health insurance"
],
"entity_id": "entity_456",
"contact_person": {
"name": "Anna Kovalenko",
"position": "HR Manager",
"email": "anna@techcorp.ua"
},
"application_process": {
"method": "email",
"contact": "hr@techcorp.ua",
"instructions": "Send CV and cover letter"
},
"tags": ["react", "nodejs", "typescript"],
"expires_at": "2024-03-15T23:59:59Z",
"visibility": "public"
}

Response:

{
"success": true,
"opportunity": {
"id": "opp_new123",
"title": "Senior Full-Stack Developer",
"status": "pending",
"created_at": "2024-01-20T15:30:00Z"
},
"message": "Opportunity created successfully and is pending review"
}

PUT /api/opportunities/updateโ€‹

Update an existing opportunity. Requires authentication and ownership/admin permissions.

Authentication: Required (Owner or Admin)

Request Body:

{
"id": "opp_123",
"title": "Updated Senior Full-Stack Developer Position",
"description": "Updated description...",
"budget": {
"min": 3500,
"max": 5500,
"currency": "USD",
"per": "month"
},
"status": "active",
"updated_fields": ["title", "description", "budget"]
}

Response:

{
"success": true,
"opportunity": {
"id": "opp_123",
"updated_at": "2024-01-20T16:45:00Z"
},
"message": "Opportunity updated successfully"
}

DELETE /api/opportunities/delete/[id]โ€‹

Delete an opportunity. Requires authentication and ownership/admin permissions.

Authentication: Required (Owner or Admin)

Path Parameters:

  • id (string, required) - Opportunity identifier

Response:

{
"success": true,
"message": "Opportunity deleted successfully"
}

File Managementโ€‹

POST /api/opportunities/uploadโ€‹

Upload files and attachments for opportunities.

Authentication: Required

Content-Type: multipart/form-data

Form Data:

  • file (File, required) - File to upload
  • opportunity_id (string, required) - Opportunity identifier
  • description (string, optional) - File description

Response:

{
"success": true,
"attachment": {
"id": "att_789",
"name": "job_requirements.pdf",
"url": "https://storage.com/attachments/job_req.pdf",
"size": 245760,
"uploaded_at": "2024-01-20T17:00:00Z"
}
}

Premium Contentโ€‹

GET /api/confidential/opportunitiesโ€‹

Access confidential opportunities for premium members.

Authentication: Required (Confidential role or higher)

Query Parameters: Same as regular opportunities endpoint

Response: Similar structure to regular opportunities but includes premium content

Frontend Integrationโ€‹

Page Routesโ€‹

The opportunities system is fully integrated with Next.js 15 App Router:

/[locale]/opportunitiesโ€‹

Bundle Size: 1.95 kB + 106 kB

  • Opportunity listing page with filtering and search
  • Pagination and infinite scroll support
  • Category-based navigation
  • Responsive grid layout

/[locale]/opportunities/[id]โ€‹

Bundle Size: 1.95 kB + 106 kB

  • Detailed opportunity view
  • Application process integration
  • Related opportunities suggestions
  • Social sharing capabilities

/[locale]/opportunities/addโ€‹

Bundle Size: 3.98 kB + 295 kB

  • Opportunity creation form
  • Rich text editor for descriptions
  • File upload interface
  • Form validation and error handling

/[locale]/confidential/opportunitiesโ€‹

Bundle Size: 1.26 kB + 112 kB

  • Premium opportunities for verified members
  • Enhanced opportunity details
  • Priority application processing

React Componentsโ€‹

Key components for opportunities functionality:

// Opportunity listing component
<OpportunityList
opportunities={opportunities}
filters={filters}
onFilterChange={handleFilterChange}
pagination={pagination}
/>

// Opportunity card component
<OpportunityCard
opportunity={opportunity}
showActions={true}
compact={false}
/>

// Opportunity creation form
<OpportunityForm
onSubmit={handleSubmit}
initialData={initialData}
entityId={entityId}
/>

// Application process component
<ApplicationProcess
opportunity={opportunity}
user={user}
onApply={handleApplication}
/>

Service Architectureโ€‹

Data Modelsโ€‹

Opportunity Model:

interface Opportunity {
id: string
title: string
description: string
short_description?: string
category: string
type: 'job' | 'project' | 'collaboration'
budget?: {
min?: number
max?: number
currency: string
per: 'hour' | 'day' | 'month' | 'project'
}
location: {
city?: string
country?: string
remote: boolean
timezone?: string
}
requirements: string[]
benefits: string[]
entity_id: string
entity?: Entity
contact_person?: ContactPerson
application_process: ApplicationProcess
attachments: Attachment[]
tags: string[]
status: 'draft' | 'pending' | 'active' | 'expired' | 'closed'
visibility: 'public' | 'members' | 'confidential'
created_at: string
updated_at: string
expires_at?: string
views: number
applications: number
is_featured: boolean
}

Database Operationsโ€‹

The service uses Firebase Firestore with optimized queries:

// Collection reference
const opportunitiesRef = collection(db, 'opportunities')

// Query with filters
const query = query(
opportunitiesRef,
where('status', '==', 'active'),
where('category', 'in', categories),
orderBy('created_at', 'desc'),
limit(10)
)

// Real-time subscription
const unsubscribe = onSnapshot(query, (snapshot) => {
const opportunities = snapshot.docs.map(doc => ({
id: doc.id,
...doc.data()
}))
})

Authentication & Authorizationโ€‹

Access control is implemented at multiple levels:

Public Access:

  • View active opportunities
  • Browse categories and filters
  • Access opportunity details

Member Access:

  • Create opportunities (with entity ownership)
  • Update owned opportunities
  • Access application tracking

Confidential Access:

  • View confidential opportunities
  • Priority placement in listings
  • Enhanced opportunity analytics

Admin Access:

  • Moderate all opportunities
  • Manage opportunity categories
  • Access comprehensive analytics

Integration Examplesโ€‹

Creating an Opportunityโ€‹

import { createOpportunity } from '@/lib/opportunities-service'

const handleCreateOpportunity = async (formData: OpportunityFormData) => {
try {
const opportunity = await createOpportunity({
title: formData.title,
description: formData.description,
category: formData.category,
type: formData.type,
budget: formData.budget,
location: formData.location,
requirements: formData.requirements,
entity_id: userEntity.id,
expires_at: formData.expiresAt
})

router.push(`/${locale}/opportunities/${opportunity.id}`)
} catch (error) {
toast.error('Failed to create opportunity')
}
}

Searching Opportunitiesโ€‹

import { searchOpportunities } from '@/lib/opportunities-service'

const handleSearch = async (filters: OpportunityFilters) => {
try {
const result = await searchOpportunities({
search: filters.search,
category: filters.category,
location: filters.location,
remote: filters.remote,
budget_min: filters.budgetMin,
budget_max: filters.budgetMax,
page: filters.page,
limit: 20
})

setOpportunities(result.opportunities)
setPagination(result.pagination)
} catch (error) {
toast.error('Search failed')
}
}

Applying to Opportunityโ€‹

import { applyToOpportunity } from '@/lib/opportunities-service'

const handleApply = async (opportunityId: string, applicationData: ApplicationData) => {
try {
await applyToOpportunity(opportunityId, {
cover_letter: applicationData.coverLetter,
cv_url: applicationData.cvUrl,
portfolio_url: applicationData.portfolioUrl,
availability: applicationData.availability
})

toast.success('Application submitted successfully')
} catch (error) {
toast.error('Failed to submit application')
}
}

Performance Optimizationโ€‹

Caching Strategyโ€‹

  • Client-side caching using React Query for opportunity listings
  • Server-side caching for frequently accessed opportunities
  • CDN caching for opportunity attachments and images
  • Database indexing on commonly filtered fields

Bundle Optimizationโ€‹

The opportunities system is optimized for performance:

  • Code splitting with dynamic imports for heavy components
  • Lazy loading for opportunity images and attachments
  • Pagination to limit data transfer
  • Optimistic updates for improved user experience

SEO & Internationalizationโ€‹

  • Localized URLs (/en/opportunities, /uk/opportunities)
  • Meta tags with opportunity-specific information
  • Schema.org markup for job posting structured data
  • Sitemap generation for opportunity pages
  • Hreflang tags for multilingual SEO

Error Handlingโ€‹

Comprehensive error handling across the service:

// API error responses
{
"error": true,
"code": "OPPORTUNITY_NOT_FOUND",
"message": "The requested opportunity could not be found",
"details": {
"opportunity_id": "opp_123",
"timestamp": "2024-01-20T18:00:00Z"
}
}

// Common error codes
- OPPORTUNITY_NOT_FOUND
- UNAUTHORIZED_ACCESS
- VALIDATION_ERROR
- ENTITY_REQUIRED
- QUOTA_EXCEEDED
- UPLOAD_FAILED

Monitoring & Analyticsโ€‹

Metrics Trackedโ€‹

  • Opportunity views and engagement metrics
  • Application conversion rates by category
  • Search performance and popular filters
  • User interaction patterns and drop-off points
  • File upload success rates and performance

Performance Monitoringโ€‹

  • API response times for all endpoints
  • Database query performance optimization
  • Bundle size monitoring for frontend components
  • Error rate tracking and alerting

The Opportunities Service provides a comprehensive, scalable solution for managing job postings and project opportunities within the Ring platform, with full internationalization support and optimized performance.