Documentation

    Concepts, value, and typical clone scenarios — less code.

    Welcome to Ring
    Quick Reference
    Getting Started
    Prerequisites
    Installation
    First Success Validation
    Next Steps
    Features
    Multi-Vendor Store
    SubscriptionConductor
    PaymentConductor
    Payments Overview
    WayForPay Payment Integration
    Wallet & Credit System
    WalletConductor
    Affiliate & Referral Enablement
    Referral Codes (Refcodes)
    NFT Exhibition Marketplace
    Solana NFT Gates
    Token Staking System
    Owner Project Lab
    Entities
    Opportunities
    Real-Time Messaging
    Ring Tasks
    WebRTC Calls & STUNner TURN
    News Module
    Member Blogs
    Public Profile Pages
    Username Reservation System
    Scientific Editor
    Notifications
    Push Notifications with FCM (Ring-Powered)
    Email AI-CRM
    Ring Mailer & RingdomX Mail
    Tunnel Protocol
    VideoConductor
    MediaConductor
    Generative Gallery
    Authentication
    Security & Compliance
    Admin console
    Admin Wiki
    Manage via Telegram
    Locale System
    Mobile Experience
    Performance Optimization Patterns
    Examples
    Quick Start
    Basic Setup
    White Label
    Custom Branding
    Web3 Integration
    Real World
    Advanced Features
    Customization
    Quick Start — Your First Ring Clone
    Customization Guide
    Branding
    Themes
    Features
    Localization
    Token Economics Setup
    Payment Gateway Integration
    Reference Ring deployments
    Web3
    Token launch jurisdictions
    Wallet
    Wallet Security Tips
    Integrations
    Ethereum wallets (Wagmi v3)
    RingFileBase (object storage API)
    Ring CDN (RingFileBase edge)
    Deployment
    Self-hosted deployment
    Vercel
    Docker
    Environment Configuration
    Monitoring & Analytics
    Performance Optimization
    Backup & Recovery
    Architecture
    Data Model
    Security
    Real Time
    Discovery Mutation Sync
    PaymentConductor architecture
    WalletConductor architecture
    Development
    Ring MCP Server

    Quick entry (CTOs · auditors · agents)

    Welcome — mission & audiences
    Quick Reference
    Getting started
    Architecture & Auth.js
    Backend modes & databases (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP Tools
    Ring MCP Server
    Token economics
    Token launch jurisdictions
    Deploy (Docker · k8s)
    Security & compliance reads
    ringdom.org — LegioX homebase
    Source — MIT license (GitHub)

    Documentation

    Concepts, value, and typical clone scenarios — less code.

    Welcome to Ring
    Quick Reference
    Getting Started
    Prerequisites
    Installation
    First Success Validation
    Next Steps
    Features
    Multi-Vendor Store
    SubscriptionConductor
    PaymentConductor
    Payments Overview
    WayForPay Payment Integration
    Wallet & Credit System
    WalletConductor
    Affiliate & Referral Enablement
    Referral Codes (Refcodes)
    NFT Exhibition Marketplace
    Solana NFT Gates
    Token Staking System
    Owner Project Lab
    Entities
    Opportunities
    Real-Time Messaging
    Ring Tasks
    WebRTC Calls & STUNner TURN
    News Module
    Member Blogs
    Public Profile Pages
    Username Reservation System
    Scientific Editor
    Notifications
    Push Notifications with FCM (Ring-Powered)
    Email AI-CRM
    Ring Mailer & RingdomX Mail
    Tunnel Protocol
    VideoConductor
    MediaConductor
    Generative Gallery
    Authentication
    Security & Compliance
    Admin console
    Admin Wiki
    Manage via Telegram
    Locale System
    Mobile Experience
    Performance Optimization Patterns
    Examples
    Quick Start
    Basic Setup
    White Label
    Custom Branding
    Web3 Integration
    Real World
    Advanced Features
    Customization
    Quick Start — Your First Ring Clone
    Customization Guide
    Branding
    Themes
    Features
    Localization
    Token Economics Setup
    Payment Gateway Integration
    Reference Ring deployments
    Web3
    Token launch jurisdictions
    Wallet
    Wallet Security Tips
    Integrations
    Ethereum wallets (Wagmi v3)
    RingFileBase (object storage API)
    Ring CDN (RingFileBase edge)
    Deployment
    Self-hosted deployment
    Vercel
    Docker
    Environment Configuration
    Monitoring & Analytics
    Performance Optimization
    Backup & Recovery
    Architecture
    Data Model
    Security
    Real Time
    Discovery Mutation Sync
    PaymentConductor architecture
    WalletConductor architecture
    Development
    Ring MCP Server

    Quick entry (CTOs · auditors · agents)

    Welcome — mission & audiences
    Quick Reference
    Getting started
    Architecture & Auth.js
    Backend modes & databases (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP Tools
    Ring MCP Server
    Token economics
    Token launch jurisdictions
    Deploy (Docker · k8s)
    Security & compliance reads
    ringdom.org — LegioX homebase
    Source — MIT license (GitHub)

    Documentation

    Concepts, value, and typical clone scenarios — less code.

    Welcome to Ring
    Quick Reference
    Getting Started
    Prerequisites
    Installation
    First Success Validation
    Next Steps
    Features
    Multi-Vendor Store
    SubscriptionConductor
    PaymentConductor
    Payments Overview
    WayForPay Payment Integration
    Wallet & Credit System
    WalletConductor
    Affiliate & Referral Enablement
    Referral Codes (Refcodes)
    NFT Exhibition Marketplace
    Solana NFT Gates
    Token Staking System
    Owner Project Lab
    Entities
    Opportunities
    Real-Time Messaging
    Ring Tasks
    WebRTC Calls & STUNner TURN
    News Module
    Member Blogs
    Public Profile Pages
    Username Reservation System
    Scientific Editor
    Notifications
    Push Notifications with FCM (Ring-Powered)
    Email AI-CRM
    Ring Mailer & RingdomX Mail
    Tunnel Protocol
    VideoConductor
    MediaConductor
    Generative Gallery
    Authentication
    Security & Compliance
    Admin console
    Admin Wiki
    Manage via Telegram
    Locale System
    Mobile Experience
    Performance Optimization Patterns
    Examples
    Quick Start
    Basic Setup
    White Label
    Custom Branding
    Web3 Integration
    Real World
    Advanced Features
    Customization
    Quick Start — Your First Ring Clone
    Customization Guide
    Branding
    Themes
    Features
    Localization
    Token Economics Setup
    Payment Gateway Integration
    Reference Ring deployments
    Web3
    Token launch jurisdictions
    Wallet
    Wallet Security Tips
    Integrations
    Ethereum wallets (Wagmi v3)
    RingFileBase (object storage API)
    Ring CDN (RingFileBase edge)
    Deployment
    Self-hosted deployment
    Vercel
    Docker
    Environment Configuration
    Monitoring & Analytics
    Performance Optimization
    Backup & Recovery
    Architecture
    Data Model
    Security
    Real Time
    Discovery Mutation Sync
    PaymentConductor architecture
    WalletConductor architecture
    Development
    Ring MCP Server

    Quick entry (CTOs · auditors · agents)

    Welcome — mission & audiences
    Quick Reference
    Getting started
    Architecture & Auth.js
    Backend modes & databases (DB_BACKEND_MODE)
    Self-hosted
    Ring MCP Tools
    Ring MCP Server
    Token economics
    Token launch jurisdictions
    Deploy (Docker · k8s)
    Security & compliance reads
    ringdom.org — LegioX homebase
    Source — MIT license (GitHub)
    1. Docs
    2. /Features
    3. /Ring Tasks

    Updated Jul 19, 20265 min listen

    Ring Platform Logo

    Завантаження документації...

    Підготовка контенту платформи Ring

    1. Docs
    2. /Features
    3. /Ring Tasks

    Updated Jul 19, 20265 min listen

    Ring Platform Logo

    Завантаження документації...

    Підготовка контенту платформи Ring

    1. Docs
    2. /Features
    3. /Ring Tasks

    Updated Jul 19, 20265 min listen

    Ring Platform Logo

    Завантаження документації...

    Підготовка контенту платформи Ring

    Ring Tasks

    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.

    LayerWhere
    Typesfeatures/chat/types/index.ts — Message.type: 'task', TaskMetadata
    Feature modulefeatures/tasks/**
    Server actionsapp/_actions/tasks.ts
    List APIsGET /api/tasks, GET /api/tasks/conversation/[id]
    Pages/tasks, /tasks/[chatId]
    Chat deep link/messages?c=<conversationId> (no /messages/[id] segment)

    Status machine (shared)

    StatusMeaning
    availablePosted without assignee
    requestedSomeone asked to be assignee
    in_progressAssignee set
    completedDone by reporter or assignee
    acceptedReporter accepted work (releases escrow if held)
    canceledReporter canceled (refunds held escrow to credit balance)
    disputedReporter disputed after completed + held escrow

    Why tasks matter for your clone

    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.

    Messaging

    Tasks appear as widgets inside the same conversation roster.

    Opportunities

    Convert a task into a public/private request when you need marketplace reach.

    Wallet credits

    Escrow v1 holds and releases credit balance (points).

    Typical scenarios

    1. Direct chat — You assign the counterparty a deliverable with a deadline; they mark Done; you Accept.

    Message type + metadata

    Extend the chat union (also allowlisted in app/api/conversations/[id]/messages/route.ts):

    text | image | file | system | payment_request | env_request | task

    TaskMetadata (kind: 'task') holds reporter, assignee, status, deadline, budget, escrow stub, lifecycle timestamps, opportunityId, and audit[].

    Content ruleDetail
    message.contentFull description
    Widget titleFirst two non-empty lines
    FallbackTask: {firstLine}
    EditOnly when status === 'available' and escrow not held/released (task action, not the 15-minute text edit window)
    VersioningOverwrite + editedAt + — no content

    Backlog

    Related documentation

    Real-Time Messaging

    Prerequisite: tasks are chat message widgets inside the same conversation roster.

    Opportunities

    Next-step: convert a task into a marketplace request opportunity.

    Wallet & Credit System

    Depends-on: task escrow v1 holds and releases credit balance points.

    PaymentConductor

    Deep-dive: PaymentPurpose task_escrow reuses Conductor rails.

    Ring Tasks

    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.

    LayerWhere
    Typesfeatures/chat/types/index.ts — Message.type: 'task', TaskMetadata
    Feature modulefeatures/tasks/**
    Server actionsapp/_actions/tasks.ts
    List APIsGET /api/tasks, GET /api/tasks/conversation/[id]
    Pages/tasks, /tasks/[chatId]
    Chat deep link/messages?c=<conversationId> (no /messages/[id] segment)

    Status machine (shared)

    StatusMeaning
    availablePosted without assignee
    requestedSomeone asked to be assignee
    in_progressAssignee set
    completedDone by reporter or assignee
    acceptedReporter accepted work (releases escrow if held)
    canceledReporter canceled (refunds held escrow to credit balance)
    disputedReporter disputed after completed + held escrow

    Why tasks matter for your clone

    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.

    Messaging

    Tasks appear as widgets inside the same conversation roster.

    Opportunities

    Convert a task into a public/private request when you need marketplace reach.

    Wallet credits

    Escrow v1 holds and releases credit balance (points).

    Typical scenarios

    1. Direct chat — You assign the counterparty a deliverable with a deadline; they mark Done; you Accept.

    Message type + metadata

    Extend the chat union (also allowlisted in app/api/conversations/[id]/messages/route.ts):

    text | image | file | system | payment_request | env_request | task

    TaskMetadata (kind: 'task') holds reporter, assignee, status, deadline, budget, escrow stub, lifecycle timestamps, opportunityId, and audit[].

    Content ruleDetail
    message.contentFull description
    Widget titleFirst two non-empty lines
    FallbackTask: {firstLine}
    EditOnly when status === 'available' and escrow not held/released (task action, not the 15-minute text edit window)
    VersioningOverwrite + editedAt + — no content

    Backlog

    Related documentation

    Real-Time Messaging

    Prerequisite: tasks are chat message widgets inside the same conversation roster.

    Opportunities

    Next-step: convert a task into a marketplace request opportunity.

    Wallet & Credit System

    Depends-on: task escrow v1 holds and releases credit balance points.

    PaymentConductor

    Deep-dive: PaymentPurpose task_escrow reuses Conductor rails.

    Ring Tasks

    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.

    LayerWhere
    Typesfeatures/chat/types/index.ts — Message.type: 'task', TaskMetadata
    Feature modulefeatures/tasks/**
    Server actionsapp/_actions/tasks.ts
    List APIsGET /api/tasks, GET /api/tasks/conversation/[id]
    Pages/tasks, /tasks/[chatId]
    Chat deep link/messages?c=<conversationId> (no /messages/[id] segment)

    Status machine (shared)

    StatusMeaning
    availablePosted without assignee
    requestedSomeone asked to be assignee
    in_progressAssignee set
    completedDone by reporter or assignee
    acceptedReporter accepted work (releases escrow if held)
    canceledReporter canceled (refunds held escrow to credit balance)
    disputedReporter disputed after completed + held escrow

    Why tasks matter for your clone

    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.

    Messaging

    Tasks appear as widgets inside the same conversation roster.

    Opportunities

    Convert a task into a public/private request when you need marketplace reach.

    Wallet credits

    Escrow v1 holds and releases credit balance (points).

    Typical scenarios

    1. Direct chat — You assign the counterparty a deliverable with a deadline; they mark Done; you Accept.

    Message type + metadata

    Extend the chat union (also allowlisted in app/api/conversations/[id]/messages/route.ts):

    text | image | file | system | payment_request | env_request | task

    TaskMetadata (kind: 'task') holds reporter, assignee, status, deadline, budget, escrow stub, lifecycle timestamps, opportunityId, and audit[].

    Content ruleDetail
    message.contentFull description
    Widget titleFirst two non-empty lines
    FallbackTask: {firstLine}
    EditOnly when status === 'available' and escrow not held/released (task action, not the 15-minute text edit window)
    VersioningOverwrite + editedAt + — no content

    Backlog

    Related documentation

    Real-Time Messaging

    Prerequisite: tasks are chat message widgets inside the same conversation roster.

    Opportunities

    Next-step: convert a task into a marketplace request opportunity.

    Wallet & Credit System

    Depends-on: task escrow v1 holds and releases credit balance points.

    PaymentConductor

    Deep-dive: PaymentPurpose task_escrow reuses Conductor rails.

  1. Group chat — Post an unassigned task; any participant hits Start (or Request for approval).
  2. Paid favor — Attach a credit budget + escrow; funds hold until Accept; Cancel before accept refunds your credits.
  3. Outgrow the chat — Convert the task to a request opportunity so more people can apply.
  4. Operator checklist

    • Members find Tasks next to Messages in the sidebar (/tasks).
    • Escrow supports credit balance, fiat (WayForPay/Stripe), and native token via PaymentConductor (PaymentPurpose.task_escrow).
    • Admin dispute resolution: /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 map

    ModuleRole
    features/tasks/services/task-service.tsStatus transitions + audit
    features/tasks/services/task-query-service.tsTree query (3/chat, max 21) + per-chat list
    features/tasks/services/task-escrow-service.tsCredit / WFP / native hold, refund, release
    features/tasks/services/notify.tsTASK_ASSIGNED / TASK_UPDATED notifications
    app/api/tasks/escrow/[id]/checkout/route.tsPaymentConductor checkout for pending escrow
    features/tasks/components/task-message-widget.tsxIn-chat actions
    features/tasks/components/task-compose-dialog.tsxCreate UI from composer
    features/tasks/components/tasks-tree.tsx/tasks filter tabs
    app/_actions/tasks.tsServer actions

    Create + lifecycle actions

    Notifications: NotificationType.TASK_ASSIGNED, TASK_UPDATED.

    /tasks query contract

    EndpointBehavior
    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 mappingavailable → available+requested; in_progress → in_progress; completed → completed+accepted

    Routes: ROUTES.TASKS, ROUTES.TASK(chatId) in constants/routes.ts.

    Escrow (credit_balance · fiat · native_token)

    PaymentPurpose includes task_escrow (lib/payments/conductor/types.ts). Order references: task_{escrowId}_{timestamp}.

    EventBehavior
    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 nativemarkHeldFromPayment → held + notify reporter
    Cancel before releaseCredit: addFiatUsd desk_refund + stable reference_id; WFP: refundStorePayment; native: treasury→reporter or credit equivalent fallback (same as release)
    Accept after completedCredit/fiat: addFiatUsd + reference_id; native: treasury→assignee or credit equivalent fallback
    Concurrent claimTrue 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).

    Native escrow ops checklist

    1. Desk buy health first (SOLANA_TREASURY_PRIVATE_KEY, SOLANA_FEE_PAYER_PRIVATE_KEY, RPC).
    2. Assignee/reporter must have a custodial native wallet for on-chain out; otherwise credit fallback runs.
    3. Mainnet hot-key blocks force credit fallback — expected, not a stuck held escrow.
    4. See features/wallet/ops/TREASURY-SWAP-OPS.md § Task escrow.

    Convert → request opportunity

    convertTaskToOpportunity (reporter only, not canceled) calls createOpportunity with type: 'request', isPrivate: true, provenance in tags (sourceMessageId:…, sourceConversationId:…), stores opportunityId on task metadata.

    Integration steps

    1. 1

      Create a task from the chat composer (ListTodo) — optional assignee, deadline, credit budget + escrow.

    2. 2

      Counterparty Start / Request → Done → reporter Accept (or Dispute when escrow held).

    3. 3

      Browse /tasks or /tasks/[chatId]; open chat via /messages?c=.

    4. 4

      Optionally Convert to opportunity → /opportunities request listing.

    ts
    
    // app/_actions/tasks.ts (names)
    createTaskMessage
    startTask | requestTask | approveTaskRequest | rejectTaskRequest
    completeTask | acceptTask | disputeTask | cancelTask
    editTaskContent | deleteTask
    convertTaskToOpportunity
  5. Group chat — Post an unassigned task; any participant hits Start (or Request for approval).
  6. Paid favor — Attach a credit budget + escrow; funds hold until Accept; Cancel before accept refunds your credits.
  7. Outgrow the chat — Convert the task to a request opportunity so more people can apply.
  8. Operator checklist

    • Members find Tasks next to Messages in the sidebar (/tasks).
    • Escrow supports credit balance, fiat (WayForPay/Stripe), and native token via PaymentConductor (PaymentPurpose.task_escrow).
    • Admin dispute resolution: /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 map

    ModuleRole
    features/tasks/services/task-service.tsStatus transitions + audit
    features/tasks/services/task-query-service.tsTree query (3/chat, max 21) + per-chat list
    features/tasks/services/task-escrow-service.tsCredit / WFP / native hold, refund, release
    features/tasks/services/notify.tsTASK_ASSIGNED / TASK_UPDATED notifications
    app/api/tasks/escrow/[id]/checkout/route.tsPaymentConductor checkout for pending escrow
    features/tasks/components/task-message-widget.tsxIn-chat actions
    features/tasks/components/task-compose-dialog.tsxCreate UI from composer
    features/tasks/components/tasks-tree.tsx/tasks filter tabs
    app/_actions/tasks.tsServer actions

    Create + lifecycle actions

    Notifications: NotificationType.TASK_ASSIGNED, TASK_UPDATED.

    /tasks query contract

    EndpointBehavior
    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 mappingavailable → available+requested; in_progress → in_progress; completed → completed+accepted

    Routes: ROUTES.TASKS, ROUTES.TASK(chatId) in constants/routes.ts.

    Escrow (credit_balance · fiat · native_token)

    PaymentPurpose includes task_escrow (lib/payments/conductor/types.ts). Order references: task_{escrowId}_{timestamp}.

    EventBehavior
    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 nativemarkHeldFromPayment → held + notify reporter
    Cancel before releaseCredit: addFiatUsd desk_refund + stable reference_id; WFP: refundStorePayment; native: treasury→reporter or credit equivalent fallback (same as release)
    Accept after completedCredit/fiat: addFiatUsd + reference_id; native: treasury→assignee or credit equivalent fallback
    Concurrent claimTrue 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).

    Native escrow ops checklist

    1. Desk buy health first (SOLANA_TREASURY_PRIVATE_KEY, SOLANA_FEE_PAYER_PRIVATE_KEY, RPC).
    2. Assignee/reporter must have a custodial native wallet for on-chain out; otherwise credit fallback runs.
    3. Mainnet hot-key blocks force credit fallback — expected, not a stuck held escrow.
    4. See features/wallet/ops/TREASURY-SWAP-OPS.md § Task escrow.

    Convert → request opportunity

    convertTaskToOpportunity (reporter only, not canceled) calls createOpportunity with type: 'request', isPrivate: true, provenance in tags (sourceMessageId:…, sourceConversationId:…), stores opportunityId on task metadata.

    Integration steps

    1. 1

      Create a task from the chat composer (ListTodo) — optional assignee, deadline, credit budget + escrow.

    2. 2

      Counterparty Start / Request → Done → reporter Accept (or Dispute when escrow held).

    3. 3

      Browse /tasks or /tasks/[chatId]; open chat via /messages?c=.

    4. 4

      Optionally Convert to opportunity → /opportunities request listing.

    ts
    
    // app/_actions/tasks.ts (names)
    createTaskMessage
    startTask | requestTask | approveTaskRequest | rejectTaskRequest
    completeTask | acceptTask | disputeTask | cancelTask
    editTaskContent | deleteTask
    convertTaskToOpportunity
  9. Group chat — Post an unassigned task; any participant hits Start (or Request for approval).
  10. Paid favor — Attach a credit budget + escrow; funds hold until Accept; Cancel before accept refunds your credits.
  11. Outgrow the chat — Convert the task to a request opportunity so more people can apply.
  12. Operator checklist

    • Members find Tasks next to Messages in the sidebar (/tasks).
    • Escrow supports credit balance, fiat (WayForPay/Stripe), and native token via PaymentConductor (PaymentPurpose.task_escrow).
    • Admin dispute resolution: /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 map

    ModuleRole
    features/tasks/services/task-service.tsStatus transitions + audit
    features/tasks/services/task-query-service.tsTree query (3/chat, max 21) + per-chat list
    features/tasks/services/task-escrow-service.tsCredit / WFP / native hold, refund, release
    features/tasks/services/notify.tsTASK_ASSIGNED / TASK_UPDATED notifications
    app/api/tasks/escrow/[id]/checkout/route.tsPaymentConductor checkout for pending escrow
    features/tasks/components/task-message-widget.tsxIn-chat actions
    features/tasks/components/task-compose-dialog.tsxCreate UI from composer
    features/tasks/components/tasks-tree.tsx/tasks filter tabs
    app/_actions/tasks.tsServer actions

    Create + lifecycle actions

    Notifications: NotificationType.TASK_ASSIGNED, TASK_UPDATED.

    /tasks query contract

    EndpointBehavior
    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 mappingavailable → available+requested; in_progress → in_progress; completed → completed+accepted

    Routes: ROUTES.TASKS, ROUTES.TASK(chatId) in constants/routes.ts.

    Escrow (credit_balance · fiat · native_token)

    PaymentPurpose includes task_escrow (lib/payments/conductor/types.ts). Order references: task_{escrowId}_{timestamp}.

    EventBehavior
    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 nativemarkHeldFromPayment → held + notify reporter
    Cancel before releaseCredit: addFiatUsd desk_refund + stable reference_id; WFP: refundStorePayment; native: treasury→reporter or credit equivalent fallback (same as release)
    Accept after completedCredit/fiat: addFiatUsd + reference_id; native: treasury→assignee or credit equivalent fallback
    Concurrent claimTrue 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).

    Native escrow ops checklist

    1. Desk buy health first (SOLANA_TREASURY_PRIVATE_KEY, SOLANA_FEE_PAYER_PRIVATE_KEY, RPC).
    2. Assignee/reporter must have a custodial native wallet for on-chain out; otherwise credit fallback runs.
    3. Mainnet hot-key blocks force credit fallback — expected, not a stuck held escrow.
    4. See features/wallet/ops/TREASURY-SWAP-OPS.md § Task escrow.

    Convert → request opportunity

    convertTaskToOpportunity (reporter only, not canceled) calls createOpportunity with type: 'request', isPrivate: true, provenance in tags (sourceMessageId:…, sourceConversationId:…), stores opportunityId on task metadata.

    Integration steps

    1. 1

      Create a task from the chat composer (ListTodo) — optional assignee, deadline, credit budget + escrow.

    2. 2

      Counterparty Start / Request → Done → reporter Accept (or Dispute when escrow held).

    3. 3

      Browse /tasks or /tasks/[chatId]; open chat via /messages?c=.

    4. 4

      Optionally Convert to opportunity → /opportunities request listing.

    ts
    
    // app/_actions/tasks.ts (names)
    createTaskMessage
    startTask | requestTask | approveTaskRequest | rejectTaskRequest
    completeTask | acceptTask | disputeTask | cancelTask
    editTaskContent | deleteTask
    convertTaskToOpportunity