Concepts, value, and typical clone scenarios — less code.
Concepts, value, and typical clone scenarios — less code.
Підготовка контенту платформи Ring
Підготовка контенту платформи Ring
Підготовка контенту платформи Ring
Use Founder / Developer tabs in the docs sidebar to filter this page. Ring Tasks extend messaging with a structured task message type — not a separate CRM product (admin email CRM tasks at /admin/crm/tasks are unrelated).
Members send each other tasks inside chat: description, optional assignee, deadline, budget, and optional credit escrow. A global /tasks tree lists recent tasks across conversations. Reporters can convert a task into a personal request opportunity.
| Layer | Where |
|---|---|
| Types | features/chat/types/index.ts — Message.type: 'task', TaskMetadata |
| Feature module | features/tasks/** |
| Server actions | app/_actions/tasks.ts |
| List APIs | GET /api/tasks, GET /api/tasks/conversation/[id] |
| Pages | /tasks, /tasks/[chatId] |
| Chat deep link | /messages?c=<conversationId> (no /messages/[id] segment) |
| Status | Meaning |
|---|---|
available | Posted without assignee |
requested | Someone asked to be assignee |
in_progress | Assignee set |
completed | Done by reporter or assignee |
accepted | Reporter accepted work (releases escrow if held) |
canceled | Reporter canceled (refunds held escrow to credit balance) |
disputed | Reporter disputed after completed + held escrow |
Messages alone do not close work. Tasks turn a chat into a lightweight work agreement: who owns it, when it is due, and whether payment is held until acceptance.
Tasks appear as widgets inside the same conversation roster.
Convert a task into a public/private request when you need marketplace reach.
Escrow v1 holds and releases credit balance (points).
Prerequisite: tasks are chat message widgets inside the same conversation roster.
Next-step: convert a task into a marketplace request opportunity.
Depends-on: task escrow v1 holds and releases credit balance points.
Deep-dive: PaymentPurpose task_escrow reuses Conductor rails.
Use Founder / Developer tabs in the docs sidebar to filter this page. Ring Tasks extend messaging with a structured task message type — not a separate CRM product (admin email CRM tasks at /admin/crm/tasks are unrelated).
Members send each other tasks inside chat: description, optional assignee, deadline, budget, and optional credit escrow. A global /tasks tree lists recent tasks across conversations. Reporters can convert a task into a personal request opportunity.
| Layer | Where |
|---|---|
| Types | features/chat/types/index.ts — Message.type: 'task', TaskMetadata |
| Feature module | features/tasks/** |
| Server actions | app/_actions/tasks.ts |
| List APIs | GET /api/tasks, GET /api/tasks/conversation/[id] |
| Pages | /tasks, /tasks/[chatId] |
| Chat deep link | /messages?c=<conversationId> (no /messages/[id] segment) |
| Status | Meaning |
|---|---|
available | Posted without assignee |
requested | Someone asked to be assignee |
in_progress | Assignee set |
completed | Done by reporter or assignee |
accepted | Reporter accepted work (releases escrow if held) |
canceled | Reporter canceled (refunds held escrow to credit balance) |
disputed | Reporter disputed after completed + held escrow |
Messages alone do not close work. Tasks turn a chat into a lightweight work agreement: who owns it, when it is due, and whether payment is held until acceptance.
Tasks appear as widgets inside the same conversation roster.
Convert a task into a public/private request when you need marketplace reach.
Escrow v1 holds and releases credit balance (points).
Prerequisite: tasks are chat message widgets inside the same conversation roster.
Next-step: convert a task into a marketplace request opportunity.
Depends-on: task escrow v1 holds and releases credit balance points.
Deep-dive: PaymentPurpose task_escrow reuses Conductor rails.
Use Founder / Developer tabs in the docs sidebar to filter this page. Ring Tasks extend messaging with a structured task message type — not a separate CRM product (admin email CRM tasks at /admin/crm/tasks are unrelated).
Members send each other tasks inside chat: description, optional assignee, deadline, budget, and optional credit escrow. A global /tasks tree lists recent tasks across conversations. Reporters can convert a task into a personal request opportunity.
| Layer | Where |
|---|---|
| Types | features/chat/types/index.ts — Message.type: 'task', TaskMetadata |
| Feature module | features/tasks/** |
| Server actions | app/_actions/tasks.ts |
| List APIs | GET /api/tasks, GET /api/tasks/conversation/[id] |
| Pages | /tasks, /tasks/[chatId] |
| Chat deep link | /messages?c=<conversationId> (no /messages/[id] segment) |
| Status | Meaning |
|---|---|
available | Posted without assignee |
requested | Someone asked to be assignee |
in_progress | Assignee set |
completed | Done by reporter or assignee |
accepted | Reporter accepted work (releases escrow if held) |
canceled | Reporter canceled (refunds held escrow to credit balance) |
disputed | Reporter disputed after completed + held escrow |
Messages alone do not close work. Tasks turn a chat into a lightweight work agreement: who owns it, when it is due, and whether payment is held until acceptance.
Tasks appear as widgets inside the same conversation roster.
Convert a task into a public/private request when you need marketplace reach.
Escrow v1 holds and releases credit balance (points).
Prerequisite: tasks are chat message widgets inside the same conversation roster.
Next-step: convert a task into a marketplace request opportunity.
Depends-on: task escrow v1 holds and releases credit balance points.
Deep-dive: PaymentPurpose task_escrow reuses Conductor rails.
/tasks).PaymentPurpose.task_escrow)./admin/crm/task-escrows — release, refund, or force cancel held escrows.audit[]versions[]Widget render path mirrors payment/env requests in features/chat/components/message-bubble.tsx → TaskMessageWidget.
| Module | Role |
|---|---|
features/tasks/services/task-service.ts | Status transitions + audit |
features/tasks/services/task-query-service.ts | Tree query (3/chat, max 21) + per-chat list |
features/tasks/services/task-escrow-service.ts | Credit / WFP / native hold, refund, release |
features/tasks/services/notify.ts | TASK_ASSIGNED / TASK_UPDATED notifications |
app/api/tasks/escrow/[id]/checkout/route.ts | PaymentConductor checkout for pending escrow |
features/tasks/components/task-message-widget.tsx | In-chat actions |
features/tasks/components/task-compose-dialog.tsx | Create UI from composer |
features/tasks/components/tasks-tree.tsx | /tasks filter tabs |
app/_actions/tasks.ts | Server actions |
Notifications: NotificationType.TASK_ASSIGNED, TASK_UPDATED.
/tasks query contract| Endpoint | Behavior |
|---|---|
GET /api/tasks?filter= | all | available | in_progress | completed — up to 3 newest tasks per conversation, global cap 21 |
GET /api/tasks/conversation/[id] | All tasks in one chat |
| Filter mapping | available → available+requested; in_progress → in_progress; completed → completed+accepted |
Routes: ROUTES.TASKS, ROUTES.TASK(chatId) in constants/routes.ts.
PaymentPurpose includes task_escrow (lib/payments/conductor/types.ts). Order references: task_{escrowId}_{timestamp}.
| Event | Behavior |
|---|---|
| Fund on create (credit) | creditBalanceService.spendCredits → escrow doc held + message metadata |
| Fund on create (fiat/native) | Pending escrow doc → needsCheckout → POST /api/tasks/escrow/[id]/checkout |
| WFP/Stripe webhook / inline native | markHeldFromPayment → held + notify reporter |
| Cancel before release | Credit: addFiatUsd desk_refund + stable reference_id; WFP: refundStorePayment; native: treasury→reporter or credit equivalent fallback (same as release) |
| Accept after completed | Credit/fiat: addFiatUsd + reference_id; native: treasury→assignee or credit equivalent fallback |
| Concurrent claim | True CAS: db().transaction + FOR UPDATE — only one of accept/cancel can claim held |
| Admin dispute | /admin/crm/task-escrows — release / refund / cancel via TaskEscrowService.adminResolve |
Collection: task_escrows (JSONB doc via DatabaseService). Stable ledger refs: task_escrow_release_${id}, task_escrow_refund_${id} (stored on claim before money move).
SOLANA_TREASURY_PRIVATE_KEY, SOLANA_FEE_PAYER_PRIVATE_KEY, RPC).held escrow.features/wallet/ops/TREASURY-SWAP-OPS.md § Task escrow.convertTaskToOpportunity (reporter only, not canceled) calls createOpportunity with type: 'request', isPrivate: true, provenance in tags (sourceMessageId:…, sourceConversationId:…), stores opportunityId on task metadata.
Create a task from the chat composer (ListTodo) — optional assignee, deadline, credit budget + escrow.
Counterparty Start / Request → Done → reporter Accept (or Dispute when escrow held).
Browse /tasks or /tasks/[chatId]; open chat via /messages?c=.
Optionally Convert to opportunity → /opportunities request listing.
// app/_actions/tasks.ts (names)
createTaskMessage
startTask | requestTask | approveTaskRequest | rejectTaskRequest
completeTask | acceptTask | disputeTask | cancelTask
editTaskContent | deleteTask
convertTaskToOpportunity/tasks).PaymentPurpose.task_escrow)./admin/crm/task-escrows — release, refund, or force cancel held escrows.audit[]versions[]Widget render path mirrors payment/env requests in features/chat/components/message-bubble.tsx → TaskMessageWidget.
| Module | Role |
|---|---|
features/tasks/services/task-service.ts | Status transitions + audit |
features/tasks/services/task-query-service.ts | Tree query (3/chat, max 21) + per-chat list |
features/tasks/services/task-escrow-service.ts | Credit / WFP / native hold, refund, release |
features/tasks/services/notify.ts | TASK_ASSIGNED / TASK_UPDATED notifications |
app/api/tasks/escrow/[id]/checkout/route.ts | PaymentConductor checkout for pending escrow |
features/tasks/components/task-message-widget.tsx | In-chat actions |
features/tasks/components/task-compose-dialog.tsx | Create UI from composer |
features/tasks/components/tasks-tree.tsx | /tasks filter tabs |
app/_actions/tasks.ts | Server actions |
Notifications: NotificationType.TASK_ASSIGNED, TASK_UPDATED.
/tasks query contract| Endpoint | Behavior |
|---|---|
GET /api/tasks?filter= | all | available | in_progress | completed — up to 3 newest tasks per conversation, global cap 21 |
GET /api/tasks/conversation/[id] | All tasks in one chat |
| Filter mapping | available → available+requested; in_progress → in_progress; completed → completed+accepted |
Routes: ROUTES.TASKS, ROUTES.TASK(chatId) in constants/routes.ts.
PaymentPurpose includes task_escrow (lib/payments/conductor/types.ts). Order references: task_{escrowId}_{timestamp}.
| Event | Behavior |
|---|---|
| Fund on create (credit) | creditBalanceService.spendCredits → escrow doc held + message metadata |
| Fund on create (fiat/native) | Pending escrow doc → needsCheckout → POST /api/tasks/escrow/[id]/checkout |
| WFP/Stripe webhook / inline native | markHeldFromPayment → held + notify reporter |
| Cancel before release | Credit: addFiatUsd desk_refund + stable reference_id; WFP: refundStorePayment; native: treasury→reporter or credit equivalent fallback (same as release) |
| Accept after completed | Credit/fiat: addFiatUsd + reference_id; native: treasury→assignee or credit equivalent fallback |
| Concurrent claim | True CAS: db().transaction + FOR UPDATE — only one of accept/cancel can claim held |
| Admin dispute | /admin/crm/task-escrows — release / refund / cancel via TaskEscrowService.adminResolve |
Collection: task_escrows (JSONB doc via DatabaseService). Stable ledger refs: task_escrow_release_${id}, task_escrow_refund_${id} (stored on claim before money move).
SOLANA_TREASURY_PRIVATE_KEY, SOLANA_FEE_PAYER_PRIVATE_KEY, RPC).held escrow.features/wallet/ops/TREASURY-SWAP-OPS.md § Task escrow.convertTaskToOpportunity (reporter only, not canceled) calls createOpportunity with type: 'request', isPrivate: true, provenance in tags (sourceMessageId:…, sourceConversationId:…), stores opportunityId on task metadata.
Create a task from the chat composer (ListTodo) — optional assignee, deadline, credit budget + escrow.
Counterparty Start / Request → Done → reporter Accept (or Dispute when escrow held).
Browse /tasks or /tasks/[chatId]; open chat via /messages?c=.
Optionally Convert to opportunity → /opportunities request listing.
// app/_actions/tasks.ts (names)
createTaskMessage
startTask | requestTask | approveTaskRequest | rejectTaskRequest
completeTask | acceptTask | disputeTask | cancelTask
editTaskContent | deleteTask
convertTaskToOpportunity/tasks).PaymentPurpose.task_escrow)./admin/crm/task-escrows — release, refund, or force cancel held escrows.audit[]versions[]Widget render path mirrors payment/env requests in features/chat/components/message-bubble.tsx → TaskMessageWidget.
| Module | Role |
|---|---|
features/tasks/services/task-service.ts | Status transitions + audit |
features/tasks/services/task-query-service.ts | Tree query (3/chat, max 21) + per-chat list |
features/tasks/services/task-escrow-service.ts | Credit / WFP / native hold, refund, release |
features/tasks/services/notify.ts | TASK_ASSIGNED / TASK_UPDATED notifications |
app/api/tasks/escrow/[id]/checkout/route.ts | PaymentConductor checkout for pending escrow |
features/tasks/components/task-message-widget.tsx | In-chat actions |
features/tasks/components/task-compose-dialog.tsx | Create UI from composer |
features/tasks/components/tasks-tree.tsx | /tasks filter tabs |
app/_actions/tasks.ts | Server actions |
Notifications: NotificationType.TASK_ASSIGNED, TASK_UPDATED.
/tasks query contract| Endpoint | Behavior |
|---|---|
GET /api/tasks?filter= | all | available | in_progress | completed — up to 3 newest tasks per conversation, global cap 21 |
GET /api/tasks/conversation/[id] | All tasks in one chat |
| Filter mapping | available → available+requested; in_progress → in_progress; completed → completed+accepted |
Routes: ROUTES.TASKS, ROUTES.TASK(chatId) in constants/routes.ts.
PaymentPurpose includes task_escrow (lib/payments/conductor/types.ts). Order references: task_{escrowId}_{timestamp}.
| Event | Behavior |
|---|---|
| Fund on create (credit) | creditBalanceService.spendCredits → escrow doc held + message metadata |
| Fund on create (fiat/native) | Pending escrow doc → needsCheckout → POST /api/tasks/escrow/[id]/checkout |
| WFP/Stripe webhook / inline native | markHeldFromPayment → held + notify reporter |
| Cancel before release | Credit: addFiatUsd desk_refund + stable reference_id; WFP: refundStorePayment; native: treasury→reporter or credit equivalent fallback (same as release) |
| Accept after completed | Credit/fiat: addFiatUsd + reference_id; native: treasury→assignee or credit equivalent fallback |
| Concurrent claim | True CAS: db().transaction + FOR UPDATE — only one of accept/cancel can claim held |
| Admin dispute | /admin/crm/task-escrows — release / refund / cancel via TaskEscrowService.adminResolve |
Collection: task_escrows (JSONB doc via DatabaseService). Stable ledger refs: task_escrow_release_${id}, task_escrow_refund_${id} (stored on claim before money move).
SOLANA_TREASURY_PRIVATE_KEY, SOLANA_FEE_PAYER_PRIVATE_KEY, RPC).held escrow.features/wallet/ops/TREASURY-SWAP-OPS.md § Task escrow.convertTaskToOpportunity (reporter only, not canceled) calls createOpportunity with type: 'request', isPrivate: true, provenance in tags (sourceMessageId:…, sourceConversationId:…), stores opportunityId on task metadata.
Create a task from the chat composer (ListTodo) — optional assignee, deadline, credit budget + escrow.
Counterparty Start / Request → Done → reporter Accept (or Dispute when escrow held).
Browse /tasks or /tasks/[chatId]; open chat via /messages?c=.
Optionally Convert to opportunity → /opportunities request listing.
// app/_actions/tasks.ts (names)
createTaskMessage
startTask | requestTask | approveTaskRequest | rejectTaskRequest
completeTask | acceptTask | disputeTask | cancelTask
editTaskContent | deleteTask
convertTaskToOpportunity