For Stakeholders
Why this matters
Retention and daily-active-use levers are usually about giving people a reason to open the app without being asked. This feature does the opposite on purpose: it pushes a reason to notice the app (a summary arrives whether or not anyone asks for it) at a moment — closing time — when an owner is naturally thinking about how the day went. It's a small feature, but it's the kind that compounds engagement without adding a single new screen to learn.
Scope and risk
This is a genuinely small, additive change:
- 2 new database columns, both defaulting to
true(no backfill risk, no
breaking change for existing users).
- 1 new hourly cron job, isolated in its own file, using the same locking
and observability patterns every other cron already uses.
- 2 new toggles reusing an existing settings screen on both web and
mobile — no new UI surface to design or maintain.
- No new third-party dependency — it reuses the existing Expo push
integration already used for other notification types.
Real risk to flag
- **A latent crash condition, not introduced by this PR but newly and
incorrectly commented as "handled" here:** if a company has no time zone configured, the code throws instead of falling back to UTC as its own comment claims — and because the whole nightly loop runs inside one try/catch, that throw would abort the run for every company not yet processed in that hour, not just the misconfigured one. This same gap already exists in three other crons this codebase runs nightly (expenses, messages, appointments), so it's a pre-existing condition across the crons module rather than something new — but it's worth a quick check that every live company actually has a time zone set, since this PR increases how much nightly value rides on that being true. See The Cron for the exact code path.
- Fire-and-forget delivery. If Expo's push service rejects a batch,
those users simply don't get notified — no retry, no alert. This matches the codebase's existing pattern for other push sends, so it's not a regression, just a ceiling on how reliable "guaranteed nightly delivery" can be marketed as.
- No automated test coverage for the new cron or its translation
helper — consistent with the rest of packages/server/src/cronJobs/, which has none either. Correctness currently rests on manual QA via the admin panel's manual-execute path.
What this is not
Not a reporting or analytics feature, not a compliance requirement, not tied to any external regulatory deadline (unlike, say, ZATCA work). It's a UX/engagement feature with a small, contained blast radius.