Trường Số · Product Requirements · 09/2026

PRD 16 · Internal tasks, reminders and leave requests

One task entity shared by all staff, linkable to a customer, student, class, session, invoice or incident; recurring tasks for operational routines; system-generated tasks with dedupe rules; a notification centre and an 08:00 digest; staff and teacher leave requests approved per branch; incident reports from the teacher app. Today the backend only has customer follow-up tasks and the personal notification endpoints.

Key facts, origin and limits
Status
Draft v1
Owning module
Operations (Vận hành)
Backend
EXISTING today-plan, notifications, class-schedules remind · EXTEND customers interactions · NEW task, task_comment, leave_request, incident
Phase
P1 (task assignment, reminders, in-app notifications) / P2 (leave requests with approval, incident reports)
Depends on
01 Admissions CRM, 04 Attendance, 06 Staff, 17 Mobile app

Drafted by an AI assistant in a single session on 16/09/2026, extending the PRD set under the original request quoted verbatim on the hub page. A proposal for team discussion, not a decision of the product team.

Sources

  • Public competitor research (PSE ONE, pse4.one), the center-crm-frontend codebase and the staging /v3 OpenAPI specification (182 paths), as of 10/09/2026.
  • The existing / extend / new tags on this page come from a comparison with the staging /v3 specification at that date.
  • A second scan of PSE ONE's public sources on 16/09/2026 (features page, pricing, user-guide articles).
  • Competitor reference (pse4.one, public scan of 16/09/2026): the pricing page lists task assignment, notifications, leave requests and automatic class reminders in every tier; marketing stresses "smart notifications and reminders" in the mobile app; the teacher app has incident reporting. Their presence in the lowest tier shows customers treat them as baseline.

Limits

  • Verification pending in-app survey, because automated login to the reference product was not authorised in the drafting session:
    • Whether the competitor's tasks link to a student, class or invoice or are a free-standing to-do list; whether checklists and comments exist.
    • Whether the competitor has recurring and system-generated tasks, and how duplicates are handled when the same condition repeats.
    • Whether the competitor's leave requests are for staff, students or both; the leave types; who approves; whether an approved request automatically flags sessions for a substitute.
    • Which types the competitor's "smart notifications and reminders" cover, whether a daily digest and quiet hours exist; whether incident reporting has photos, severity and routing.

Proposed design

All branch operations run through one Tasks area with five tabs (My work · Team work · Routines · Leave requests · Incidents); the most important thing to see is that every task row states its source (manual, routine, system) and its linked entity, while leave requests and incidents are simply two more ways of generating tasks into the same list.

1 · My work

/tasks/my · desktop

My work
The five groups in the order of section 4: Quá hạn, Hôm nay, Chờ xác nhận của tôi, Tuần này, Sau đó; each row has the done checkbox, title, linked entity (chip with a student, class or invoice icon, or "Không gắn"), due, priority, source and unread comment count; filters for branch, source and entity. The hovered row shows the three row actions (Hoàn thành, Hoãn đến ngày mai, Mở chi tiết); in the pending-review group they become Xác nhận and Trả lại (TSK-02). The two overdue rows are red only in the due column because overdue is a condition, not a status (rule 5); the unfinished "Chốt quỹ 15/09" coexists with the 16/09 occurrence (TSK-03); the empty Sau đó group shows the exact empty-state copy from the PRD.

2 · My work in the teacher app

/teach/tasks · mobile

My work in the teacher app
The teacher tab bar gains a Việc item as section 4 requires. Same five groups, each row reduced to title, due, linked entity, source, priority and unread comments; the overdue task from the session_unmarked trigger sits on top. Long-pressing a row opens a bottom sheet with exactly the three row actions (Hoàn thành, Hoãn đến ngày mai, Mở chi tiết).

3 · Team work

/tasks/team · desktop

Team work
Table with all nine columns of section 4 (title, assignees, assigner, linked entity, due, priority, status, source, last update), six filters and an overdue-only toggle. The per-staff summary (open, overdue, done in 7 days) is rendered as a strip of cards above the table instead of a side column, because the nine columns already fill the 1440 frame. Two selected rows raise the bulk bar with Giao lại, Đổi hạn, Đóng kèm lý do; the Chờ xác nhận and Hoàn thành rows and the rows assigned by Hệ thống or Mẫu lặp show all five statuses and three sources.

4 · Recurring routines

/tasks/routines · desktop

Recurring routines
Four stat tiles (running routines, tasks generated today in the centre timezone, previous periods still open, routines that skip holidays) and a table with every column: name, recurrence, generation time, due after, assignee (a named staff member or a role at the branch), branch scope, last generated, Đang chạy / Tạm dừng toggle. The three suggested routines for a new tenant (Chốt quỹ, Kiểm kho, Xác nhận lịch tuần tới) carry the "Mẫu gợi ý có sẵn" label; the overflow menu offers Sinh ngay một kỳ and Tạm dừng; the note restates that a period is never generated twice and edits only affect future occurrences (rules 6, 7).

5 · Task detail

/tasks/:id · drawer over Team work · desktop

Task detail
Header: inline-editable title, source chip with the trigger code, status selector, priority, due, assignees and the "needs review" flag. Left body: the linked entity opening the student record (with the parent), description, a 2/3 checklist recording who ticked each item and when, attachments 1/10, and reminders with the default 09:00 mark on the due date plus the + Nhắc button. The right column is the comment timeline: user comments with @mentions, dashed system comments including "Vắng thêm buổi ngày 15/09, tổng 4 buổi" with the priority raised one step instead of a new task (TSK-04, rule 8); the sticky action bar reads Huỷ việc · Giao lại · Hoàn thành, and because the review flag is on, the primary button states the move to Chờ xác nhận (TSK-02).

6 · Leave requests · Chờ tôi duyệt tab

/leave · desktop

Leave requests · Chờ tôi duyệt tab
The Đơn của tôi / Chờ tôi duyệt switch (the second only for approvers) and a table with every column: requester, type (Nghỉ phép, Nghỉ ốm, Nghỉ không lương, Đổi ca), from and to with the part of day, days, affected sessions, status, approver, submitted at. Phạm Hồng Nhung's request, unhandled for more than 48 hours, carries the extra "Quá 48 giờ · đã leo thang" label (rule 13); the rejected request shows its reason under the status; the sick-leave row shows the attached medical note.

7 · Approving a leave request

/leave/:id · drawer · desktop

Approving a leave request
Approval drawer for Lê Thu Trang's request: requester with leave days used, type, period, reason, and the four affected sessions each marked as main teacher or substitute. The warning box states the effect of approval: sessions flagged Cần dạy thay, "Phân công dạy thay" tasks for the academic office, exclusion from the timesheet (TSK-07, rule 14); the note field is mandatory on rejection; Từ chối and Duyệt đơn sit at the right, Đóng far left.

8 · Submit a leave request

/teach/leave/new · mobile

9 · Report an incident from a session

/teach/incidents/new · mobile

Submit a leave request
Report an incident from a session
Screen 8: the teacher form with large type chips, the date range, the full day / morning / afternoon / evening selector, reason and medical-note attachment; before submission an amber warning lists the four affected sessions exactly as in TSK-06, with a note that the default approver is the main branch manager, that the request can only be cancelled while pending and that an overlapping request is rejected (rules 12, 13). Screen 9: a single screen with branch, room and session pre-filled from context, type and severity as large chips, up to 5 client-compressed photos, title and description; the amber banner says the device is offline and the report will sync later; the footnote states that Nghiêm trọng and An toàn học viên push immediately, bypassing quiet hours (TSK-08, rule 16).

10 · Incidents

/incidents · desktop

Incidents
Four stat tiles (new, in progress, resolved awaiting confirmation, critical in 30 days) and the per-branch table with every column: title with code and photo count, type, severity, room, reporter, time, status, linked task. Each incident has exactly one handling task shown with its assignee and status; the critical "Học viên trượt ngã cầu thang" incident was pushed immediately to the owner; resolved incidents close automatically after 3 days without the reporter's confirmation (rule 15).

11 · Notification centre

/notifications · panel from the bell · desktop

Notification centre
Dropdown panel from the bell in the top bar with the filter chips Tất cả · Công việc · Đơn xin nghỉ · Sự cố · Hệ thống, plus the Đọc tất cả and Cài đặt thông báo links. The first item is the single 08:00 digest of the day listing the four groups with counts and the first three items of each (TSK-05, rule 10); the other items show the type icon, title, subtitle, relative time and unread dot; the hovered item shows the Lưu trữ button; two read items are dimmed; the footer recalls the 90-day auto-archive.

1Purpose

Most of the work of running a centre belongs to no single module: calling a parent back, finding a substitute teacher, closing the cash drawer, counting stock on Monday, fixing a broken projector. Today these live in Zalo groups, notebooks or spreadsheets, and nobody knows which are done. This module introduces one task entity that any staff member can be assigned, that every other module can generate, and that everyone sees in a single "My work" screen. The same reminder and notification machinery serves staff leave requests and incident reports from the classroom.

In scope

Out of scope

2What exists today

CapabilityEndpointKeep?
Today plan: tasks, calls and appointments linked to customers, dashboard widgetGET /v3/crm/me/today-planexisting keep; its data source widens to the new task entity
Customer follow-up tasks: an interaction type (Task) on the timeline with due date, assignee, statusGET /v3/crm/customers/{id}/interactionsextend migrate Task-type interactions into customer-linked tasks
Personal notification centre: list, unread count, read, read all, archiveGET /v3/crm/me/notifications, GET .../unread-count, POST .../{id}/read, POST .../read-all, POST .../{id}/archiveexisting keep; new notification types added, contract unchanged
Class reminder to parents and send-time previewPOST /v3/teacher/class-schedules/{id}/remind, POST /v3/teacher/class-schedules/preview-remind-timeexisting belongs to PRD 07; unchanged
Shared tasks, recurring tasks, system-generated tasks, leave requests, incident reportsnonenew

Proposed decision: separate tasks from customer interactions. Task-type interactions are migrated once into task with source = migrated and linked_type = customer, keeping assignee and due date; interactions keep only calls, meetings and notes; the customer timeline additionally reads from the task table.

3User stories and acceptance criteria

TSK-01Assign a task to a colleague
A branch manager assigns a dated task to an academic admin, linked to a student.
  • Given the student record or the Team work screen is open
  • When the manager chooses "+ Giao việc", enters title, assignees (one or many), due date, priority, description and an optional checklist
  • Then the task is created in status Mới, linked to the student; each assignee receives an in-app notification and a push within 1 minute; the task appears in the assignee's My work and in the Công việc tab of the student record.
TSK-02Work on and complete a task
The assignee updates progress and submits the result for the assigner to confirm.
  • Given a task with a three-item checklist and the "requires review" flag on
  • When the assignee ticks the checklist items, attaches a photo and chooses "Hoàn thành"
  • Then the status becomes Chờ xác nhận and the assigner is notified; the assigner chooses "Xác nhận" to move it to Hoàn thành, or "Trả lại" with a comment to return it to Đang làm; when the flag is off, "Hoàn thành" moves straight to Hoàn thành.
TSK-03Recurring task for an operational routine
The accountant's cash-close task appears every working day without being created by hand.
  • Given a routine "Chốt quỹ chi nhánh": daily except Sunday, generation time 16:00, due 18:00, assignee the accountant role at the branch
  • When the generation time arrives
  • Then a new task is created for each active branch and assigned to the staff holding the accountant role there; if the previous period's task is not done, the new one is still created and the old one shows as overdue; the routine can be paused, and editing it only affects future generations.
TSK-04System-generated task without duplicates
The student-care staff receives exactly one task for a student with repeated absences.
  • Given the student already has an open task "Liên hệ phụ huynh: vắng 3 buổi" triggered by PRD 04
  • When the student is absent a fourth time before that task is done
  • Then no new task is created; the existing task receives a system comment "Vắng thêm buổi ngày dd/MM, tổng 4 buổi", its priority rises one step and the assignee is reminded again; if the task was completed within the last 7 days, no new task is created either.
TSK-05Reminders, digest and notification centre
Each staff member starts the day with one digest and handles notifications in one place.
  • Given a user has 2 overdue tasks, 3 due today, 1 awaiting their review and 1 leave request awaiting their approval
  • When the clock reaches 08:00 in the centre's time zone
  • Then a single digest notification is created in the notification centre and pushed, listing the four groups with counts and the first three items of each; a digest email is sent if the user enabled it; per-task reminders (default 09:00 on the due date) keep working independently; selecting a notification marks it read through the existing endpoint and opens the right task.
TSK-06Teacher submits a leave request
A teacher requests two days off and immediately sees the affected sessions.
  • Given the teacher opens Đơn xin nghỉ in the mobile app
  • When they choose type Nghỉ phép, a date range and a reason, and submit
  • Then the system lists the sessions where the teacher is main or substitute teacher in that range before submission; the request is created as Chờ duyệt, the approver is the branch manager of the teacher's primary branch and is notified; the teacher can cancel while it is still Chờ duyệt.
TSK-07Approve a leave request and its impact
The branch manager approves and the system prepares the follow-up.
  • Given a pending request affecting 4 sessions
  • When the approver chooses "Duyệt" with an optional note
  • Then the request becomes Đã duyệt; each affected session is flagged "Cần dạy thay" (PRD 03) and a task "Phân công dạy thay: [lớp] [ngày]" is created for the branch's academic admin; sessions in the leave period stay out of the absent teacher's timesheet (PRD 06); the teacher is notified of the outcome; on "Từ chối" a reason is mandatory and sessions are untouched.
TSK-08Teacher reports an incident from the classroom
A teacher reports a broken air conditioner from a phone in under a minute.
  • Given the teacher is in a session and opens "Báo cáo sự cố" from the session screen
  • When they choose type Cơ sở vật chất, severity Trung bình, take two photos, type a short description and submit
  • Then the incident is created with branch, room and session pre-filled; a task "Xử lý sự cố: [tiêu đề]" is created for the branch manager with matching priority; a critical incident pushes immediately to the branch manager and the owner; the teacher follows the status in Sự cố của tôi.

4Screens

My work (desktop and mobile) /tasks/my · /teach/tasks

Groups in order: Quá hạn · Hôm nay · Chờ xác nhận của tôi · Tuần này · Sau đó. Each row: done checkbox, title, linked entity (chip with icon and name), due, priority, source (Giao tay / Lặp / Hệ thống), unread comment count. Filters: branch, source, linked entity. Row actions: Hoàn thành, Hoãn đến ngày mai, open detail. Empty state: "Không có việc nào đến hạn. Việc được giao và việc hệ thống sinh ra sẽ xuất hiện tại đây." On mobile the teacher's tab bar gains a Việc item.

Team work and recurring routines (desktop) /tasks/team · /tasks/routines

Table: title, assignees, assigner, linked entity, due, priority, status, source, last update. Filters: branch, assignee, status, priority, source, overdue. Side panel: per-staff summary (open, overdue, done in 7 days). Multi-select: Giao lại, Đổi hạn, Đóng with reason. Routines page: name, recurrence (daily, weekdays, weekly on day N), generation time, due after, assignee (staff or a role at the branch), branch scope, last generated, Đang chạy / Tạm dừng; a new tenant gets three suggested routines: Chốt quỹ (daily), Kiểm kho (Monday), Xác nhận lịch tuần tới (Friday). Empty state: "Chi nhánh chưa có công việc nào. Tạo mẫu công việc lặp để bắt đầu."

Task detail (drawer on desktop, screen on mobile) /tasks/:id

Header: inline-editable title, source, priority, due, status selector, assignees. Body: linked entity (link opens the right record), description, checklist, attachments, reminders (default 09:00 on the due date, + Nhắc button). Comments are a timeline of user comments (with @name mentions) and system comments (status changes, reassignment, escalation); the change log is reachable through "Lịch sử". Sticky action bar: Hoàn thành · Giao lại · Huỷ.

Leave requests (desktop and mobile) /leave · /teach/leave

Two tabs: Đơn của tôi and Chờ tôi duyệt (only for users with approval rights). Table: requester, type (Nghỉ phép / Nghỉ ốm / Nghỉ không lương / Đổi ca), from and to, days, affected sessions, status, approver, submitted at. Form: type, period (full day or morning/afternoon/evening), reason, attachment (medical note); for a shift swap: the session and proposed receiving teacher. Before submission the affected sessions are listed. Approvers see Duyệt / Từ chối with a note field. Empty state: "Chưa có đơn xin nghỉ nào."

Incidents (desktop) and Report incident (mobile) /incidents · /teach/incidents/new

Desktop: table per branch with title, type (Cơ sở vật chất / An toàn học viên / Hành vi / Thiết bị / Khác), severity (Thấp / Trung bình / Cao / Nghiêm trọng), room, reporter, time, status (Mới / Đang xử lý / Đã xử lý / Đóng), linked task. Mobile: one screen with type and severity (large chips), photos (max 5, compressed client-side), description; branch, room and session pre-filled from context; can be submitted offline and synced later. Empty state: "Chưa có sự cố nào trong 30 ngày."

Notification centre (panel) /notifications

Panel opened from the bell, filter chips: Tất cả · Công việc · Đơn xin nghỉ · Sự cố · Hệ thống. Each item: type icon, title, subtitle, relative time, unread mark. Actions: select to open, Đọc tất cả, per-item Lưu trữ; a "Cài đặt thông báo" link opens channel preferences per type (in-app always on; push and email toggleable). Empty state: "Không có thông báo mới."

5Business rules

  1. Valid status transitions: new → in_progress; in_progress → pending_review (when requires review is on) or done; pending_review → done or in_progress; any → cancelled with a reason. Done or cancelled tasks are not reopened.
  2. A task has at least one assignee. With several assignees the task is done when any of them completes it (default) or when all do (flag require_all). An assignee is a specific staff member or a role at a branch; for a role the system assigns every active staff member holding that role at creation time.
  3. Priority shares the lead scale of PRD 01. Overdue is not a status but the condition due_at < now on a task that is not done or cancelled.
  4. Recurring tasks are generated in the centre's time zone, skipping branch holidays (PRD 03) when the routine has that flag on. The pair (routine_id, period_key) is unique, so a period is never generated twice; editing a routine only affects future generations.
  5. System tasks carry dedupe_key = trigger_code plus linked entity. When an open task with the same dedupe_key exists, the system creates none, adds a system comment, raises priority one step (up to urgent) and re-reminds. After completion the dedupe_key is held for 7 days (tenant setting, 0 to 30) before regeneration.
  6. P1 triggers and default assignees: lead_cold (no interaction for 7 days; the lead's assignee), student_absent (thresholds per PRD 04; the student-care owner at the branch), invoice_overdue (7 days overdue; branch accountant), session_unmarked (ended more than 2 hours ago; the session's teacher, escalating to the branch manager after 24 hours), substitute_needed (branch academic admin), incident_new (branch manager). Each trigger can be switched off per tenant.
  7. Per-task reminders default to 09:00 on the due date, up to 3 more can be added; they go only to assignees of tasks that are not closed. The 08:00 digest is one daily_digest notification per user with at least one item, replaced if one already exists for the day. Push respects the quiet hours 21:30 to 07:00 (shared setting with PRD 04); in-app notifications are never held and auto-archive after 90 days.
  8. The notification centre keeps the existing endpoint contract; new types are added to the type enum, and the payload always carries entity_type and entity_id so the UI opens the right context.
  9. The requester may cancel a leave request only while pending; the approver may revoke an approved request before its start date with a reason, and substitute flags are removed if no substitute is assigned yet. A request overlapping another request of the same staff member is rejected at creation.
  10. The default approver is the branch manager of the requester's primary branch (PRD 06); when the requester is a branch manager the approver is the owner; the tenant may set an alternate approver per branch. A request untouched for 48 hours is escalated to the owner by notification; the system never auto-approves.
  11. On approval every session in the leave period where the requester is main or substitute teacher gets needs_substitute = true; PRD 03 handles assignment; those sessions produce no timesheet line for the absent teacher (PRD 06) unless that teacher actually marks attendance (attendance wins over the leave and a warning is logged). An approved shift swap creates the substitute assignment for the receiving teacher immediately.
  12. Each incident spawns exactly one handling task; closing the task moves the incident to resolved, the reporter confirms or it auto-closes after 3 days. Student-safety or critical incidents push immediately to the branch manager and owner, bypassing quiet hours.
  13. Every entity belongs to one centre (center_id) and one branch (school_id); a task without an explicit branch takes the creator's branch. A user sees only tasks where they are assigner, assignee or mentioned, or that fall within a branch in their permission scope. Attachments use the CRM file service: at most 10 files per task, 20 MB each.

6Data model

EntityFieldsNotes
taskid uuid; center_id; school_id; title; description; source enum(manual, routine, system, migrated); trigger_code null; dedupe_key null (unique while open); routine_id null; period_key null; linked_type enum(customer, student, class, session, invoice, incident) null; linked_id null; created_by_staff_id; priority enum(low, medium, high, critical, urgent); status enum(new, in_progress, pending_review, done, cancelled); require_review bool; require_all bool; due_at; completed_at; cancelled_reason; version intnew; indexes (center_id, school_id, status, due_at) and (linked_type, linked_id); audit detail in task_history
task_assigneetask_id; staff_id; assigned_by_rule enum(direct, role); role_code null; state enum(open, done); done_at; last_reminded_atprimary key (task_id, staff_id)
task_checklist_item · task_attachment · task_reminderchecklist: id; task_id; position; label; checked; checked_by. attachment: id; task_id; file_id; uploaded_by. reminder: id; task_id; kind enum(relative, absolute); offset_minutes null; fire_at; fired_at nullmax 30 items, 10 files, 4 reminders
task_commentid uuid; task_id; author_staff_id null (null means system); body; kind enum(user, system); mentions staff_id[]; created_atnew
task_routineid; center_id; school_ids[] (empty means all branches); name; title_template; checklist_template json; priority; require_review; recurrence enum(daily, weekdays, weekly); weekday null; generate_time; due_after_minutes; skip_holidays bool; assignee_rule {staff_ids[] | role_code}; is_paused; last_generated_atnew
notification (existing) · notification_preferencetype enum extended: task_assigned, task_due, task_overdue, task_commented, task_review_requested, task_returned, task_completed, leave_submitted, leave_decided, leave_escalated, incident_reported, incident_updated, daily_digest; payload {entity_type, entity_id, title, body}. preference: staff_id; type; push bool; email boolextend enum and payload only; preference is new
leave_requestid uuid; center_id; school_id; staff_id; type enum(annual, sick, unpaid, shift_swap); date_from; date_to; part_of_day enum(full, morning, afternoon, evening); session_id null; swap_with_staff_id null; reason; attachment_file_id null; status enum(pending, approved, rejected, cancelled); approver_staff_id; decided_at; decision_note; escalated_at nullnew; leave_request_session (leave_request_id; session_id; substitute_task_id null) computed at submission, recomputed at decision
incident · incident_attachmentid uuid; center_id; school_id; room_id null; session_id null; class_id null; reported_by_staff_id; type enum(facility, student_safety, behaviour, equipment, other); severity enum(low, medium, high, critical); title; description; status enum(new, in_progress, resolved, closed); task_id; resolved_at; closed_at. attachment: id; incident_id; file_idnew; max 5 photos, compressed to 1,600 px on the long edge
task_policy (tenant settings)dedupe_window_days (7); digest_time (08:00); default_reminder_time (09:00); triggers {lead_cold: {enabled, days}, student_absent, invoice_overdue: {enabled, days}, session_unmarked, substitute_needed, incident_new}; leave_approver_overrides [{school_id, staff_id}]; leave_escalation_hours (48); incident_autoclose_days (3)stored in centre settings (PRD 10)

7API contract

MethodPathRequest / responseStatus
GET/v3/crm/me/today-plan→ adds a tasks array (overdue, today, awaiting review) next to the existing calls and appointmentsexisting
GET · POST/v3/crm/me/notifications · /unread-count · /{id}/read · /read-all · /{id}/archivecontract unchanged; optional type? filter addedexisting
POST/v3/teacher/class-schedules/{id}/remind · /preview-remind-timeclass reminders to parents, PRD 07; reference onlyexisting
GET/v3/crm/customers/{id}/interactionsadditionally returns customer-linked tasks as timeline items kind = task (read-only); task creation uses /v3/crm/tasksextend
GET / POST/v3/crm/tasksview=my|team, school_id, assignee_id, status[], priority[], source, linked_type, linked_id, overdue, due_from, due_to, q; POST {title, description?, assignees: [{staff_id} | {role_code, school_id}], due_at?, priority?, require_review?, require_all?, linked?: {type, id}, checklist?, reminders?, attachments?}new
GET / PATCH/v3/crm/tasks/{id}detail with checklist, attachments, reminders, comments, history; PATCH with version, 409 STALE_VERSIONnew
POST/v3/crm/tasks/{id}/transition · /reassign · /v3/crm/tasks/bulk{to, reason?} validated per section 5; {assignees[], note?}; bulk {ids[], action: reassign|reschedule|cancel, payload}new
PUT · GET/POST · POST/DELETE/v3/crm/tasks/{id}/checklist · /comments · /reminderschecklist replaces the whole list; comment {body, mentions?} notifies mentioned staff; reminder {kind, offset_minutes | fire_at}new
GET / POST / PATCH / DELETE/v3/crm/task-routines · /{id}fields per section 6; PATCH {is_paused}; POST /{id}/run-now generates one period immediatelynew
GET / PUT/v3/crm/me/notification-preferences[{type, push, email}]new
GET / POST/v3/crm/leave-requestsview=mine|to_approve|all, school_id, staff_id, status[], from, to; POST {type, date_from, date_to, part_of_day, session_id?, swap_with_staff_id?, reason, attachment_file_id?} → with affected_sessions[]; POST /preview-impact returns affected_sessions[] before submissionnew
POST/v3/crm/leave-requests/{id}/decide · /cancel · /revokedecide {decision: approved|rejected, note?} (note required when rejected) flags sessions and creates substitute tasks; cancel by requester while pending; revoke by approver before start date {reason}new
GET / POST/v3/crm/incidentsschool_id, status[], severity[], type[], from, to; POST {type, severity, title, description, room_id?, session_id?, class_id?, attachments[], client_created_at?} idempotent by (reported_by, client_created_at)new
GET / PATCH/v3/crm/incidents/{id}detail with task; PATCH {status, severity?, note?}; POST /{id}/confirm-resolved by the reporternew
GET / PUT/v3/teacher/school-configtask_policy block addedextend
GET/v3/crm/tasks/reportschool_id, from, to, group_by=assignee|source|trigger → created, done, on-time, median completion time; consumed by PRD 09new

8Permissions

Codeownerbranch_manageradmissionsacademic_adminaccountantteacher
tasks.viewallbranchown + mentionedbranchown + invoice-linked in branchown + linked to own classes
tasks.createyesyesyes (linked to own customers)yesyesyes (linked to own classes, sessions)
tasks.assign_others, tasks.edit_any, tasks.bulk, tasks.team_viewallbranchno (self only)branchnono
tasks.routinesyesbranchnononono
leave.request, incidents.reportyesyesyesyesyesyes
leave.approveallbranchnononono
leave.viewallbranchownbranch (read, for substitutes)branch (read, for pay)own
incidents.manageallbranchnobranchnoown (confirm resolved)
tasks.policyyesnonononono
tasks.reportallbranchnobranchnono

Parents have no permission in this module; parent requests go through PRD 07 and become front-desk tasks through a system trigger.

9Analytics events

EventProperties
task_createdsource (manual|routine|system|migrated), trigger_code, linked_type, assignee_count, has_due, has_checklist, by_role, device
task_transitionedfrom, to, hours_open, was_overdue, by_role, source
task_dedupedtrigger_code, priority_before, priority_after
reminder_sentkind (task|digest), channel (in_app|push|email), quiet_hours_deferred
notification_openedtype, minutes_after_send, device
routine_generatedroutine_id, recurrence, schools_count, previous_period_incomplete
leave_submittedtype, days, part_of_day, affected_sessions, device
leave_decideddecision, hours_to_decide, escalated, affected_sessions
incident_reportedtype, severity, photos, offline_queued, seconds_to_submit
incident_resolvedhours_to_resolve, confirmed_by_reporter, autoclosed

10Edge cases

11Open questions

Trường Số (truongso.net) · FLYER internal