# Handover FE — Daily Activity Report (PDF) Status: backend selesai (commit `6d006cc`, seeder `3a85112`). Tidak ada perubahan di `middleware_socket-gateway`. --- ## 1. Ringkasan Download PDF laporan daily activity **per project**. Pola persis seperti hierarchy report: 1. FE `POST` bikin job → status `QUEUED` 2. Worker BullMQ generate PDF → `PROCESSING` → `READY` / `FAILED` 3. Setiap perubahan status dipush lewat socket event `document-download:updated` 4. FE ambil file lewat `GET /:jobId/download` (blob, **bukan** lewat socket) Tidak ada persentase progres — hanya status. Sama seperti hierarchy. --- ## 2. Endpoint Semua di bawah workspace path, butuh login + membership workspace: ``` POST /api/workspaces/:workspaceId/daily-activity-reports GET /api/workspaces/:workspaceId/daily-activity-reports POST /api/workspaces/:workspaceId/daily-activity-reports/:jobId/retry DELETE /api/workspaces/:workspaceId/daily-activity-reports/:jobId GET /api/workspaces/:workspaceId/daily-activity-reports/:jobId/download ``` Authz: member workspace **dan** harus punya role `MEMBER` / `OWNER` / `ADMIN` di project target. Project di luar workspace path → `404 Project not found in workspace`. --- ## 3. Create job ```http POST /api/workspaces/:workspaceId/daily-activity-reports Content-Type: application/json ``` ```json { "scope_id": "uuid-project", "period_type": "ALL", "period_index": "ALL", "start_date": "2026-11-01T00:00:00.000Z", "end_date": "2026-11-07T23:59:59.999Z" } ``` | Field | Wajib | Keterangan | |---|---|---| | `scope_id` | ya | id **project** (report ini project-only, tidak ada `scope_type`) | | `period_type` | ya | `WEEKLY` \| `MONTHLY` \| `CUSTOM` \| `ALL` | | `period_index` | tidak | label granularitas, lihat §4 | | `start_date` / `end_date` | tidak | window eksplisit; `CUSTOM` pakai ini verbatim, `WEEKLY`/`MONTHLY` fallback ke tanggal project, `ALL` diabaikan | Response = row job: ```json { "id": "uuid", "project_id": "uuid-project", "period_type": "ALL", "period_index": "ALL", "start_date": null, "end_date": null, "seq": 1, "file_name": "001/PRJ/ALL/2026113", "status": "QUEUED", "s3_key": null, "error_message": null, "requested_by": "uuid-user", "generated_at": null, "queued_at": "2026-11-03T02:11:04.518Z", "generated_day": "20261103", "cleared_at": null, "updated_at": "2026-11-03T02:11:04.518Z" } ``` `file_name` dipakai sebagai doc number di footer PDF (`Page X of Y` di kanan, logo ConsDoc di kiri). Slash di-strip hanya saat download. --- ## 4. `period_index` & label periode di PDF Subtitle PDF = `header.periodLabel` yang dibentuk backend: | `period_type` | `period_index` | `window.label` | Subtitle PDF | |---|---|---|---| | `WEEKLY` | `W3` | `Week 3` | `Week 3 Report : 12 Januari 2025 - 18 Januari 2025` | | `WEEKLY` | `ALWK` | `All week` | `All week Report : …` | | `MONTHLY` | `M4` | `Month 4` | `Month 4 Report : …` | | `MONTHLY` | `ALMT` | `All month` | `All month Report : …` | | `CUSTOM` | `CSM` (default) | `Custom` | `Custom Report : 5 Januari 2025 - 12 Januari 2025` | | `ALL` | `ALL` (default) | — | `All Data` | FE tinggal kirim `period_index` sesuai pilihan user. Kalau kosong: `ALL` → `ALL`, sisanya → `CSM`. **`ALL` = seluruh daily activity project**, tanpa clamp tanggal project. Daily activity yang diisi setelah `endDate` project tetap ikut (project belum `CLOSED`). --- ## 5. List / inbox ```http GET /api/workspaces/:workspaceId/daily-activity-reports?tab=in_process&page=1&limit=20 ``` | Query | Default | Keterangan | |---|---|---| | `scope_id` | — | kalau diisi, inbox cuma project itu (di-assert dulu) | | `tab` | `in_process` | `in_process` = `QUEUED`/`PROCESSING`/`FAILED`; `files_ready` = `READY` | | `page` | `1` | | | `limit` | `20` | max 100 | ```json { "data": [ { "id": "uuid", "seq": 1, "file_name": "001/PRJ/ALL/2026113", "status": "READY", "error_message": null, "generated_at": "2026-11-03T02:11:09.201Z", "queued_at": "2026-11-03T02:11:04.518Z" } ], "meta": { "page": 1, "limit": 20, "total": 1 } } ``` Urut `queued_at desc`. Row yang sudah di-clear tidak pernah muncul. > Catatan: list **belum** mengembalikan `project_id` / `period_type` / `period_index`. Kalau FE mau menampilkan label periode per baris di inbox, bilang — tiga field tinggal ditambahkan ke `select`. --- ## 6. Socket Reuse client yang sudah ada di FE: ``` web_consdoc/src/clients/document-download/document-download-socket.client.ts ``` Event: `document-download:updated` (konstanta `DOCUMENT_DOWNLOAD_SOCKET_EVENTS.UPDATED`). ```ts { change: 'created' | 'status', source: 'daily-activities-report', // beda dari hierarchy item: { id: string, project_id: string, period_type: string, period_index: string, seq: number, file_name: string, status: 'QUEUED' | 'PROCESSING' | 'READY' | 'FAILED' | 'CANCELLED', error_message: string | null, generated_at: string | null, queued_at: string } } ``` Filter `payload.source === 'daily-activities-report'` di hook. Audience = semua member workspace project itu (bukan per-user khusus), jadi beberapa tab bisa menerima event yang sama. Tidak ada event `created` terpisah yang perlu ditangani selain yang sudah ada di client — backend mengirim `change: 'created'` untuk row baru, `change: 'status'` untuk transisi status. --- ## 7. Download ```http GET /api/workspaces/:workspaceId/daily-activity-reports/:jobId/download ``` Response `application/pdf` dengan header: ``` Content-Disposition: attachment; filename="001-PRJ-ALL-2026113.pdf" ``` Ambil sebagai blob (`responseType: 'blob'`) lalu `URL.createObjectURL`. Hanya `status: READY` yang bisa; selain itu `404 Report job not found`. --- ## 8. Retry & clear **Retry** — hanya `FAILED`: ```http POST .../:jobId/retry ``` → status balik `QUEUED`, `error_message` di-null-kan. `seq` dan `file_name` **tidak** diregenerasi (nama file beku sejak create). **Clear download** — soft delete: ```http DELETE .../:jobId ``` - `QUEUED` / `PROCESSING` → jadi `CANCELLED` + `cleared_at` diisi (worker skip) - `READY` / `FAILED` / `CANCELLED` → `cleared_at` diisi, objek S3 dihapus best-effort - Nomor file tidak pernah dipakai ulang karena `seq` menghitung row yang sudah di-clear juga --- ## 9. Isi PDF Header: breadcrumb `agendaName → programName` (kiri) + tanggal report (kanan), title `Progress Report - `, subtitle label periode, garis pemisah, heading `Daily Activities` + `Record your daily activities on Consdoc`. Tabel per hari (banner tanggal biru muda, header tabel ikut berulang saat pindah halaman): | Time | Activity | Division guest | Shared | Action plan | |---|---|---|---|---| Aturan data: - `Time` = `HH:mm – HH:mm` (en dash) - `Division guest` = nama divisi tamu; `—` kalau kosong - `Shared` = teks berwarna, **bukan pill**: `VISIBLE TO TEAM` (biru) untuk `PUBLIC`, `NO` (abu) untuk `PRIVATE` - `Action plan` = nama item action-plan yang di-link, digabung `, `; `—` kalau tidak ada - `note` tidak ditampilkan - Tanggal banner: `Senin, 03 Nov 2026` (nama hari Indonesia + bulan singkat) - Kosong → satu baris `No daily activity in this period` --- ## 10. Aturan visibility (penting untuk ekspektasi user) PDF **tidak** menampilkan semua baris. Filter per row: | Kondisi | Tampil? | |---|---| | `PUBLIC` | ya, selalu | | `PRIVATE`, dibuat oleh user yang request | ya | | `PRIVATE`, user lain, requester `OWNER`/`ADMIN` workspace | ya | | `PRIVATE`, user lain, requester `MEMBER` biasa | **tidak** | Artinya dua user bisa generate report periode sama dan dapat isi berbeda. Kalau user komplain "kok baris saya hilang", cek role-nya di workspace. --- ## 11. Error | Kasus | Status | Body | |---|---|---| | Project bukan milik workspace path | 404 | `Project not found in workspace` | | Role project kurang | 403 | `You do not have required role perform action` | | Retry job bukan `FAILED` | 400 | `Only FAILED jobs can be retried` | | Job tidak ada / sudah clear | 404 | `Report job not found` | | Job belum `READY` saat download | 404 | `Report job not found` | | Generate gagal | row `FAILED` | `error_message` berisi pesan Gotenberg/Chromium | `error_message` dipotong 65000 char. Tampilkan di UI untuk tab `in_process`. --- ## 12. Yang belum ada - Tidak ada progres persentase, tidak ada estimasi durasi. - Tidak ada filter per-user di inbox (semua row project/workspace terlihat). - Belum ada endpoint untuk preview HTML (hanya PDF). - File lama tidak otomatis expire; umur file tergantung lifecycle S3.