This guide describes the Weekly brief feature in APM: ISO-week–based division and directorate reporting, PDFs, reminders, compiled email packs, and access rules.
filing_iso_week_offset).directorates.director_id) may review submitted briefs for configured reporting units in their directorate (including legacy d-* keys mapped via divisions.directorate_id).Access is enforced by App\Services\DivisionWeeklyBriefGate (nav, routes, and report actions).
| Audience | Access |
|----------|--------|
| System admin (role 10) | Full access, including Weekly briefing settings. |
| Configured contributors | Rows in weekly_briefing_contributors for their staff_id and contribution_key. |
| Report viewers | report_viewer_staff_ids on settings: read all configured units’ reports (and compiled exports where allowed). |
| Directorate directors | When division_directors_can_access_module is enabled (name is legacy): staff listed as directorates.director_id on at least one active directorate. Session staff id is resolved from staff_id or auth_staff_id. |
| Division admin assistants | Staff listed as divisions.admin_assistant on at least one division. They see only configured contributor rows for those divisions and may view, edit, and submit weekly briefs on behalf of the assigned division head (same filing window as the contributor). Submission is attributed to the configured contributor / division head (submitted_by_staff_id); the admin assistant is recorded on the director completion trail (submitted_on_behalf). |
The top menu item Weekly brief and the home dashboard card are shown when DivisionWeeklyBriefGate::canAccessModule() is true (App\Providers\AppServiceProvider passes showDivisionWeeklyBriefNav into layouts.partials.nav).
| Method | Path (relative to APM base) | Name | Notes |
|--------|-----------------------------|------|--------|
| GET | weekly-briefing | weekly-briefing.index | Tabs: This reporting week (uses configured filing ISO week) / All reports; filters and pagination. Each tab lists a Directorate column when the row’s contribution key maps to a directorate (d- via divisions.directorate_id, dr- via the directorate id): directorate name and assigned director (directorates.director_id → Staff::name); otherwise the cell is empty. Search on both tabs matches directorate and director names where present. |
| GET | weekly-briefing/create | weekly-briefing.create | Start a report (contribution_key query). |
| GET/PUT | weekly-briefing/{report}/edit, weekly-briefing/{report} | weekly-briefing.edit, weekly-briefing.update | Draft / submitted editing per rules. |
| POST | weekly-briefing/{report}/director-review | weekly-briefing.director-review | Record director review when applicable. |
| GET | weekly-briefing/{report}/pdf | weekly-briefing.pdf | Single-unit PDF. |
| GET | weekly-briefing/compiled/{year}/{week}/pdf | weekly-briefing.compiled-pdf | Organisation-wide compiled PDF (allowed roles). |
| GET | weekly-briefing/compiled/{year}/{week}/completion-pdf | weekly-briefing.completion-summary-pdf | Completion summary PDF. |
| GET | weekly-briefing/directorate-combined/{year}/{week}/{directorate_id}/pdf | weekly-briefing.directorate-combined-pdf | Director-scoped combined PDF. |
| GET/PUT | weekly-briefing/settings | weekly-briefing.settings.edit, weekly-briefing.settings.update | Admin only (role 10). |
d-{apm_division_id} (matches divisions.id / APM division).dr-{directorate_id}.Contributors and listing keys are driven by weekly_briefing_contributors linked to weekly_briefing_settings. Each hub row is one contributor record with its own d-{division_id} brief (contributing division required). Directorate on a row is optional metadata for director review and directorate combined PDFs — not a shared report. Use PDF display name to override labels on the hub and PDFs. Legacy dr-{directorate_id} keys are migrated to division keys via php artisan weekly-briefing:repair-contribution-keys or by saving settings.
Route: weekly-briefing/settings (WeeklyBriefingSettingsController).
Typical options include:
hod_reminder_days_before_deadline always includes offsets 1 and 0 when saved; extra offsets such as 2 are optional). The scheduler matches calendar day and H:i; sends stop after the deadline passes.director_review_reminder_days_before_deadline (e.g. 1 for one day before the deadline; do not use 0) — grouped emails at HoD reminder time on those calendar days. On the deadline calendar day, a separate nudge runs 4 hours before submission closes (not at close time). Stops after the deadline. On submit, directors also get an immediate email when a brief still needs review (see Email).compiled_exclude_unreviewed_director_divisions — when enabled, the organisation-wide compiled PDF and central compiled attachment omit submitted briefs (d- and dr-) that require director review but are not yet marked reviewed (default off / include all).filing_iso_week_offset — 0 = ISO week that contains “today”; 1 = the next ISO week (e.g. brief ahead for the coming week). Drives the index “This reporting week” tab, default create targets, weekly-briefing:hod-reminders, weekly-briefing:director-review-reminders, and weekly-briefing:compiled-summary week selection. When 1, WeeklyBriefingReport::submissionDeadline() uses submission weekday in the calendar week before that reporting week’s Monday (same clock as Submission closes). When 0, the deadline is that weekday inside the reporting ISO week.division_directors_can_access_module): allow directorate directors to open the module and review configured units.staff_id values with read-only access across units.Settings row selection uses WeeklyBriefingSetting::current() (deterministic: prefers the most recently updated row when duplicates exist).
submissionDeadline($settings); weekly-briefing:lock-drafts sets draft rows to locked unless an unlock applies to that report.directorates.director_id set and the brief is submitted, that director may record review via the UI / director-review endpoint; trail fields on weekly_briefing_reports store audit data.Statuses and helpers live on App\Models\WeeklyBriefingReport.
WeeklyBriefingController::pdf and views under resources/views/weekly-briefing/.WeeklyBriefingCompletionSummary, compiled PDF views.dr- and d- briefs under a directorate for the directorate director): App\Services\WeeklyBriefingDirectorateCombined.App\Support\WeeklyBriefingMailTemplate and Blade under resources/views/emails/ (e.g. weekly briefing notification).WeeklyBriefingCompiledSummaryCommand, WeeklyBriefingHodRemindersCommand, and WeeklyBriefingDirectorReviewRemindersCommand (see below). Text reminders use WeeklyBriefingNotificationMailer → SendNotificationEmailJob::dispatchSync (same Exchange/SMTP path as approval alerts). Compiled PDF attachments use sendEmail() → Graph directly (binary attachments cannot be queued in the job JSON).directorates.director_id), WeeklyBriefingController::update dispatches SendWeeklyBriefingDirectorReviewReminderJob, which emails that director’s work_email via sendEmail + WeeklyBriefingMailTemplate (WeeklyBriefingDirectorSubmitNotifier). Skipped if submitter is the same as the director or the director has no email. Applies to both d- (via divisions.directorate_id) and dr- keys.| Command | Purpose |
|---------|---------|
| weekly-briefing:hod-reminders | Reminds contributors (and related staff) about missing briefs for the configured filing ISO week. Without --force, respects reminders_enabled, deadline-relative days (hod_reminder_days_before_deadline), and hod_reminder_time from settings (same as the HoD reminder time field on the settings page). Uses the same mail path as approval notifications (SendNotificationEmailJob, Exchange + SMTP fallback). |
| weekly-briefing:director-review-reminders | Reminds directorate directors about submitted briefs still pending director review. Without --force, respects reminders_enabled, day-before offsets in director_review_reminder_days_before_deadline (at HoD reminder time), plus a deadline-day send 4 hours before submission closes; stops after the deadline. |
| weekly-briefing:lock-drafts | Locks draft reports past their submission deadline (skips rows covered by report unlock override). |
| weekly-briefing:compiled-summary | Sends compiled / summary emails per settings; without --force, respects reminders_enabled, the calendar day of the filing week submission deadline (same rule as WeeklyBriefingSetting::filingSubmissionDeadline() / advance filing), and summary_send_time (with same-day catch-up until end of deadline day). Central recipients always receive at least the completion summary PDF even when no briefs were submitted. Organisation-wide compiled PDF honours compiled_exclude_unreviewed_director_divisions. |
| weekly-briefing:test-notifications | Sends sample weekly-brief emails to a given address to verify SMTP. |
| weekly-briefing:repair-contribution-keys | Migrates legacy shared dr- contributor/report rows to per-division d- keys (run once after deploy if divisions were entangled). |
In bootstrap/app.php, the scheduler runs (each with overlap protection):
weekly-briefing:hod-reminders — every minute (command self-gates on deadline-relative day + time).weekly-briefing:director-review-reminders — every minute (same pattern; only when there is pending director review work).weekly-briefing:lock-drafts — every minute.weekly-briefing:compiled-summary — every minute.Production still requires php artisan schedule:run in cron (see Cron Setup).
jobs/weekly-briefing (jobs.weekly-briefing) — triggers test or operational weekly-brief mail actions from the Jobs UI (test inbox, forced HoD reminders, forced director review reminders, forced compiled summary; whitelist / role checks in JobsController).All PDFs generated through generate_pdf() / mpdf_print() in app/Helpers/home_helper.php share the same HTML footer:
document_url or source_url, else the current HTTP request()->url(), else config('app.url').document_url explicitly (ActivityController::buildActivityMemoPdfForOutput) so the QR encodes the canonical memo PDF URL even when the PDF is built from another route (e.g. email).inline-block wrapper. QR display size is tuned in home_helper.php (Endroid QrCode size and CSS mm width/height).If QR generation fails (e.g. missing GD), the footer falls back to a small plain-text URL in the QR column.
| Area | Path |
|------|------|
| Gate / listing keys | app/Services/DivisionWeeklyBriefGate.php |
| Directorate combined PDF logic | app/Services/WeeklyBriefingDirectorateCombined.php |
| Completion summary rows | app/Services/WeeklyBriefingCompletionSummary.php |
| Deadline / unlock | app/Services/WeeklyBriefingWindowService.php |
| HTTP controller | app/Http/Controllers/WeeklyBriefingController.php |
| Settings | app/Http/Controllers/WeeklyBriefingSettingsController.php |
| Artisan (HoD / director / compiled mail) | app/Console/Commands/WeeklyBriefingHodRemindersCommand.php, WeeklyBriefingDirectorReviewRemindersCommand.php, WeeklyBriefingCompiledSummaryCommand.php |
| Models | app/Models/WeeklyBriefingSetting.php, WeeklyBriefingReport.php, WeeklyBriefingContributor.php |
| Nav composer | app/Providers/AppServiceProvider.php |
- Enable directorate director access (division_directors_can_access_module) in settings.
- Confirm staff_id / auth_staff_id in session matches directorates.director_id on an active directorate.
- Ensure WeeklyBriefingSetting::current() is the row you edit (avoid duplicate settings rows with conflicting flags).
- Check reminders_enabled, times, and for HoD mails the days-before-deadline list; for director mails, day-before offsets (at HoD reminder time) and the 4 hours before close slot on deadline day; use --force on the Artisan command once to verify mail outside the window.
See also: Jobs and Commands (scheduler overview), README index.