feat(web): record service ping history and add usage report download#1348
Conversation
Record each service ping in a new ServicePingEvent table (activation code stripped) so offline deployments, which can't report usage to Lighthouse automatically, can download their usage history and email it to us. Adds a "Download usage report" button to the offline license settings card that exports the recorded pings as a JSON file. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
WalkthroughAdds a ChangesService Ping Event Recording and Download
Sequence Diagram(s)sequenceDiagram
rect rgba(173, 216, 230, 0.5)
note over syncWithLighthouse,servicePingEvent: Every ping cycle
syncWithLighthouse->>recordServicePingInDB: await recordServicePingInDB(orgId, payload)
recordServicePingInDB->>recordServicePingInDB: strip activationCode
recordServicePingInDB->>servicePingEvent: prisma.servicePingEvent.create()
servicePingEvent-->>recordServicePingInDB: saved (errors caught+logged)
recordServicePingInDB-->>syncWithLighthouse: returns
syncWithLighthouse->>LighthouseClient: ping(payload) or skip if offline
end
rect rgba(144, 238, 144, 0.5)
note over Owner,servicePingEvent: On-demand export
Owner->>DownloadServicePingHistoryButton: click "Download usage report"
DownloadServicePingHistoryButton->>getServicePingHistory: getServicePingHistory()
getServicePingHistory->>servicePingEvent: findMany(orgId, orderBy: createdAt asc)
servicePingEvent-->>getServicePingHistory: rows
getServicePingHistory-->>DownloadServicePingHistoryButton: ServicePingHistoryEntry[]
DownloadServicePingHistoryButton->>Owner: JSON blob download
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
packages/web/src/app/(app)/settings/license/actions.ts (1)
19-21: ⚖️ Poor tradeoffConsider pagination or limits for large datasets.
This query fetches all service ping events without pagination. For deployments running for years with daily pings, this could return thousands of records. While offline deployments may genuinely need all history, consider whether:
- A
take/skippagination strategy would be useful- A date range filter would help users export specific periods
- A reasonable upper limit (e.g., last 1000 events) should be enforced
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/web/src/app/`(app)/settings/license/actions.ts around lines 19 - 21, The query in the servicePingEvent.findMany() call fetches all records without any limit or pagination, which could cause performance issues with large datasets over time. Add a take parameter to limit the number of records returned (e.g., last 1000 events) as a reasonable upper bound, and optionally implement pagination with take and skip parameters or add a where clause with a date range filter to allow users to query specific time periods instead of always fetching the complete history.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@packages/db/prisma/migrations/20260618182127_add_service_ping_event_table/migration.sql`:
- Around line 1-8: In the migration file creating the ServicePingEvent table,
add a database index on the createdAt column to optimize the ordered queries
performed by the getServicePingHistory server action. The createdAt column is
used for sorting results in ascending order but currently lacks an index, which
will cause full table scans as the table grows. Add a CREATE INDEX statement
after the table creation to create an index on the createdAt column of the
ServicePingEvent table to ensure queries remain performant as data accumulates.
In `@packages/db/prisma/schema.prisma`:
- Around line 361-365: The ServicePingEvent model lacks an orgId field which
breaks multi-tenant isolation and allows any OWNER to access all organizations'
service ping events. Add an orgId field to the ServicePingEvent model in
schema.prisma as a String required field with a foreign key relation to the
Organization model. Then update the getServicePingHistory function in actions.ts
to filter ServicePingEvent records by the requesting organization's orgId
instead of fetching all records. Finally, update the recordServicePingInDB
function in servicePing.ts to capture and include the orgId when creating new
ServicePingEvent records.
In `@packages/web/src/app/`(app)/settings/license/actions.ts:
- Around line 19-21: The servicePingEvent.findMany() query is missing an orgId
filter, which creates a security vulnerability allowing cross-organization data
access. Add a where clause to the findMany call that filters servicePingEvent
records by orgId using role.orgId to ensure only the current organization's
service ping events are retrieved. This prevents any OWNER from accessing
service ping history from other organizations.
---
Nitpick comments:
In `@packages/web/src/app/`(app)/settings/license/actions.ts:
- Around line 19-21: The query in the servicePingEvent.findMany() call fetches
all records without any limit or pagination, which could cause performance
issues with large datasets over time. Add a take parameter to limit the number
of records returned (e.g., last 1000 events) as a reasonable upper bound, and
optionally implement pagination with take and skip parameters or add a where
clause with a date range filter to allow users to query specific time periods
instead of always fetching the complete history.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 29aa261b-7964-47ab-b600-895f44389483
📒 Files selected for processing (7)
CHANGELOG.mdpackages/db/prisma/migrations/20260618182127_add_service_ping_event_table/migration.sqlpackages/db/prisma/schema.prismapackages/web/src/app/(app)/settings/license/actions.tspackages/web/src/app/(app)/settings/license/downloadServicePingHistoryButton.tsxpackages/web/src/app/(app)/settings/license/offlineLicenseCard.tsxpackages/web/src/features/billing/servicePing.ts
Overview
Offline / air-gapped deployments can't report usage to Lighthouse automatically. This change records each service ping locally so those deployments can download their usage history and send it to us out-of-band.
Changes
ServicePingEventtable (id,payloadJSON,createdAt) + migration.syncWithLighthousenow persists each ping (viarecordServicePingInDB) before sending it to Lighthouse, so the history is captured even when the outbound ping fails (as it always will on air-gapped instances). The activation code is stripped before persisting, and recording is best-effort (wrapped in try/catch + logging) so a DB error never blocks the real ping.Settings → License), backed by anOWNER-gated server action that returns the recorded events. Downloads as<date>-usage-history.json.ar@sourcebot.dev.Notes
🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features
Refactor