Skip to content

Tasks — Developer Guide

Mirror of the Leads developer guide. Prefer copying Leads patterns over inventing new ones.

Backend layout

PiecePath
Modelsapp/Models/Task.php, TaskTag, TaskNote, TaskNoteMention, TaskActivity
Enumsapp/Enums/Tenant/TaskStatusEnum (includes waiting; Open label To Do), TaskPriorityEnum, TaskActivityTypeEnum
Serviceapp/Services/Tenant/TaskService.php (+ ScopesToAssignee), TaskTagService.php
Controllerapp/Http/Controllers/Tenant/Api/V1/TaskController.php, TaskTagController.php
Requestsapp/Http/Requests/Tenant/Api/V1/Task/*
Resourcesapp/Http/Resources/Tenant/Api/V1/Task/*
Policyapp/Policies/TaskPolicy.php (changeDueDatetasks.change_due_date), TaskTagPolicy.php
Eventsapp/Events/Task*.php (includes TaskTagCreated, TaskTagsSynced)
Subscriberapp/Listeners/TaskEventSubscriber.php (audit + notifications)
Notificationsapp/Notifications/Tenant/Task/* — assign/complete/reopen: database + optional mail (+ webpush on assign); mentions: database + webpush + optional mail; due/overdue: database; daily digest: mail only (TaskDueDigestNotification)
MentionsApp\Support\NoteMentions, NoteMentionService; wired from TaskNoteAdded in TaskEventSubscriber
Digest deliverytask_digest_deliveries + TaskDigestDeliveryService; TrackTaskDueDigestDelivery on NotificationSent / NotificationFailed
Scheduled duecrm:send-due-notifications every 5 minutes (onOneServer); tenant setting task_reminder_time (Daily Reminder Time) gated in workspace timezone — see Workspace timezone convention
Teststests/Feature/Tenant/Task/TaskTest.php, TaskTagTest.php, tests/Feature/Tenant/Notification/TaskDueDigestNotificationTest.php, NoteMentionNotificationTest.php, tests/Unit/NoteMentionsTest.php

Domain notes

  • Comment bodies may include @[Display Name](user:ID) mention tokens (composer UI shows @Name chips). On TaskNoteAdded, NoteMentionService persists task_note_mentions and sends task.mentioned (skip self; idempotent via dedupe_key). Mail is optional via email_notifications.task_mentioned (default off).
  • Assignee scoping via ScopesToAssignee with tasks.assign.
  • Task assignee pickers use filterTaskAssigneeOptions (omit suspended only). They do not reuse filterLeadAssigneeOptionsexclude_from_lead_auto_assign and workspace owners remain assignable on Tasks. Backend create/update/assign use EligibleTaskAssignee (User::isEligibleAssignee — rejects suspended users; allows keeping the current assignee when suspended so they can be cleared).
  • Updating due_at after create requires tasks.change_due_date (enforced in TaskService / policy). Initial due_at on create is allowed without that permission.
  • due_at is a UTC instant (UtcDateTime / UtcIso). Overdue / due-today / due-this-week SQL uses App\Support\UtcInstant so non-UTC workspace timezones do not mark upcoming tasks overdue. SPA create/edit uses appLocalInputToIso / isoToAppLocalInput (Settings → General timezone), not raw datetime-local / ISO slice.
  • Board columns are one per TaskStatusEnum case.
  • Optional soft project_id (nullable FK → projects, nullOnDelete) validated by LinkableProject — Projects module must be entitled and the project must be visible to the actor. List/show embed project (id, uuid, title, status) when loaded. Catalog version 1.4.0 (attachments + upload-policy enforcement). See Projects developer guide.
  • Attachments: task_attachments and task_note_attachments on the workspace uploads disk (tenants/{uuid}/tasks/). Types/sizes from workspace storage.upload_policy via WorkspaceUploadPolicy. Multi-file batches assert total bytes against remaining Storage quota before any object is written. Auth’d download/delete; bytes count toward Storage used. Production checklist: upload policy + task media readiness.

Permissions

config/tenant-permissions.php:

tasks.view | create | update | delete | assign | complete | change_due_date

Routes use module:tasks then can:tasks.* / policies.

API (tenant)

Base: /api/tenant/v1 — full reference tenant-v1-tasks.md.

MethodPathPermission
GET/tasksview
GET/tasks/statsview
GET/tasks/boardview
POST/taskscreate
GET/tasks/{task}view
PUT/tasks/{task}update (+ change_due_date when changing due_at)
DELETE/tasks/{task}delete
POST/tasks/{task}/assignassign
POST/tasks/{task}/completecomplete
POST/tasks/{task}/reopencomplete
POST/tasks/{task}/notesupdate
GET/tasks/{task}/timelineview
GET/task-tagsview
POST/task-tagscreate
PUT/tasks/{task}/tagsupdate

Auth login/me include modules: string[] for SPA gating.

Colored tags are create-only for MVP (no tag update/delete/reorder routes). Assign on store/update via tag_ids[] or PUT …/tags; filter list/board with tag_id.

Frontend

PiecePath
Pagesrc/pages/tasks/tasks-page.tsx (board default + list; list row menu Complete/Reopen via tasks.complete)
Formtask-form-dialog.tsx
Detailtask-detail-sheet.tsx (Comments + History; Comments use MentionComposer; board DnD auto-saves status on the list page)
Shared boardsrc/components/crm/kanban-board.tsx (per-column vertical scroll + contained horizontal scroll; titles stay fixed; touch pan on column lists)
Mentions UIsrc/components/crm/mention-composer.tsx (shows @Name chips; emits @[Name](user:id); keep typing after pick; Backspace/Delete removes chips), src/lib/note-mentions.ts (formatNoteMentionsForDisplay in record pages + latest-note-follow-up.tsx list/board previews)
Notification registrysrc/notifications/modules/tasks.ts (task.mentioned)
ServicetaskService in src/api/services.ts
Navpermission: tasks.view, module: 'tasks'

Tests

bash
# Backend
php artisan test --compact tests/Feature/Tenant/Task/TaskTest.php
php artisan test --compact tests/Feature/Tenant/Task/TaskTagTest.php
php artisan test --compact tests/Unit/UtcInstantTest.php

# Frontend E2E
npm run test:e2e:tasks

Logging

  • Spatie LogsActivity on Task (log name tasks)
  • Domain task_activities timeline
  • PlatformAuditService via TaskEventSubscriber (includes task_tag_created, task_tags_synced)

Intentional differences from Leads

LeadsTasks
Stages + independent statusStatus + priority enums (no stages)
Follow-upsNone
Assignment history tableTimeline only
export / convertcomplete / change_due_date
Board by stageBoard by status

AI tools

Ask EloSync Task tools (get_task, confirmed status/assign/note writes, plus existing list reads and create_task) are registered in AIToolRegistry and confirmed via PendingAiActionService. See AI tools and AI Task triage production readiness.

Official documentation for the EloSync SaaS Platform.