Concepts, value, and typical clone scenarios — less code.
Concepts, value, and typical clone scenarios — less code.
Preparing Ring Platform content
Preparing Ring Platform content
Preparing Ring Platform content
Ring Opportunities is the supply ↔ demand loop for each clone: members post offers and requests (plus specialized types), Matcher scores interested users, and notifications invite them to connect — without waiting for someone to search the feed.
Use Founder / Developer tabs in the docs sidebar to filter this page. audience frontmatter controls in-page blocks; sidebar visibility is controlled by lib/docs/audience-curated-docs.ts.
Older copy claimed fixed accuracy %, hire-cost savings, and “15k+ users.” Those figures are deprecated. Live numbers come from Admin → Matcher analytics and clone traffic. Matcher thresholds are config (ring-config.json → matcher, overridable in platform settings) — not kingdom-wide SLAs.
| Previous | Ring equivalent |
|---|---|
| Post job → hope someone searches | Post opportunity → Matcher scores candidates → notify with short explanations |
| Offers only (employer → talent) | Dual-nature: offer and request plus specialized types |
| One listing taxonomy | White-label opportunities.enabledTypes gate (16 defaults in Layer1 / org config) |
| Manual enrichment | Optional LLM auto-fill on create (OpportunityAutoFillService) |
| Opaque ranking | Eight scored factors (MatchFactors in lib/ai/types.ts) + configurable scoreThreshold |
| Separate funding jars | Collective / builder jars via Public Pools (donation path live; on-chain escrow gated) |
Default Matcher install values (ring-config.json → matcher): scoreThreshold 0.7, maxMatches 10, autoApprove false, autoApproveMinScore 0.7, llmConfidenceGate 0.8. Env can override auto-approve via MATCHER_AUTO_APPROVE / MATCHER_AUTO_APPROVE_MIN_SCORE (see features/admin/platform-settings/matcher-config.ts). Cap matches with MAX_MATCHES_PER_OPPORTUNITY.
MatchFactors in lib/ai/types.ts (0–100 each): skillMatch, experienceMatch, industryMatch, locationMatch, budgetMatch, availabilityMatch, careerMatch, cultureMatch. LLM match runs populate this bag; the non-LLM heuristic path in lib/ai/matcher.ts blends skill / tag / location / experience with its own internal weights — do not treat AI-CONTEXT percentage tables as runtime SSOT.
Explanations aim for ≤160 characters (MatchingService truncates longer LLM text). Quality bands in matching results: high ≥80, medium 60–79, low <60 — for analytics, not a published accuracy KPI.
Opportunities turn your Ring into a local marketplace of intent: people publish what they can provide and what they need. Matcher pushes relevant invitations instead of relying on feed scroll. Specialized types (jobs, collective orders, scheduled services, program/investment → CRM, Ring customization quests) are gated per clone so you ship only the loops your vertical needs.
Use the ring-ai-matcher-specialist (or Cursor skill of the same family) with a pause-for-approval prompt:
“Audit this clone’s Opportunities loop: list
opportunities.enabledTypesandmatcherfromring-config.json, confirm LLM env is set, dry-run create of oneofferand onerequest, report MatchFactors and whetherautoApprovewould promote pending→active. Do not change platform_settings until I approve.”
Inputs checklist: clone key, admin access, LLM credentials present, sample entity id for organizationId.
Set opportunities.enabledTypes and matcher.* in ring-config.json; redeploy or reload config snapshot as your clone does for ring-config.
In Admin → Matcher / AI settings, leave auto-approve off; set scoreThreshold / maxMatches to match your vertical tolerance.
Create a test opportunity from the type selector UI (or POST /api/opportunities); open My Opportunities at /opportunities/my.
Confirm a matched user received a notification and that discovery lists refresh (Tunnel / soft refresh) without inventing a search-index reindex step.
No. Default matcher.autoApprove is false. When enabled, maybeAutoApproveOpportunity still requires score and LLM confidence gates (autoApproveMinScore, llmConfidenceGate).
No. Treat historical marketing percentages as deprecated. Use Admin Matcher analytics for your tenant.
Only when DB_BACKEND_MODE=firebase-full. PostgreSQL clones use opportunity-db-mapper.ts and SerializedOpportunity.
/opportunities/my-opportunities go?Removed. Canonical dashboard is /opportunities/my via ROUTES.MY_OPPORTUNITIES.
Check LLM availability, Matcher score threshold, maxMatches, and entity block filters in matcher-notification-filter. Notifications go through features/notifications/services/notification-service.
Opportunity specializations can carry JSONB metadata (e.g. collective order slots). Community funding jars and builder payout SSOT are documented under Public Pools — do not invent PSP “donation product” APIs as the jar path.
Next-step: REST route contract and payloads after you understand the create → match pipeline.
Depends-on: how syncOpportunityDiscovery invalidates cache and publishes Tunnel events.
Same-workflow: organization linkage and verified posters for opportunities.
Same-workflow: match invitations are delivered as platform notifications.
Ring Opportunities is the supply ↔ demand loop for each clone: members post offers and requests (plus specialized types), Matcher scores interested users, and notifications invite them to connect — without waiting for someone to search the feed.
Use Founder / Developer tabs in the docs sidebar to filter this page. audience frontmatter controls in-page blocks; sidebar visibility is controlled by lib/docs/audience-curated-docs.ts.
Older copy claimed fixed accuracy %, hire-cost savings, and “15k+ users.” Those figures are deprecated. Live numbers come from Admin → Matcher analytics and clone traffic. Matcher thresholds are config (ring-config.json → matcher, overridable in platform settings) — not kingdom-wide SLAs.
| Previous | Ring equivalent |
|---|---|
| Post job → hope someone searches | Post opportunity → Matcher scores candidates → notify with short explanations |
| Offers only (employer → talent) | Dual-nature: offer and request plus specialized types |
| One listing taxonomy | White-label opportunities.enabledTypes gate (16 defaults in Layer1 / org config) |
| Manual enrichment | Optional LLM auto-fill on create (OpportunityAutoFillService) |
| Opaque ranking | Eight scored factors (MatchFactors in lib/ai/types.ts) + configurable scoreThreshold |
| Separate funding jars | Collective / builder jars via Public Pools (donation path live; on-chain escrow gated) |
Default Matcher install values (ring-config.json → matcher): scoreThreshold 0.7, maxMatches 10, autoApprove false, autoApproveMinScore 0.7, llmConfidenceGate 0.8. Env can override auto-approve via MATCHER_AUTO_APPROVE / MATCHER_AUTO_APPROVE_MIN_SCORE (see features/admin/platform-settings/matcher-config.ts). Cap matches with MAX_MATCHES_PER_OPPORTUNITY.
MatchFactors in lib/ai/types.ts (0–100 each): skillMatch, experienceMatch, industryMatch, locationMatch, budgetMatch, availabilityMatch, careerMatch, cultureMatch. LLM match runs populate this bag; the non-LLM heuristic path in lib/ai/matcher.ts blends skill / tag / location / experience with its own internal weights — do not treat AI-CONTEXT percentage tables as runtime SSOT.
Explanations aim for ≤160 characters (MatchingService truncates longer LLM text). Quality bands in matching results: high ≥80, medium 60–79, low <60 — for analytics, not a published accuracy KPI.
Opportunities turn your Ring into a local marketplace of intent: people publish what they can provide and what they need. Matcher pushes relevant invitations instead of relying on feed scroll. Specialized types (jobs, collective orders, scheduled services, program/investment → CRM, Ring customization quests) are gated per clone so you ship only the loops your vertical needs.
Use the ring-ai-matcher-specialist (or Cursor skill of the same family) with a pause-for-approval prompt:
“Audit this clone’s Opportunities loop: list
opportunities.enabledTypesandmatcherfromring-config.json, confirm LLM env is set, dry-run create of oneofferand onerequest, report MatchFactors and whetherautoApprovewould promote pending→active. Do not change platform_settings until I approve.”
Inputs checklist: clone key, admin access, LLM credentials present, sample entity id for organizationId.
Set opportunities.enabledTypes and matcher.* in ring-config.json; redeploy or reload config snapshot as your clone does for ring-config.
In Admin → Matcher / AI settings, leave auto-approve off; set scoreThreshold / maxMatches to match your vertical tolerance.
Create a test opportunity from the type selector UI (or POST /api/opportunities); open My Opportunities at /opportunities/my.
Confirm a matched user received a notification and that discovery lists refresh (Tunnel / soft refresh) without inventing a search-index reindex step.
No. Default matcher.autoApprove is false. When enabled, maybeAutoApproveOpportunity still requires score and LLM confidence gates (autoApproveMinScore, llmConfidenceGate).
No. Treat historical marketing percentages as deprecated. Use Admin Matcher analytics for your tenant.
Only when DB_BACKEND_MODE=firebase-full. PostgreSQL clones use opportunity-db-mapper.ts and SerializedOpportunity.
/opportunities/my-opportunities go?Removed. Canonical dashboard is /opportunities/my via ROUTES.MY_OPPORTUNITIES.
Check LLM availability, Matcher score threshold, maxMatches, and entity block filters in matcher-notification-filter. Notifications go through features/notifications/services/notification-service.
Opportunity specializations can carry JSONB metadata (e.g. collective order slots). Community funding jars and builder payout SSOT are documented under Public Pools — do not invent PSP “donation product” APIs as the jar path.
Next-step: REST route contract and payloads after you understand the create → match pipeline.
Depends-on: how syncOpportunityDiscovery invalidates cache and publishes Tunnel events.
Same-workflow: organization linkage and verified posters for opportunities.
Same-workflow: match invitations are delivered as platform notifications.
Ring Opportunities is the supply ↔ demand loop for each clone: members post offers and requests (plus specialized types), Matcher scores interested users, and notifications invite them to connect — without waiting for someone to search the feed.
Use Founder / Developer tabs in the docs sidebar to filter this page. audience frontmatter controls in-page blocks; sidebar visibility is controlled by lib/docs/audience-curated-docs.ts.
Older copy claimed fixed accuracy %, hire-cost savings, and “15k+ users.” Those figures are deprecated. Live numbers come from Admin → Matcher analytics and clone traffic. Matcher thresholds are config (ring-config.json → matcher, overridable in platform settings) — not kingdom-wide SLAs.
| Previous | Ring equivalent |
|---|---|
| Post job → hope someone searches | Post opportunity → Matcher scores candidates → notify with short explanations |
| Offers only (employer → talent) | Dual-nature: offer and request plus specialized types |
| One listing taxonomy | White-label opportunities.enabledTypes gate (16 defaults in Layer1 / org config) |
| Manual enrichment | Optional LLM auto-fill on create (OpportunityAutoFillService) |
| Opaque ranking | Eight scored factors (MatchFactors in lib/ai/types.ts) + configurable scoreThreshold |
| Separate funding jars | Collective / builder jars via Public Pools (donation path live; on-chain escrow gated) |
Default Matcher install values (ring-config.json → matcher): scoreThreshold 0.7, maxMatches 10, autoApprove false, autoApproveMinScore 0.7, llmConfidenceGate 0.8. Env can override auto-approve via MATCHER_AUTO_APPROVE / MATCHER_AUTO_APPROVE_MIN_SCORE (see features/admin/platform-settings/matcher-config.ts). Cap matches with MAX_MATCHES_PER_OPPORTUNITY.
MatchFactors in lib/ai/types.ts (0–100 each): skillMatch, experienceMatch, industryMatch, locationMatch, budgetMatch, availabilityMatch, careerMatch, cultureMatch. LLM match runs populate this bag; the non-LLM heuristic path in lib/ai/matcher.ts blends skill / tag / location / experience with its own internal weights — do not treat AI-CONTEXT percentage tables as runtime SSOT.
Explanations aim for ≤160 characters (MatchingService truncates longer LLM text). Quality bands in matching results: high ≥80, medium 60–79, low <60 — for analytics, not a published accuracy KPI.
Opportunities turn your Ring into a local marketplace of intent: people publish what they can provide and what they need. Matcher pushes relevant invitations instead of relying on feed scroll. Specialized types (jobs, collective orders, scheduled services, program/investment → CRM, Ring customization quests) are gated per clone so you ship only the loops your vertical needs.
Use the ring-ai-matcher-specialist (or Cursor skill of the same family) with a pause-for-approval prompt:
“Audit this clone’s Opportunities loop: list
opportunities.enabledTypesandmatcherfromring-config.json, confirm LLM env is set, dry-run create of oneofferand onerequest, report MatchFactors and whetherautoApprovewould promote pending→active. Do not change platform_settings until I approve.”
Inputs checklist: clone key, admin access, LLM credentials present, sample entity id for organizationId.
Set opportunities.enabledTypes and matcher.* in ring-config.json; redeploy or reload config snapshot as your clone does for ring-config.
In Admin → Matcher / AI settings, leave auto-approve off; set scoreThreshold / maxMatches to match your vertical tolerance.
Create a test opportunity from the type selector UI (or POST /api/opportunities); open My Opportunities at /opportunities/my.
Confirm a matched user received a notification and that discovery lists refresh (Tunnel / soft refresh) without inventing a search-index reindex step.
No. Default matcher.autoApprove is false. When enabled, maybeAutoApproveOpportunity still requires score and LLM confidence gates (autoApproveMinScore, llmConfidenceGate).
No. Treat historical marketing percentages as deprecated. Use Admin Matcher analytics for your tenant.
Only when DB_BACKEND_MODE=firebase-full. PostgreSQL clones use opportunity-db-mapper.ts and SerializedOpportunity.
/opportunities/my-opportunities go?Removed. Canonical dashboard is /opportunities/my via ROUTES.MY_OPPORTUNITIES.
Check LLM availability, Matcher score threshold, maxMatches, and entity block filters in matcher-notification-filter. Notifications go through features/notifications/services/notification-service.
Opportunity specializations can carry JSONB metadata (e.g. collective order slots). Community funding jars and builder payout SSOT are documented under Public Pools — do not invent PSP “donation product” APIs as the jar path.
Next-step: REST route contract and payloads after you understand the create → match pipeline.
Depends-on: how syncOpportunityDiscovery invalidates cache and publishes Tunnel events.
Same-workflow: organization linkage and verified posters for opportunities.
Same-workflow: match invitations are delivered as platform notifications.
publicPools.platformFeePercentByRolejob, offer, request, partnership; keep Matcher auto-approve off until you trust scoring.collective_order, scheduled_services, asset_rental, bounty, tender with Wallet / PaymentConductor rails.ring_customization and program so customization quests and institution programs land in CRM.opportunities.opportunities.enabledTypes in ring-config.json (do not assume every OpportunityType union member is UI-visible).LLM_PROVIDER, OPENAI_API_KEY or ANTHROPIC_API_KEY, LLM_MODEL) before expecting auto-fill / LLM explanations./opportunities/my (ROUTES.MY_OPPORTUNITIES) — legacy /opportunities/my-opportunities is removed.features/opportunities/services/auto-fill-service.ts |
| Auto-approve | features/opportunities/services/auto-approval-service.ts |
| PG JSONB ↔ client | features/opportunities/lib/opportunity-db-mapper.ts |
| Post-mutation sync | features/opportunities/lib/opportunity-mutation-sync.ts → syncOpportunityDiscovery |
| Program → CRM | features/opportunities/lib/program-crm-ingest.ts |
| UI Server Actions | app/_actions/opportunities.ts |
| Firestore legacy | lib/converters/opportunity-converter.ts when DB_BACKEND_MODE=firebase-full only |
Database: default production clones use DB_BACKEND_MODE=k8s-postgres-fcm (also supabase-fcm). Services return SerializedOpportunity (ISO date strings). Do not invent DATABASE_MODE=firebase_only.
public | subscriber | member | confidentialdraft | pending | active | closed | expired | archivedcanCreateOpportunityConfidential / canEditOpportunity)| Bucket | Types (examples) | Minimum role |
|---|---|---|
| Member offers | offer, job, partnership, volunteer, mentorship, resource, event, ring_customization, program, collective_order, tender, asset_rental | member privileges |
| Requests | request | subscriber+ |
| Subscriber specials | cv, scheduled_services, bounty | subscriber+ |
| Other union members | e.g. future-facing types not in enabled/permission sets | admin+ (and must be enabled) |
| Method | Route | Service |
|---|---|---|
GET / POST | /api/opportunities | getOpportunitiesForRole / createOpportunity |
GET / PUT / PATCH / DELETE | /api/opportunities/[id] | get / update / delete |
GET / POST | /api/opportunities/search | searchOpportunities |
GET | /api/opportunities/my | user-owned list |
POST | /api/opportunities/upload | attachments |
UI forms may still prefer Server Actions in app/_actions/opportunities.ts.
Authenticate and call createOpportunity with a permitted type. Default type when omitted is offer.
Search with role-aware filters (query, types, budget band, sortBy).
After mutations, rely on syncOpportunityDiscovery (already called from create/update/delete paths): invalidates opportunity cache tags, revalidatePath for /[locale]/opportunities, detail, and /[locale]/opportunities/my, and publishes Tunnel discovery for channel opportunities. This is not a separate full-text index reindex CLI.
Keys documented in env.local.template: LLM_PROVIDER, OPENAI_API_KEY, ANTHROPIC_API_KEY, LLM_MODEL, MAX_MATCHES_PER_OPPORTUNITY, MATCHING_MAX_TOKENS. Without a working provider, Matcher falls back to non-LLM / tag-style explanations with lower confidence.
See-also: collective / builder jar payouts tied to opportunity owners.
publicPools.platformFeePercentByRolejob, offer, request, partnership; keep Matcher auto-approve off until you trust scoring.collective_order, scheduled_services, asset_rental, bounty, tender with Wallet / PaymentConductor rails.ring_customization and program so customization quests and institution programs land in CRM.opportunities.opportunities.enabledTypes in ring-config.json (do not assume every OpportunityType union member is UI-visible).LLM_PROVIDER, OPENAI_API_KEY or ANTHROPIC_API_KEY, LLM_MODEL) before expecting auto-fill / LLM explanations./opportunities/my (ROUTES.MY_OPPORTUNITIES) — legacy /opportunities/my-opportunities is removed.features/opportunities/services/auto-fill-service.ts |
| Auto-approve | features/opportunities/services/auto-approval-service.ts |
| PG JSONB ↔ client | features/opportunities/lib/opportunity-db-mapper.ts |
| Post-mutation sync | features/opportunities/lib/opportunity-mutation-sync.ts → syncOpportunityDiscovery |
| Program → CRM | features/opportunities/lib/program-crm-ingest.ts |
| UI Server Actions | app/_actions/opportunities.ts |
| Firestore legacy | lib/converters/opportunity-converter.ts when DB_BACKEND_MODE=firebase-full only |
Database: default production clones use DB_BACKEND_MODE=k8s-postgres-fcm (also supabase-fcm). Services return SerializedOpportunity (ISO date strings). Do not invent DATABASE_MODE=firebase_only.
public | subscriber | member | confidentialdraft | pending | active | closed | expired | archivedcanCreateOpportunityConfidential / canEditOpportunity)| Bucket | Types (examples) | Minimum role |
|---|---|---|
| Member offers | offer, job, partnership, volunteer, mentorship, resource, event, ring_customization, program, collective_order, tender, asset_rental | member privileges |
| Requests | request | subscriber+ |
| Subscriber specials | cv, scheduled_services, bounty | subscriber+ |
| Other union members | e.g. future-facing types not in enabled/permission sets | admin+ (and must be enabled) |
| Method | Route | Service |
|---|---|---|
GET / POST | /api/opportunities | getOpportunitiesForRole / createOpportunity |
GET / PUT / PATCH / DELETE | /api/opportunities/[id] | get / update / delete |
GET / POST | /api/opportunities/search | searchOpportunities |
GET | /api/opportunities/my | user-owned list |
POST | /api/opportunities/upload | attachments |
UI forms may still prefer Server Actions in app/_actions/opportunities.ts.
Authenticate and call createOpportunity with a permitted type. Default type when omitted is offer.
Search with role-aware filters (query, types, budget band, sortBy).
After mutations, rely on syncOpportunityDiscovery (already called from create/update/delete paths): invalidates opportunity cache tags, revalidatePath for /[locale]/opportunities, detail, and /[locale]/opportunities/my, and publishes Tunnel discovery for channel opportunities. This is not a separate full-text index reindex CLI.
Keys documented in env.local.template: LLM_PROVIDER, OPENAI_API_KEY, ANTHROPIC_API_KEY, LLM_MODEL, MAX_MATCHES_PER_OPPORTUNITY, MATCHING_MAX_TOKENS. Without a working provider, Matcher falls back to non-LLM / tag-style explanations with lower confidence.
See-also: collective / builder jar payouts tied to opportunity owners.
publicPools.platformFeePercentByRolejob, offer, request, partnership; keep Matcher auto-approve off until you trust scoring.collective_order, scheduled_services, asset_rental, bounty, tender with Wallet / PaymentConductor rails.ring_customization and program so customization quests and institution programs land in CRM.opportunities.opportunities.enabledTypes in ring-config.json (do not assume every OpportunityType union member is UI-visible).LLM_PROVIDER, OPENAI_API_KEY or ANTHROPIC_API_KEY, LLM_MODEL) before expecting auto-fill / LLM explanations./opportunities/my (ROUTES.MY_OPPORTUNITIES) — legacy /opportunities/my-opportunities is removed.features/opportunities/services/auto-fill-service.ts |
| Auto-approve | features/opportunities/services/auto-approval-service.ts |
| PG JSONB ↔ client | features/opportunities/lib/opportunity-db-mapper.ts |
| Post-mutation sync | features/opportunities/lib/opportunity-mutation-sync.ts → syncOpportunityDiscovery |
| Program → CRM | features/opportunities/lib/program-crm-ingest.ts |
| UI Server Actions | app/_actions/opportunities.ts |
| Firestore legacy | lib/converters/opportunity-converter.ts when DB_BACKEND_MODE=firebase-full only |
Database: default production clones use DB_BACKEND_MODE=k8s-postgres-fcm (also supabase-fcm). Services return SerializedOpportunity (ISO date strings). Do not invent DATABASE_MODE=firebase_only.
public | subscriber | member | confidentialdraft | pending | active | closed | expired | archivedcanCreateOpportunityConfidential / canEditOpportunity)| Bucket | Types (examples) | Minimum role |
|---|---|---|
| Member offers | offer, job, partnership, volunteer, mentorship, resource, event, ring_customization, program, collective_order, tender, asset_rental | member privileges |
| Requests | request | subscriber+ |
| Subscriber specials | cv, scheduled_services, bounty | subscriber+ |
| Other union members | e.g. future-facing types not in enabled/permission sets | admin+ (and must be enabled) |
| Method | Route | Service |
|---|---|---|
GET / POST | /api/opportunities | getOpportunitiesForRole / createOpportunity |
GET / PUT / PATCH / DELETE | /api/opportunities/[id] | get / update / delete |
GET / POST | /api/opportunities/search | searchOpportunities |
GET | /api/opportunities/my | user-owned list |
POST | /api/opportunities/upload | attachments |
UI forms may still prefer Server Actions in app/_actions/opportunities.ts.
Authenticate and call createOpportunity with a permitted type. Default type when omitted is offer.
Search with role-aware filters (query, types, budget band, sortBy).
After mutations, rely on syncOpportunityDiscovery (already called from create/update/delete paths): invalidates opportunity cache tags, revalidatePath for /[locale]/opportunities, detail, and /[locale]/opportunities/my, and publishes Tunnel discovery for channel opportunities. This is not a separate full-text index reindex CLI.
Keys documented in env.local.template: LLM_PROVIDER, OPENAI_API_KEY, ANTHROPIC_API_KEY, LLM_MODEL, MAX_MATCHES_PER_OPPORTUNITY, MATCHING_MAX_TOKENS. Without a working provider, Matcher falls back to non-LLM / tag-style explanations with lower confidence.
See-also: collective / builder jar payouts tied to opportunity owners.