(WEB_PORTAL) Building a Weekly Work Report Aggregation Feature and Notification System
Overview
We moved the weekly work reports that team members used to write as scattered individual documents into the service itself, where they can be written and viewed together by admins on a single screen. At the same time, we also built a shared notification system that could be used across the entire service.
Key Implementation Points
1. ISO Week Calculation Utility
To manage reports by week number, we implemented the ISO week rules (including year-boundary handling) ourselves as plain calculation functions, without an external library. A big part of the motivation was avoiding the issue where week-number results can subtly differ depending on the library version.
toWeekId(date): converts to "YYYY-W<week>" format
getCurrentWeekId(): the current week number based on today
getRecentWeekIds(n): list of the last n weeks
weekIdToLabel(weekId): converts to a human-readable label like "Week 16, 2025"
2. Report Writing and Aggregation Screens
The writing screen collects three fields — this week's progress, issues, and next week's plan — and shows the previous two weeks' entries alongside it for reference. The aggregation screen lets admins select recent weeks, surfaces people who haven't submitted yet so they stand out, and includes a button for admins to send a reminder notification to those people.
3. Shared Notification System
When a specific event occurs (a report submission reminder, a new item pending approval, etc.), a record is written to a notifications table. The bell icon in the top-right of the screen periodically polls this table and displays the unread count as a badge. Each notification type uses a different icon so its nature can be recognized at a glance.
Retrospective
- For something needed in common across multiple features, like notifications, designing a shared table and component from the start — rather than building it separately for each feature — made it much easier to add new notification types later.
- For logic that looks simple on the surface but has tricky edge cases, like date/week calculations around year boundaries, writing our own small pure functions instead of relying on an external dependency actually made testing and debugging easier.