Dev Specs

Epic E04 — Task Execution [mobile]

Назначение эпика: Mobile-флоу исполнения задачи линейным персоналом «в поле» (Housekeeping, Handyman): открыть назначенную задачу → пройти чеклист по зонам → отметить выполнение/фото/комментарии → отслеживать таймер → завершить. Замыкает жизненный цикл задачи статусом Finished и фиксирует фактическое время исполнения. Участвует в use-cases: UC-2 (Task execution mobile) — потребитель задач, порождённых recalc engine (UC-1) и назначенных по Department Defaults юнита. Сущности (owns/touches):

  • touches/writes: Task (status transition, started_at / finished_at / total_time / on_track), Task.Event (Started / Finished / отметка зоны), Task.Cost 🟡 (см. ниже — на этих экранах costs не показаны), UnitArea (источник зон чеклиста), area photos.
  • reads: Unit (property meta: name / location / wifi / keybox / attachments), TaskTemplate.Section (per-area задачи: Task 1/2 + Reference + Task Description), Reservation (контекст Check-In).
  • Новых сущностей эпик НЕ вводит — переиспользует модель E03 (Task) из 00-overview.md §7. Экраны: S50 (My Tasks list), S41 (Unit/Check-In card + property meta), S45 (Task checklist + timer). Все 375×812. Открытые findings: F-filter-hierarchy-assignee (роль field-staff / Vendors scope — 00-overview.md §3).

S50 — My Tasks [mobile]

  • Назначение: список моих назначенных задач на исполнение — точка входа в mobile-флоу (нижний таб Tasks).
  • Источник (Miro): «Screen 9», id 3458764673067131618 (375×812). Текст: Tasks (заголовок) · карточки-повторы Due: 12:00 26/06/2026 · on track · Check In · Villa Alaya.
  • Layout: mobile-экран. Header Tasks. Вертикальный список карточек задач. Снизу — таб-бар shell-а (см. E11, Tasks активен).
  • Данные на экране (на карточку):
    • тип/название задачи — Check In (task name);
    • юнит — Villa Alaya (Unit.name);
    • срок — Due: 12:00 26/06/2026 (HH:MM DD/MM/YYYY, из Task.due_at);
    • статус-чип расписания — on track (on-track / due / overdue — производное от due_at vs now).
  • Контролы и действия:
    • карточка задачи → tap (button) → открывает S41 (карточка юнита / Check-In) для этой задачи.
    • 🟡 фильтр/сортировка списка на скелете отсутствуют — не добавляем.
  • Состояния/вкладки:
    • default — список назначенных задач;
    • on track / due / overdue — состояние чипа по сроку (цвет: electric-green / amber / red, 00-overview §4);
    • empty — 🟡 «No tasks assigned» (см. Edge cases);
    • loading / error — стандартные shell-состояния.
  • Связи (data-flow): читает Task где assignee = current user (назначение по Department Defaults юнита, задачи рождены recalc engine UC-1). Tap → S41. Не пишет.
  • Мутации: нет (read-only список).
  • Права: Field staff (Housekeeping / Handyman) — видят ТОЛЬКО свои назначенные задачи. Vendors — ограниченно (🟡 F-filter-hierarchy-assignee).
  • 🟡 [не было додумано]: на скелете все карточки = Check In; считаю это образцом, реально тип задачи произвольный (Cleaning, Check-Out и т.д. — единый Task). Не выдумываю фильтры/группировки сверх списка.
  • Edge cases:
    • empty — нет назначенных задач → 🟡 пустое состояние «No tasks assigned» (обоснование: иначе пустой экран без объяснения; field-сотруднику нужен явный сигнал «работы нет», а не подозрение на сбой).
    • длинный Unit.name / task name — обрезка с ellipsis в одну строку.
    • просроченная задача — чип overdue (red), задача остаётся в списке (не скрывается).

S41 — Unit / Check-In Card [mobile]

  • Назначение: карточка занятого юнита с контекстом задачи (Check In) и property meta, нужным для входа на объект и исполнения; точка перехода в чеклист.
  • Источник (Miro): «Screen 11», id 3458764673071102027 (375×812). Текст: < (back) · OCCUPIED · Check In · Task task task · Due: 12:00 26/06/2026 · Task Description + lorem · Property (Name: Villa Alaya, Location: Jl. Raya Semat No.88, Canggu… Bali 80361, Wifi Login:, Wifi Password:, Keybox Code: 123456) · Attachments > · Comments.
  • Layout: mobile. Top-bar: < back + occupancy-чип OCCUPIED. Блок задачи: тип (Check In), название (Task task task), Due: …, секция Task Description (текст). Блок Property (meta-поля списком). Раскрываемые секции Attachments > и Comments. CTA на старт исполнения 🟡 (см. ниже).
  • Данные на экране:
    • Task: Check In (тип), Task task task (name), Due: 12:00 26/06/2026 (due_at), Task Description (описание).
    • Occupancy: OCCUPIED (Unit/Reservation статус занятости; альт. VACANT).
    • Property (Unit meta): Name (Villa Alaya), Location (адрес), Wifi Login, Wifi Password, Keybox Code (123456).
    • Attachments: список файлов юнита/задачи (раскрывается по >).
    • Comments: комментарии к задаче.
  • Контролы и действия:
    • < (button) → назад в S50.
    • Attachments > (button/disclosure) → раскрыть/открыть вложения.
    • Comments (button/disclosure) → раскрыть/добавить комментарий к Task. 🟡 add-comment input на скелете не отрисован — отметка точки, без формы.
    • переход к чеклисту → открывает S45. 🟡 явная кнопка («Start» / тап по задаче) на скелете не подписана (см. дозумано).
  • Состояния/вкладки:
    • occupancy: OCCUPIED / VACANT (chip);
    • Attachments / Comments — collapsed / expanded;
    • task status задаётся неявно (см. S45: старт таймера = New → In Progress).
  • Связи (data-flow): читает Unit (meta), Task (поля + описание), Reservation (occupancy/Check-In контекст), attachments, comments. Переход → S45 (чеклист). Запись комментария → Task.Event/comment (логически).
  • Мутации:
    • add comment → создаёт comment/Task.Event на Task (если пользователь пишет).
    • переход в S45 и старт таймера там → транзиция статуса (см. S45).
  • Права: Field staff — только назначенные задачи своих юнитов; видят property meta (wifi/keybox нужны для входа). Read property meta; write — только comments/исполнение.
  • 🟡 [не было додумано]:
    • CTA перехода в чеклист. На скелете нет подписанной кнопки между S41 и S45, но флоу требует перехода. Достраиваю: tap по блоку задачи (или кнопка Start / Open checklist) → S45. Обоснование: без явного перехода карточка — тупик; минимальное добавление, не меняет данные.
    • Comments — точка-маркер без формы ввода на скелете; добавление комментария оставляю как логическую возможность, UI-форму не выдумываю детально.
  • Edge cases:
    • VACANT юнит (для Cleaning/Check-Out) — тот же layout, чип VACANT.
    • пустые wifi/keybox — поле с прочерком/скрыто (не показывать «null»).
    • длинный адрес Location — перенос на несколько строк (как в скелете).
    • нет attachments / comments — секция раскрывается в пустое состояние «No attachments» / «No comments» 🟡 (обоснование: раскрытие пустой секции без текста читается как баг).

S45 — Task Checklist + Timer [mobile]

  • Назначение: исполнение задачи по чеклисту — зоны (Areas) с per-area подзадачами, отметки выполнения, фото, отсчёт таймера; ядро флоу.
  • Источник (Miro): «Screen 12», id 3458764673072718144 (375×812). Текст: < · 00:02:00 (таймер) · Areas · collapse · hide done · Bathroom / Bedroom (зоны) · 0 of 20 (прогресс зоны) · 🔻 (collapse-маркер) · Task 1 / Task 2 + Reference + Task Description … (lorem).
  • Layout: mobile. Top-bar: < back + крупный таймер 00:02:00 (running). Блок Areas с контролами collapse и hide done. Список зон (Bathroom, Bedroom …), каждая: заголовок + счётчик 0 of 20 + collapse-маркер 🔻; внутри зоны — подзадачи Task 1, Task 2: Reference (эталон/референс-фото) + Task Description + место под фото-отметку.
  • Данные на экране:
    • Timer: 00:02:00 — накопленное время исполнения (HH:MM:SS), идёт от старта задачи; источник started_at.
    • Area (UnitArea): имя зоны (Bathroom / Bedroom), прогресс 0 of 20 (done / total подзадач зоны).
    • Sub-task (per-area, из TaskTemplate.Section): Task 1 / Task 2, Reference (референс), Task Description (что сделать), фото-вложение по подзадаче/зоне (area photos).
  • Контролы и действия:
    • < (button) → назад в S41 (исполнение продолжается, таймер не сбрасывается).
    • collapse (button/toggle) → свернуть/развернуть все зоны.
    • hide done (toggle) → скрыть завершённые подзадачи/зоны.
    • 🔻 на зоне (toggle) → свернуть/развернуть конкретную зону.
    • отметка подзадачи выполненной (checkbox 🟡) → инкремент счётчика done of total.
    • прикрепить фото к подзадаче/зоне (button → camera/upload) → area photo.
    • завершение задачи → транзиция In Progress → Finished (CTA Finish 🟡 — см. дозумано).
    • 🟡 таймер start/pause control на скелете не подписан — старт привязываю к входу в исполнение (см. мутации).
  • Состояния/вкладки:
    • timer running (по умолчанию на экране);
    • area: expanded / collapsed; глобально collapse all;
    • hide done on/off;
    • sub-task: pending / done;
    • completion: все зоны N of N → готово к Finish;
    • empty (нет зон/чеклиста) — 🟡 см. Edge cases;
    • photo error — 🟡 см. Edge cases.
  • Связи (data-flow):
    • читает UnitArea (зоны юнита) + TaskTemplate.Section (per-area подзадачи, Reference, Description) для данной Task.
    • пишет: отметки/фото → Task.Event (+ area photos); таймер → Task.started_at / total_time; завершение → Task.status, Task.finished_at, Task.on_track.
    • downstream (логически): завершённая задача с area photos питает Area Report → Maintenance Report (E06), как в 00-overview §5.
  • Мутации (статус-машина задачи — ядро эпика):
    • New → In Progress: при старте исполнения (вход в чеклист / старт таймера). Фиксируется started_at + Task.Event Started.
    • In Progress (рабочее): отметки подзадач, area photos, накопление времени; промежуточные Task.Event.
    • In Progress → Finished: по завершению (Finish). Фиксируется finished_at, total_time (= finished − started, накопленное), on_track (производное: finished_at ≤ due_at → on track, иначе overdue) + Task.Event Finished.
    • Соответствует расписаночному жизненному циклу Planned/New → In Progress → Finished (00-overview §4); Planned — состояние до назначения/старта (recalc engine), на mobile сотрудник видит уже New+.
  • Права: Field staff (assignee) — единственные, кто переводит задачу In Progress/Finished и грузит area photos. Coordinator видит результат на desktop (E03/E06), но исполнение — mobile assignee.
  • 🟡 [не было додумано]:
    • Чекбокс отметки подзадачи — счётчик 0 of 20 подразумевает отметку выполнения, но сам контрол на скелете не отрисован. Достраиваю минимальный per-sub-task check (инкрементит счётчик). Обоснование: без него прогресс done of total недостижим.
    • CTA Finish — транзиция в Finished нужна флоу, кнопка на скелете не подписана. Достраиваю Finish (доступна когда все зоны/подзадачи done, либо явное подтверждение при незавершённых 🟡). Обоснование: иначе задача не закрывается.
    • Таймер start: привязка старта к началу исполнения (не отдельная кнопка) — скелет показывает уже бегущий 00:02:00. Pause/stop не выдумываю.
    • Offline: НЕ добавляю (вне скелета; field-связь на Bali может рваться, но прототип это не специфицирует — не оверинжинирим).
  • Edge cases:
    • photo error — 🟡 сбой загрузки/съёмки фото → inline-ошибка «Photo failed, retry» + retry, отметка подзадачи не теряется (обоснование: field-сеть нестабильна, фото — ключевой артефакт Area Report; молчаливая потеря недопустима).
    • empty checklist — у задачи нет зон/template-секций → 🟡 «No checklist for this task» + возможность всё равно Finish (обоснование: разовая задача может не иметь чеклиста).
    • Finish при незавершённых подзадачах — 🟡 подтверждение «N tasks not done, finish anyway?» (обоснование: предотвратить случайное закрытие, но не блокировать — реальность поля).
    • длинный Task Description — скролл/перенос (как lorem в скелете).
    • таймер при уходе с экрана (< / сворачивание) — продолжает идти (время = wall-clock от started_at, не зависит от того, открыт ли экран).

Cross-screen relations (внутри эпика)

S50 (My Tasks list)
   │ tap карточки задачи
   ▼
S41 (Unit / Check-In card + property meta)
   │ Start / Open checklist 🟡
   ▼
S45 (Checklist + Timer)
   │  старт исполнения → Task: New → In Progress (started_at, Event Started)
   │  отметки + area photos (Task.Event)
   │  Finish → Task: In Progress → Finished (finished_at, total_time, on_track, Event Finished)
   ▼
(downstream, вне эпика) Area Report → Maintenance Report (E06)

< на S45 → возврат на S41 (исполнение и таймер сохраняются). < на S41 → S50.

Решения заказчика (2026-06-22)

Ответы со встречи Akira × Sergey (реестр 00-client-questions.md).

  • Q-06 · task lifecycle — РЕШЕНО: mobile (этот эпик) — только исполнение задач. Создание задачи (4 источника, см. E03) и апрув — на desktop. Подтверждает текущую модель эпика (S50/S41/S45 = открыть → исполнить → Finish); на mobile НЕ добавляем создание/апрув. Часть manager-report тасков исполняется на desktop, но это вне mobile-эпика.

Дозумано на уровне эпика 🟡

  • Переходы между экранами (S41→S45 CTA, отметка подзадачи, Finish). Скелет показывает экраны-состояния, но не подписывает кнопки переходов/завершения. Достроены минимальные контролы, без которых флоу «открыть → исполнить → завершить» не замыкается. Отклонение от прототипа — только в наличии явных CTA, не в данных/логике.
  • Статус-машина и тайм-трекинг. New → In Progress → Finished + started_at / finished_at / total_time / on_track явно прописаны (требование задания): они выводятся из таймера 00:02:00, чипа on track и статусной модели 00-overview §4. Новых сущностей нет — поля Task / Task.Event из индекса §7.
  • Costs на mobile. Task.Cost существует в модели (E03), но на S41/S45 НЕ показан → на этих экранах НЕ добавляем ввод costs (минимализм; costs — desktop/Report-контур E06).
  • Empty / photo-error состояния. Добавлены явные пустые состояния (нет задач / нет attachments / нет comments / нет чеклиста) и обработка ошибки фото — необходимый UX для field-сценария, прямо запрошены в задании; всё помечено 🟡 на местах.
  • Offline — сознательно НЕ добавлен (вне скелета, прототип не специфицирует синхронизацию).