Skip to content

chore: backfill voice logs and fix timezone handling#262

Merged
danielhe4rt merged 6 commits into
4.xfrom
chore/backfill-voice-logs
May 20, 2026
Merged

chore: backfill voice logs and fix timezone handling#262
danielhe4rt merged 6 commits into
4.xfrom
chore/backfill-voice-logs

Conversation

@danielhe4rt
Copy link
Copy Markdown
Contributor

Summary

  • Backfill command (discord:backfill-voice): paginates a Discord channel to reimport voice join/left events from Dyno bot, with rate limit handling, duplicate detection, and progress display via Laravel Prompts
  • Timezone normalization: PersistVoiceStateAction now uses now()->utc() instead of now() so gateway voice events match ETL timestamps
  • timestamptz migration: converts voice_messages.occurred_at from timestamp to timestamptz (treating existing values as UTC)
  • Dashboard query fix: removes double AT TIME ZONE cast in VoiceHeatmap and VoicePerDay that caused a +3h shift after the timestamptz migration

Test plan

  • Run php artisan discord:backfill-voice <channel_id> --dry-run to verify pagination and duplicate detection
  • Run php artisan discord:backfill-voice <channel_id> --since=2026-04-01 --until=2026-05-01 to backfill April gap
  • Verify voice dashboard heatmap shows correct BRT hours after migration
  • Verify VoicePerDay daily counts match raw SQL queries

Paginates a Discord channel to reimport voice join/left events from a
bot (Dyno). Includes rate limit handling, duplicate detection, and
progress display via Laravel Prompts.
Change now() to now()->utc() in PersistVoiceStateAction to ensure
gateway voice events use UTC, matching the ETL/Dyno source timestamps.
Convert from timestamp without timezone to timestamptz, treating
existing values as UTC. Enables correct timezone-aware queries.
After migrating to timestamptz, the double AT TIME ZONE cast caused a
+3h shift. Use single cast to America/Sao_Paulo since PostgreSQL now
handles the UTC→local conversion automatically.
Add BackfillVoiceLogsCommand to the module's service provider.
@danielhe4rt danielhe4rt force-pushed the chore/backfill-voice-logs branch from 7669616 to 6fe29dd Compare May 20, 2026 01:37
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

Warning

Rate limit exceeded

@danielhe4rt has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 26 minutes and 44 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Pro

Run ID: e36ef475-d5fe-46c4-9d8c-ebe792b2f632

📥 Commits

Reviewing files that changed from the base of the PR and between 49dcb37 and 17c0b54.

📒 Files selected for processing (7)
  • app-modules/bot-discord/src/Actions/VoiceChannel/PersistVoiceStateAction.php
  • app-modules/integration-discord/src/ETL/Console/BackfillVoiceLogsCommand.php
  • app-modules/integration-discord/src/IntegrationDiscordServiceProvider.php
  • app-modules/integration-discord/src/Transport/Requests/Messages/ListChannelMessages.php
  • app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/VoiceHeatmap.php
  • app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/VoicePerDay.php
  • database/migrations/2026_05_19_221434_alter_voice_messages_occurred_at_to_timestamptz.php

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@danielhe4rt danielhe4rt merged commit 5a45594 into 4.x May 20, 2026
6 checks passed
@danielhe4rt danielhe4rt deleted the chore/backfill-voice-logs branch May 20, 2026 01:41
danielhe4rt added a commit that referenced this pull request May 20, 2026
## Summary

- Adds `app.display_timezone` config key (`DISPLAY_TIMEZONE` env,
default `America/Sao_Paulo`) to centralize the user-facing timezone
- Changes `app.timezone` default from `America/Sao_Paulo` to `UTC`
- Replaces all 15 hardcoded `'America/Sao_Paulo'` occurrences across 15
files with `config('app.display_timezone')`
- Uses parameterized SQL bindings (`?`) for `AT TIME ZONE` clauses
instead of string interpolation
- Adds `AT TIME ZONE` conversion to moderation heatmap SQL that was
missing it entirely
- Converts all user-facing timestamp displays (SLA deadlines, connection
dates, schedule cards) to use the display timezone

## Modules affected

- `config/app.php` — new config key
- `bot-discord` — GreetingsEvent
- `he4rt` — heatmap highlight + schedule-card
- `panel-admin` — marketing dashboard queries (6 files) + moderation
heatmap + appeal views
- `integration-discord` — BackfillVoiceLogsCommand CLI output
- `routes/console.php` — backup:monitor schedule
- `resources/views` — connection-hub

## Test plan

- [x] Rector dry-run — no suggestions
- [x] Pint — passed
- [x] PHPStan — 0 errors
- [x] Tests — 497 passed, 3 skipped
- [x] Verified `AT TIME ZONE ?` binding works via tinker
- [ ] Verify heatmaps render correctly in the admin panel
- [ ] Verify SLA deadline times display in Brazil timezone
- [ ] Verify schedule-card shows correct local times

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Description
Centralizes the user-facing timezone by adding app.display_timezone (env
DISPLAY_TIMEZONE, default America/Sao_Paulo) and switching the
application default timezone to UTC. Replaces hard-coded
America/Sao_Paulo occurrences with config('app.display_timezone'),
parameterizes SQL AT TIME ZONE bindings, fixes a missing AT TIME ZONE in
the moderation heatmap, and converts user-facing timestamp displays to
the new display timezone.

## References
- PR: #262
- PR: #260
- PostgreSQL AT TIME ZONE docs:
https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-TIMEZONES

## Dependencies & Requirements
- New config key: app.display_timezone (env: DISPLAY_TIMEZONE, default:
America/Sao_Paulo)
- app.timezone default changed to UTC (env: APP_TIMEZONE)
- .env.example updated with APP_TIMEZONE=UTC and
DISPLAY_TIMEZONE=America/Sao_Paulo
- No new composer/npm packages added
- Database must accept parameterized AT TIME ZONE bindings (validated
via tinker)
- Manual verifications pending: admin heatmaps rendering, SLA deadline
display, schedule-card local times

## Contributor Summary
| Contributor | Lines Added | Lines Removed | Files Changed |
|---|---:|---:|---:|
| gvieira18 | 63 | 45 | 15 |

## Changes Summary
| File Path | Change Description |
|---|---|
| config/app.php | Added display_timezone key; changed default
app.timezone to UTC |
| .env.example | Added APP_TIMEZONE and DISPLAY_TIMEZONE entries |
| app-modules/bot-discord/src/Events/GreetingsEvent.php | Use
display_timezone for greeting-hour calculation |
|
app-modules/he4rt/resources/views/components/dashboard/heatmap.blade.php
| Heatmap current-time highlight uses display_timezone |
| app-modules/he4rt/resources/views/components/schedule-card.blade.php |
Normalize schedule timestamps to display_timezone |
|
app-modules/integration-discord/src/ETL/Console/BackfillVoiceLogsCommand.php
| Format CLI log timestamps with display_timezone |
|
app-modules/panel-admin/resources/views/moderation/appeal-queue/appeal-detail.blade.php
| SLA deadline displays converted to display_timezone with null fallback
|
|
app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/ActivityPerDay.php
| Use display_timezone and bind into SQL AT TIME ZONE |
|
app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/MessageHeatmap.php
| Parameterized timezone bindings for day/hour extraction |
|
app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/VoiceHeatmap.php
| Parameterized timezone bindings in voice heatmap query |
|
app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/VoicePerDay.php
| Day-extraction query updated to use display_timezone |
|
app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/PeriodStats.php
| Compute subdivisions using display_timezone |
|
app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/TopChannels.php
| Date range calculations use display_timezone |
| app-modules/panel-admin/src/Marketing/Pages/MeetingShowcasePage.php |
Parse meeting bounds with display_timezone and convert to UTC |
|
app-modules/panel-admin/src/Moderation/Livewire/ModerationDashboardLivewire.php
| Added AT TIME ZONE conversion and parameterized bindings for
moderation heatmap |
| resources/views/livewire/connection-hub.blade.php | "Connected at"
timestamp uses display_timezone; props formatting |
| routes/console.php | Schedule backup:monitor to run at 09:00 in
display_timezone |
|
database/migrations/2026_05_20_160249_alter_messages_sent_at_to_timestamptz.php
| Migration: convert messages.sent_at to timestamptz interpreting
existing values as UTC |

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/he4rt/heartdevs.com/pull/264?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: danielhe4rt <danielhe4rt@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants