-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Partners audit logs #2610
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Partners audit logs #2610
Conversation
- Introduced new `record-audit-log.ts` to handle recording of audit logs. - Created `schemas.ts` for defining audit log schemas using Zod. - Added `dub_audit_logs.datasource` for Tinybird integration. - Updated `create-id.ts` to include "audit_" prefix for generated IDs.
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
|
Warning Rate limit exceeded@steven-tey has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 11 minutes and 1 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the 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. 📒 Files selected for processing (1)
WalkthroughThis update introduces a comprehensive audit logging system across the application. It adds new backend APIs, data schemas, and UI components to record, fetch, and export audit logs. Audit log recording is integrated into numerous partner and commission actions, with corresponding Tinybird data pipelines and datasources. The workspace security dashboard is refactored to modularize SAML, SCIM, and audit log export functionality. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant WebApp
participant API
participant Tinybird
User->>WebApp: Clicks "Export Audit Logs"
WebApp->>API: POST /api/audit-logs/export {start, end}
API->>Tinybird: Fetch audit logs (get_audit_logs.pipe)
Tinybird-->>API: Returns audit log data
API-->>WebApp: Returns CSV file
WebApp-->>User: Triggers CSV download
sequenceDiagram
participant User
participant WebApp
participant API
participant Tinybird
User->>WebApp: Performs partner/commission action
WebApp->>API: Action request (e.g., approve, ban, update)
API->>Tinybird: recordAuditLog (ingest audit log)
Tinybird-->>API: Ingestion confirmation
API-->>WebApp: Action response
Suggested reviewers
Poem
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🧹 Nitpick comments (8)
apps/web/app/(ee)/api/audit-logs/export/route.ts (2)
22-27: Remove redundant validation.The schema already validates that
startandendare strings, so this additional check is unnecessary sinceauditLogExportQuerySchema.parse()would have already thrown an error for missing fields.- if (!start || !end) { - throw new DubApiError({ - code: "bad_request", - message: "Must provide start and end dates.", - }); - }
52-52: Add filename to Content-Disposition header.The CSV export should include a descriptive filename for better user experience.
- "Content-Disposition": `attachment;`, + "Content-Disposition": `attachment; filename="audit-logs-${start}-${end}.csv"`,apps/web/lib/api/audit-logs/record-audit-log.ts (1)
12-40: Consider data consistency improvements.The transformation function is well-structured but has some considerations:
Location extraction inconsistency: The function tries
ipAddress(data.req)first, then falls back togetIP(), but the logic might be inconsistent.Empty string defaults: Some fields default to empty strings instead of null, which might not match the Tinybird schema expectations.
Consider this improvement for better data consistency:
- location: location || "", - user_agent: userAgent || "", + location: location || null, + user_agent: userAgent || null,And ensure the Tinybird schema handles nulls appropriately.
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/audit-log.tsx (2)
23-25: Improve the workspace ID validation.The current check
if (!workspaceId) return;silently fails without user feedback. Consider providing user feedback or using a more robust validation approach.Apply this diff to provide better user feedback:
-if (!workspaceId) { - return; -} +if (!workspaceId) { + toast.error("Workspace not found"); + return; +}
60-62: Improve error handling specificity.The error handling could be more specific about the error type and provide better user feedback.
Apply this diff to improve error handling:
} catch (error) { - toast.error(error); + toast.error(error instanceof Error ? error.message : "Failed to export audit logs"); } finally {apps/web/lib/api/audit-logs/get-audit-logs.ts (2)
45-46: Document the date formatting logic.The date formatting logic that replaces "T" with space and removes "Z" appears to be specific to Tinybird's expected format. Consider adding a comment to explain this transformation.
Apply this diff to improve documentation:
+ // Convert ISO date to Tinybird format: "YYYY-MM-DD HH:mm:ss" start: start.toISOString().replace("T", " ").replace("Z", ""), end: end.toISOString().replace("T", " ").replace("Z", ""),
45-46: Consider extracting date formatting to a utility function.The date formatting logic could be reused elsewhere. Consider extracting it to a utility function for better maintainability.
Create a utility function:
const formatDateForTinybird = (date: Date): string => { return date.toISOString().replace("T", " ").replace("Z", ""); };Then use it in the function:
- start: start.toISOString().replace("T", " ").replace("Z", ""), - end: end.toISOString().replace("T", " ").replace("Z", ""), + start: formatDateForTinybird(start), + end: formatDateForTinybird(end),apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/saml.tsx (1)
94-126: Consider extracting popover menu logic.The popover implementation is correct but could be extracted into a separate component for better reusability, especially if similar action menus are used elsewhere in the security settings.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (42)
apps/web/app/(ee)/api/audit-logs/export/route.ts(1 hunks)apps/web/app/(ee)/api/commissions/[commissionId]/route.ts(2 hunks)apps/web/app/(ee)/api/cron/payouts/confirm/confirm-payouts.ts(3 hunks)apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/audit-log.tsx(1 hunks)apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/page-client.tsx(1 hunks)apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/saml.tsx(1 hunks)apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/scim.tsx(1 hunks)apps/web/lib/actions/partners/approve-partners-bulk.ts(2 hunks)apps/web/lib/actions/partners/archive-partner.ts(3 hunks)apps/web/lib/actions/partners/ban-partner.ts(4 hunks)apps/web/lib/actions/partners/create-clawback.ts(2 hunks)apps/web/lib/actions/partners/create-commission.ts(4 hunks)apps/web/lib/actions/partners/create-discount.ts(3 hunks)apps/web/lib/actions/partners/create-program.ts(2 hunks)apps/web/lib/actions/partners/create-reward.ts(2 hunks)apps/web/lib/actions/partners/delete-discount.ts(4 hunks)apps/web/lib/actions/partners/delete-program-invite.ts(3 hunks)apps/web/lib/actions/partners/delete-reward.ts(3 hunks)apps/web/lib/actions/partners/invite-partner.ts(3 hunks)apps/web/lib/actions/partners/mark-commission-duplicate.ts(3 hunks)apps/web/lib/actions/partners/mark-commission-fraud-or-canceled.ts(3 hunks)apps/web/lib/actions/partners/mark-payout-paid.ts(4 hunks)apps/web/lib/actions/partners/reject-partner.ts(3 hunks)apps/web/lib/actions/partners/reject-partners-bulk.ts(3 hunks)apps/web/lib/actions/partners/resend-program-invite.ts(4 hunks)apps/web/lib/actions/partners/unban-partner.ts(3 hunks)apps/web/lib/actions/partners/update-auto-approve-partners.ts(2 hunks)apps/web/lib/actions/partners/update-discount.ts(3 hunks)apps/web/lib/actions/partners/update-program.ts(4 hunks)apps/web/lib/actions/partners/update-reward.ts(3 hunks)apps/web/lib/api/audit-logs/get-audit-logs.ts(1 hunks)apps/web/lib/api/audit-logs/record-audit-log.ts(1 hunks)apps/web/lib/api/audit-logs/schemas.ts(1 hunks)apps/web/lib/api/create-id.ts(1 hunks)apps/web/lib/api/programs/get-program-enrollment-or-throw.ts(2 hunks)apps/web/lib/partners/approve-partner-enrollment.ts(3 hunks)apps/web/lib/partners/bulk-approve-partners.ts(4 hunks)apps/web/lib/partners/create-partner-commission.ts(4 hunks)apps/web/lib/plan-capabilities.ts(1 hunks)apps/web/ui/shared/simple-date-range-picker.tsx(2 hunks)packages/tinybird/datasources/dub_audit_logs.datasource(1 hunks)packages/tinybird/pipes/audit_logs.pipe(1 hunks)
🧰 Additional context used
🧠 Learnings (18)
apps/web/lib/actions/partners/approve-partners-bulk.ts (2)
Learnt from: devkiran
PR: dubinc/dub#2177
File: apps/web/lib/api/links/bulk-create-links.ts:66-84
Timestamp: 2025-06-06T07:59:03.120Z
Learning: In apps/web/lib/api/links/bulk-create-links.ts, the team accepts the risk of potential undefined results from links.find() operations when building invalidLinks arrays, because existing links are fetched from the database based on the input links, so matches are expected to always exist.
Learnt from: devkiran
PR: dubinc/dub#2510
File: apps/web/lib/actions/partners/onboard-program.ts:16-19
Timestamp: 2025-06-10T19:16:23.445Z
Learning: Business rule: Each workspace may have at most one program; attempting to create more must be blocked in code.
apps/web/lib/actions/partners/create-clawback.ts (1)
Learnt from: TWilson023
PR: dubinc/dub#2538
File: apps/web/ui/partners/overview/blocks/commissions-block.tsx:16-27
Timestamp: 2025-06-18T20:26:25.177Z
Learning: In the Dub codebase, components that use workspace data (workspaceId, defaultProgramId) are wrapped in `WorkspaceAuth` which ensures these values are always available, making non-null assertions safe. This is acknowledged as a common pattern in their codebase, though not ideal.
apps/web/lib/actions/partners/delete-program-invite.ts (1)
Learnt from: devkiran
PR: dubinc/dub#2177
File: apps/web/lib/api/links/bulk-create-links.ts:66-84
Timestamp: 2025-06-06T07:59:03.120Z
Learning: In apps/web/lib/api/links/bulk-create-links.ts, the team accepts the risk of potential undefined results from links.find() operations when building invalidLinks arrays, because existing links are fetched from the database based on the input links, so matches are expected to always exist.
apps/web/lib/actions/partners/reject-partners-bulk.ts (2)
Learnt from: devkiran
PR: dubinc/dub#2177
File: apps/web/lib/api/links/bulk-create-links.ts:66-84
Timestamp: 2025-06-06T07:59:03.120Z
Learning: In apps/web/lib/api/links/bulk-create-links.ts, the team accepts the risk of potential undefined results from links.find() operations when building invalidLinks arrays, because existing links are fetched from the database based on the input links, so matches are expected to always exist.
Learnt from: TWilson023
PR: dubinc/dub#2538
File: apps/web/ui/partners/overview/blocks/commissions-block.tsx:16-27
Timestamp: 2025-06-18T20:26:25.177Z
Learning: In the Dub codebase, components that use workspace data (workspaceId, defaultProgramId) are wrapped in `WorkspaceAuth` which ensures these values are always available, making non-null assertions safe. This is acknowledged as a common pattern in their codebase, though not ideal.
apps/web/lib/actions/partners/create-discount.ts (1)
Learnt from: devkiran
PR: dubinc/dub#2177
File: apps/web/lib/api/links/bulk-create-links.ts:66-84
Timestamp: 2025-06-06T07:59:03.120Z
Learning: In apps/web/lib/api/links/bulk-create-links.ts, the team accepts the risk of potential undefined results from links.find() operations when building invalidLinks arrays, because existing links are fetched from the database based on the input links, so matches are expected to always exist.
apps/web/lib/actions/partners/create-program.ts (1)
Learnt from: devkiran
PR: dubinc/dub#2510
File: apps/web/lib/actions/partners/onboard-program.ts:16-19
Timestamp: 2025-06-10T19:16:23.445Z
Learning: Business rule: Each workspace may have at most one program; attempting to create more must be blocked in code.
apps/web/lib/actions/partners/mark-commission-duplicate.ts (1)
Learnt from: TWilson023
PR: dubinc/dub#2538
File: apps/web/ui/partners/overview/blocks/commissions-block.tsx:16-27
Timestamp: 2025-06-18T20:26:25.177Z
Learning: In the Dub codebase, components that use workspace data (workspaceId, defaultProgramId) are wrapped in `WorkspaceAuth` which ensures these values are always available, making non-null assertions safe. This is acknowledged as a common pattern in their codebase, though not ideal.
apps/web/lib/actions/partners/reject-partner.ts (1)
Learnt from: TWilson023
PR: dubinc/dub#2538
File: apps/web/ui/partners/overview/blocks/commissions-block.tsx:16-27
Timestamp: 2025-06-18T20:26:25.177Z
Learning: In the Dub codebase, components that use workspace data (workspaceId, defaultProgramId) are wrapped in `WorkspaceAuth` which ensures these values are always available, making non-null assertions safe. This is acknowledged as a common pattern in their codebase, though not ideal.
apps/web/lib/partners/approve-partner-enrollment.ts (1)
Learnt from: devkiran
PR: dubinc/dub#2177
File: apps/web/lib/api/links/bulk-create-links.ts:66-84
Timestamp: 2025-06-06T07:59:03.120Z
Learning: In apps/web/lib/api/links/bulk-create-links.ts, the team accepts the risk of potential undefined results from links.find() operations when building invalidLinks arrays, because existing links are fetched from the database based on the input links, so matches are expected to always exist.
apps/web/app/(ee)/api/cron/payouts/confirm/confirm-payouts.ts (2)
Learnt from: steven-tey
PR: dubinc/dub#0
File: :0-0
Timestamp: 2025-06-25T21:20:59.837Z
Learning: In the Dub codebase, payout limit validation uses a two-stage pattern: server actions perform quick sanity checks (payoutsUsage > payoutsLimit) for immediate user feedback, while the cron job (/cron/payouts) performs authoritative validation (payoutsUsage + payoutAmount > payoutsLimit) with actual calculated amounts before processing. This design provides fast user feedback while ensuring accurate limit enforcement at transaction time.
Learnt from: steven-tey
PR: dubinc/dub#0
File: :0-0
Timestamp: 2025-06-19T01:46:45.723Z
Learning: PayPal webhook verification in the Dub codebase is handled at the route level in `apps/web/app/(ee)/api/paypal/webhook/route.ts` using the `verifySignature` function. Individual webhook handlers like `payoutsItemFailed` don't need to re-verify signatures since they're only called after successful verification.
apps/web/lib/actions/partners/update-program.ts (2)
Learnt from: TWilson023
PR: dubinc/dub#2538
File: apps/web/ui/partners/overview/blocks/commissions-block.tsx:16-27
Timestamp: 2025-06-18T20:26:25.177Z
Learning: In the Dub codebase, components that use workspace data (workspaceId, defaultProgramId) are wrapped in `WorkspaceAuth` which ensures these values are always available, making non-null assertions safe. This is acknowledged as a common pattern in their codebase, though not ideal.
Learnt from: devkiran
PR: dubinc/dub#2510
File: apps/web/lib/actions/partners/onboard-program.ts:16-19
Timestamp: 2025-06-10T19:16:23.445Z
Learning: Business rule: Each workspace may have at most one program; attempting to create more must be blocked in code.
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/audit-log.tsx (1)
Learnt from: TWilson023
PR: dubinc/dub#2538
File: apps/web/ui/partners/overview/blocks/commissions-block.tsx:16-27
Timestamp: 2025-06-18T20:26:25.177Z
Learning: In the Dub codebase, components that use workspace data (workspaceId, defaultProgramId) are wrapped in `WorkspaceAuth` which ensures these values are always available, making non-null assertions safe. This is acknowledged as a common pattern in their codebase, though not ideal.
apps/web/lib/api/programs/get-program-enrollment-or-throw.ts (1)
Learnt from: devkiran
PR: dubinc/dub#2448
File: packages/email/src/templates/partner-program-summary.tsx:0-0
Timestamp: 2025-05-29T04:45:18.504Z
Learning: In the PartnerProgramSummary email template (packages/email/src/templates/partner-program-summary.tsx), the stat titles are hardcoded constants ("Clicks", "Leads", "Sales", "Earnings") that will always match the ICONS object keys after toLowerCase() conversion, so icon lookup failures are not possible.
apps/web/lib/actions/partners/unban-partner.ts (1)
Learnt from: devkiran
PR: dubinc/dub#2177
File: apps/web/lib/api/links/bulk-create-links.ts:66-84
Timestamp: 2025-06-06T07:59:03.120Z
Learning: In apps/web/lib/api/links/bulk-create-links.ts, the team accepts the risk of potential undefined results from links.find() operations when building invalidLinks arrays, because existing links are fetched from the database based on the input links, so matches are expected to always exist.
apps/web/lib/partners/bulk-approve-partners.ts (1)
Learnt from: devkiran
PR: dubinc/dub#2177
File: apps/web/lib/api/links/bulk-create-links.ts:66-84
Timestamp: 2025-06-06T07:59:03.120Z
Learning: In apps/web/lib/api/links/bulk-create-links.ts, the team accepts the risk of potential undefined results from links.find() operations when building invalidLinks arrays, because existing links are fetched from the database based on the input links, so matches are expected to always exist.
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/page-client.tsx (1)
Learnt from: TWilson023
PR: dubinc/dub#2538
File: apps/web/ui/partners/overview/blocks/commissions-block.tsx:16-27
Timestamp: 2025-06-18T20:26:25.177Z
Learning: In the Dub codebase, components that use workspace data (workspaceId, defaultProgramId) are wrapped in `WorkspaceAuth` which ensures these values are always available, making non-null assertions safe. This is acknowledged as a common pattern in their codebase, though not ideal.
apps/web/lib/actions/partners/ban-partner.ts (1)
Learnt from: devkiran
PR: dubinc/dub#2177
File: apps/web/lib/api/links/bulk-create-links.ts:66-84
Timestamp: 2025-06-06T07:59:03.120Z
Learning: In apps/web/lib/api/links/bulk-create-links.ts, the team accepts the risk of potential undefined results from links.find() operations when building invalidLinks arrays, because existing links are fetched from the database based on the input links, so matches are expected to always exist.
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/saml.tsx (1)
Learnt from: TWilson023
PR: dubinc/dub#2538
File: apps/web/ui/partners/overview/blocks/commissions-block.tsx:16-27
Timestamp: 2025-06-18T20:26:25.177Z
Learning: In the Dub codebase, components that use workspace data (workspaceId, defaultProgramId) are wrapped in `WorkspaceAuth` which ensures these values are always available, making non-null assertions safe. This is acknowledged as a common pattern in their codebase, though not ideal.
🧬 Code Graph Analysis (18)
apps/web/lib/actions/partners/delete-program-invite.ts (1)
apps/web/lib/api/audit-logs/record-audit-log.ts (1)
recordAuditLog(42-62)
apps/web/lib/actions/partners/delete-reward.ts (1)
apps/web/lib/api/audit-logs/record-audit-log.ts (1)
recordAuditLog(42-62)
apps/web/lib/actions/partners/resend-program-invite.ts (1)
apps/web/lib/api/audit-logs/record-audit-log.ts (1)
recordAuditLog(42-62)
apps/web/lib/actions/partners/create-discount.ts (1)
apps/web/lib/api/audit-logs/record-audit-log.ts (1)
recordAuditLog(42-62)
apps/web/lib/actions/partners/delete-discount.ts (1)
apps/web/lib/api/audit-logs/record-audit-log.ts (1)
recordAuditLog(42-62)
apps/web/lib/actions/partners/create-program.ts (1)
apps/web/lib/api/audit-logs/record-audit-log.ts (1)
recordAuditLog(42-62)
apps/web/lib/partners/approve-partner-enrollment.ts (1)
apps/web/lib/api/audit-logs/record-audit-log.ts (1)
recordAuditLog(42-62)
apps/web/app/(ee)/api/cron/payouts/confirm/confirm-payouts.ts (1)
apps/web/lib/api/audit-logs/record-audit-log.ts (1)
recordAuditLog(42-62)
apps/web/lib/api/audit-logs/record-audit-log.ts (3)
apps/web/lib/api/audit-logs/schemas.ts (2)
recordAuditLogInputSchema(170-185)auditLogSchemaTB(10-24)apps/web/lib/api/create-id.ts (1)
createId(55-64)packages/utils/src/functions/log.ts (1)
log(9-45)
apps/web/lib/actions/partners/update-program.ts (1)
apps/web/lib/api/audit-logs/record-audit-log.ts (1)
recordAuditLog(42-62)
apps/web/lib/actions/partners/mark-commission-fraud-or-canceled.ts (2)
apps/web/lib/api/partners/sync-total-commissions.ts (1)
syncTotalCommissions(4-35)apps/web/lib/api/audit-logs/record-audit-log.ts (1)
recordAuditLog(42-62)
apps/web/lib/actions/partners/archive-partner.ts (3)
apps/web/lib/actions/safe-action.ts (1)
authActionClient(33-82)apps/web/lib/zod/schemas/partners.ts (1)
archivePartnerSchema(574-577)apps/web/lib/api/audit-logs/record-audit-log.ts (1)
recordAuditLog(42-62)
apps/web/lib/actions/partners/mark-payout-paid.ts (1)
apps/web/lib/api/audit-logs/record-audit-log.ts (1)
recordAuditLog(42-62)
apps/web/lib/partners/create-partner-commission.ts (5)
apps/web/lib/types.ts (1)
RewardProps(472-472)packages/prisma/client.ts (1)
CommissionType(5-5)apps/web/lib/auth/utils.ts (1)
Session(6-16)apps/web/lib/api/partners/sync-total-commissions.ts (1)
syncTotalCommissions(4-35)apps/web/lib/api/audit-logs/record-audit-log.ts (1)
recordAuditLog(42-62)
apps/web/lib/actions/partners/update-discount.ts (1)
apps/web/lib/api/audit-logs/record-audit-log.ts (1)
recordAuditLog(42-62)
apps/web/lib/actions/partners/unban-partner.ts (4)
apps/web/lib/api/programs/get-default-program-id-or-throw.ts (1)
getDefaultProgramIdOrThrow(4-17)apps/web/lib/api/programs/get-program-enrollment-or-throw.ts (1)
getProgramEnrollmentOrThrow(6-85)apps/web/lib/api/links/cache.ts (1)
linkCache(102-102)apps/web/lib/api/audit-logs/record-audit-log.ts (1)
recordAuditLog(42-62)
apps/web/lib/actions/partners/ban-partner.ts (6)
apps/web/lib/api/programs/get-default-program-id-or-throw.ts (1)
getDefaultProgramIdOrThrow(4-17)apps/web/lib/api/programs/get-program-enrollment-or-throw.ts (1)
getProgramEnrollmentOrThrow(6-85)packages/email/src/index.ts (1)
sendEmail(6-29)packages/email/src/templates/partner-banned.tsx (1)
PartnerBanned(17-84)apps/web/lib/zod/schemas/partners.ts (1)
BAN_PARTNER_REASONS(38-45)apps/web/lib/api/audit-logs/record-audit-log.ts (1)
recordAuditLog(42-62)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/saml.tsx (2)
packages/ui/src/icons/nucleo/lock.tsx (1)
Lock(3-48)packages/ui/src/tooltip.tsx (1)
TooltipContent(90-128)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: build
🔇 Additional comments (61)
apps/web/lib/actions/partners/approve-partners-bulk.ts (1)
49-49: LGTM! User context properly passed for audit logging.The change from
userId: user.idtousercorrectly passes the entire user object to support audit logging functionality in thebulkApprovePartnersfunction.apps/web/ui/shared/simple-date-range-picker.tsx (1)
8-8: LGTM! Proper disabled prop implementation.The
disabledprop is correctly added with proper TypeScript typing and forwarded to the underlyingDateRangePickercomponent. This supports the audit log export feature gating.Also applies to: 13-13, 74-74
apps/web/lib/api/create-id.ts (1)
29-29: LGTM! Audit prefix properly added.The
"audit_"prefix is correctly added to support audit log ID generation, following the established naming pattern.apps/web/lib/plan-capabilities.ts (1)
13-13: LGTM! Enterprise-only audit log export capability correctly implemented.The
canExportAuditLogsflag properly restricts audit log export functionality to enterprise plans only, following the established pattern for other capability flags.apps/web/lib/actions/partners/create-commission.ts (2)
22-22: LGTM! User context properly extracted for audit logging.The user is correctly extracted from the context to support audit logging in commission creation.
63-65: LGTM! Consistent audit logging parameters across all commission types.The
userandworkspaceIdparameters are consistently added to all three commission creation calls (custom, lead, and sale), ensuring proper audit logging coverage across all commission types.Also applies to: 184-186, 220-222
apps/web/lib/actions/partners/create-clawback.ts (1)
12-12: LGTM! Clean integration of audit logging context.The extraction of
userfrom context and passing it tocreatePartnerCommissionalong withworkspaceIdfollows the established pattern for enabling audit logging in partner actions.Also applies to: 29-30
apps/web/lib/actions/partners/delete-program-invite.ts (1)
3-3: LGTM! Comprehensive audit logging implementation.The audit log integration is well-implemented with proper error isolation using
Promise.allSettledand includes all necessary context (workspace, program, actor, target with metadata). The action type"partner.invite_deleted"is descriptive and follows the established naming convention.Also applies to: 19-19, 60-73
packages/tinybird/datasources/dub_audit_logs.datasource (1)
1-19: LGTM! Well-designed audit log schema.The datasource schema demonstrates excellent design choices:
LowCardinalityforactionandactor_typefields optimizes storage for frequently repeated values- Partitioning by
toYYYYMM(timestamp)provides efficient time-based data management- Sorting key
workspace_id, program_id, timestampenables fast queries by workspace and program- 1-year TTL is appropriate for audit log retention policies
- JSON path extraction allows flexible data ingestion
apps/web/lib/actions/partners/create-reward.ts (1)
3-3: LGTM! Proper audit logging implementation.The audit log integration follows the established pattern correctly:
- Uses
waitUntilappropriately for the async audit log operation- Includes comprehensive audit context (workspace, program, actor, target with metadata)
- Action type
"reward.created"is descriptive and consistent with naming conventionsAlso applies to: 11-11, 17-17, 114-131
apps/web/lib/actions/partners/create-program.ts (1)
1-1: LGTM! Clean integration into existing async operations.The audit log recording is properly integrated into the existing
Promise.allSettledcall, maintaining consistency with other post-creation operations. The audit log structure appropriately captures the program creation event with comprehensive metadata.Also applies to: 200-213
apps/web/lib/actions/partners/delete-reward.ts (1)
3-3: LGTM - Audit logging implementation follows best practices.The audit logging implementation is well-structured:
- Uses asynchronous logging with
waitUntilto avoid blocking the main action- Captures relevant metadata from the fetched reward before deletion
- Follows consistent pattern with other audit logging implementations
Also applies to: 8-8, 20-20, 66-83
apps/web/lib/actions/partners/reject-partner.ts (1)
3-3: LGTM - Proper inclusion of partner data for audit logging.The changes correctly:
- Include the partner relation in the query to access partner metadata for audit logging
- Follow the established async audit logging pattern with
waitUntil- Use appropriate action type and descriptive message
Also applies to: 7-7, 14-14, 26-28, 44-61
apps/web/lib/actions/partners/update-reward.ts (1)
3-3: LGTM - Audit logging correctly captures reward update.The implementation properly:
- Uses the
updatedRewardfrom the Prisma update operation for metadata- Places audit logging after all business logic completion
- Follows the established async pattern with
waitUntilAlso applies to: 12-12, 18-18, 85-102
apps/web/app/(ee)/api/cron/payouts/confirm/confirm-payouts.ts (1)
273-307: LGTM - Good practice to refetch payouts before audit logging.The refetch to confirm payouts are in "processing" state before logging is a good practice that ensures data consistency for the audit trail.
apps/web/lib/actions/partners/reject-partners-bulk.ts (1)
3-3: LGTM - Proper bulk audit logging implementation.The implementation correctly:
- Includes the partner relation in the query for audit log metadata
- Maps over program enrollments to create individual audit log entries for each rejection
- Uses the established async audit logging pattern with
waitUntil- Maintains consistency with the single partner rejection action
Also applies to: 8-8, 15-15, 30-30, 49-68
apps/web/lib/actions/partners/invite-partner.ts (2)
96-96: Good practice: Capturing the enrolled partner result.Properly capturing the
enrolledPartnerresult for use in the audit log metadata ensures consistent tracking of partner enrollment actions.
110-142: Excellent implementation of concurrent async operations.The use of
Promise.allSettledto run email sending and audit logging concurrently is a good pattern that ensures neither operation blocks the other, while maintaining proper error isolation.packages/tinybird/pipes/audit_logs.pipe (1)
5-26: Well-structured audit log query with proper filtering.The query structure effectively retrieves audit log data with conditional filtering support for date ranges, workspace, and program scope. The descending timestamp ordering ensures most recent logs appear first.
apps/web/lib/actions/partners/mark-payout-paid.ts (2)
19-19: Proper context extraction for audit logging.Adding
userto the context extraction enables proper actor tracking in the audit log.
50-67: Consistent audit logging implementation.The audit log recording follows the established pattern of using
waitUntilfor async execution without blocking the main action flow. The payout metadata is properly captured in the audit log.apps/web/lib/partners/approve-partner-enrollment.ts (2)
122-130: Appropriate user fetching for audit logging.Using
findUniqueOrThrowensures the actor information is available for audit logging, properly handling cases where the user might not exist.
169-182: Well-integrated audit logging with existing operations.The audit log recording is properly integrated into the existing
Promise.allSettledalongside email and webhook operations, maintaining consistent async execution patterns.apps/web/lib/actions/partners/create-discount.ts (2)
17-17: Proper context extraction for audit logging.Adding
userto the context extraction enables proper actor tracking in the audit log.
100-129: Consistent concurrent operation pattern.The implementation properly uses
Promise.allSettledto execute cache invalidation and audit logging concurrently, following the established pattern seen in other audit logging integrations.apps/web/lib/actions/partners/resend-program-invite.ts (1)
52-89: LGTM! Good use of Promise.allSettled for resilient concurrent operations.The switch from
Promise.alltoPromise.allSettledensures all operations are attempted even if one fails, which is appropriate for this use case. The audit log entry is comprehensive with proper metadata including workspace, program, action type, and target information.apps/web/lib/actions/partners/delete-discount.ts (1)
102-129: LGTM! Proper audit logging implementation.The audit log correctly captures the discount data before deletion and uses
Promise.allSettledto ensure both the cache invalidation and audit logging are attempted even if one fails.apps/web/lib/actions/partners/update-program.ts (1)
134-147: LGTM! Clean integration of audit logging.The audit log properly captures the updated program state and is well-integrated into the existing async operations pattern. Using the
updatedProgramdata for the audit log metadata is appropriate for tracking the final state after the update.apps/web/lib/actions/partners/mark-commission-duplicate.ts (1)
77-99: LGTM! Consistent audit logging pattern.The audit log correctly captures the commission data before any modifications and uses
Promise.allSettledto ensure both the commission sync and audit logging are attempted even if one fails. The implementation follows the established pattern across the codebase.apps/web/lib/actions/partners/mark-commission-fraud-or-canceled.ts (3)
3-3: LGTM: Clean audit log import added.The import follows the established pattern used across other files in this PR.
21-21: LGTM: User extracted from context for audit logging.This change aligns with the audit logging requirements to capture the acting user information.
116-141: LGTM: Excellent concurrent execution pattern with audit logging.The implementation correctly:
- Uses
Promise.allSettledfor concurrent execution of commission sync and audit logging- Conditionally sets action type based on status (
commission.marked_fraudvscommission.canceled)- Includes comprehensive audit metadata (commission ID, actor, targets with full commission data)
- Maintains error isolation between operations
apps/web/lib/actions/partners/update-auto-approve-partners.ts (4)
3-3: LGTM: Necessary imports added for audit logging.The imports follow the established pattern used across other files in this PR.
Also applies to: 6-6
18-18: LGTM: User extracted from context for audit logging.This change aligns with the audit logging requirements to capture the acting user information.
23-31: LGTM: Program object returned for better API response.Returning the updated program object provides better response data for API consumers.
32-47: LGTM: Well-structured audit logging implementation.The audit log implementation correctly:
- Uses conditional action types (
auto_approve_partner.enabledvsauto_approve_partner.disabled)- Provides clear, user-friendly descriptions
- Includes necessary context (workspace, program, actor)
- Executes asynchronously to avoid blocking the main flow
apps/web/lib/actions/partners/archive-partner.ts (4)
3-3: LGTM: Necessary imports added for audit logging.The imports follow the established pattern used across other files in this PR.
Also applies to: 8-8
15-15: LGTM: User extracted from context for audit logging.This change aligns with the audit logging requirements to capture the acting user information.
25-39: LGTM: Enhanced query to support audit logging.The query modification correctly:
- Includes partner data needed for audit log metadata
- Returns the status for conditional audit log action
- Maintains the original toggle logic
41-59: LGTM: Proper audit logging with conditional actions.The audit log implementation correctly:
- Uses conditional action types (
partner.archivedvspartner.approved)- Includes partner metadata in targets for comprehensive audit trail
- Executes asynchronously to avoid blocking the main flow
- Follows the established pattern
apps/web/lib/partners/bulk-approve-partners.ts (4)
9-9: LGTM: Necessary imports added for audit logging and type definitions.The imports follow the established pattern and provide necessary type definitions for the signature change.
Also applies to: 12-12
22-22: LGTM: Function signature enhanced with full user object.The change from
userId: stringtouser: Session["user"]provides richer context for audit logging. This breaking change should be coordinated with all callers.Also applies to: 27-27
66-66: LGTM: Consistent use of user.id for partner link generation.The change maintains compatibility with the existing
generatePartnerLinkfunction while using the new user object structure.
121-136: LGTM: Efficient bulk audit logging implementation.The audit log implementation correctly:
- Records individual audit logs for each approved partner
- Uses array input to
recordAuditLogfor efficient batch processing- Includes comprehensive partner metadata in targets
- Follows the established pattern with descriptive action type
apps/web/lib/api/audit-logs/record-audit-log.ts (4)
1-8: LGTM: Well-structured imports for audit logging infrastructure.The imports cover all necessary utilities for data transformation, validation, and ingestion.
10-10: LGTM: Clean type definition from schema.Using
z.inferensures type safety and consistency with the validation schema.
42-62: LGTM: Robust error handling with logging.The function correctly:
- Handles both single and array inputs
- Includes comprehensive error logging
- Uses Slack notifications for error alerts
- Avoids throwing errors to prevent breaking main flows
64-68: LGTM: Proper Tinybird endpoint configuration.The configuration correctly specifies the datasource, event schema, and wait parameter for reliable ingestion.
apps/web/lib/partners/create-partner-commission.ts (2)
18-52: Function signature update looks good.The addition of optional
workspaceIdanduserparameters maintains backward compatibility while enabling audit logging functionality. The parameter types are correctly defined.
191-222: Audit logging implementation is well-structured.The conditional audit logging based on
userandworkspaceIdavailability is appropriate. TheisClawbacklogic correctly identifies negative earnings, and the use ofPromise.allSettledensures both operations execute independently without blocking each other.apps/web/lib/actions/partners/unban-partner.ts (2)
28-28: Good addition of includePartner parameter.Adding
includePartner: trueis necessary to fetch partner metadata for the audit log, ensuring the audit entry has complete information about the partner being unbanned.
90-108: Audit logging implementation follows established pattern.The audit logging implementation is consistent with other partner actions in the codebase. Using
Promise.allSettledensures both cache invalidation and audit logging are attempted independently.apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/page-client.tsx (1)
1-15: Excellent refactor for better maintainability.The modularization of the security settings page into separate
SAML,SCIM, andAuditLogcomponents greatly improves code organization and maintainability. This follows React best practices for component composition.apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/scim.tsx (1)
13-167: Well-structured component with proper feature gating.The component follows React best practices with proper state management, conditional rendering, and accessibility considerations. The enterprise plan gating for SCIM configuration is correctly implemented.
apps/web/lib/actions/partners/update-discount.ts (1)
123-150: Consistent audit logging implementation.The audit logging implementation follows the established pattern throughout the codebase. The use of
Promise.allSettledappropriately handles both cache invalidation and audit logging as independent operations.apps/web/lib/api/programs/get-program-enrollment-or-throw.ts (1)
10-10: LGTM! Clean implementation following existing patterns.The addition of the
includePartnerparameter follows the same pattern asincludeRewards, maintaining consistency in the codebase. This change efficiently supports the audit logging requirements by allowing partner data to be fetched in a single query.Also applies to: 15-15, 29-32
apps/web/lib/actions/partners/ban-partner.ts (1)
3-3: LGTM! Well-implemented audit logging with good practices.The audit logging implementation demonstrates several good practices:
- Optimizes database queries by using
includePartner: trueinstead of separate partner fetch- Uses
Promise.allSettledfor concurrent operations to prevent blocking- Includes comprehensive metadata in audit logs (actor, targets, action type)
- Maintains existing error handling and transaction logic
The change integrates seamlessly with the existing ban functionality while adding the required audit trail.
Also applies to: 22-22, 30-30, 84-84, 104-137
apps/web/app/(ee)/api/commissions/[commissionId]/route.ts (1)
2-2: LGTM! Well-integrated audit logging implementation.The audit logging implementation is well-integrated and follows established patterns:
- Properly adds session context to access user information for audit logs
- Uses
Promise.allSettledfor concurrent operations to prevent blocking- Includes comprehensive audit metadata with actor and updated commission data
- Maintains existing error handling and transaction logic
The changes seamlessly add audit trail functionality without disrupting the existing commission update flow.
Also applies to: 19-20, 155-179
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/saml.tsx (1)
128-143: LGTM - Proper enterprise plan gating implementation.The button correctly implements plan-based feature gating with appropriate tooltip for non-enterprise users, following the pattern established in the codebase.
apps/web/lib/api/audit-logs/schemas.ts (2)
10-24: LGTM - Well-structured Tinybird schema.The schema correctly uses snake_case naming convention for database storage and includes all necessary fields for audit log tracking.
184-184: No changes needed:Requestis available in the browser and Next.js runtimes
The globalRequestconstructor is provided in all target environments—browsers, Node.js 18+ (used by Next.js), and the Next.js Edge runtime. Thez.instanceof(Request).nullish()check will work as expected.
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/scim.tsx
Show resolved
Hide resolved
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/audit-log.tsx
Show resolved
Hide resolved
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/saml.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🧹 Nitpick comments (2)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/audit-logs.tsx (2)
17-19: Remove unnecessary workspaceId check.Based on the retrieved learning, components that use workspace data are wrapped in
WorkspaceAuthwhich ensuresworkspaceIdis always available, making this guard clause unnecessary.- const exportAuditLogs = async () => { - if (!workspaceId) { - return; - } - + const exportAuditLogs = async () => {
115-120: Handle undefined slug gracefully.The upgrade button logic assumes
slugmight be undefined but doesn't handle the case where it could be an empty string or other falsy values consistently.onClick={() => window.open( - slug ? `/${slug}/upgrade` : "https://dub.co/enterprise", + slug && slug.trim() ? `/${slug}/upgrade` : "https://dub.co/enterprise", "_blank", ) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/audit-logs.tsx(1 hunks)apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/page-client.tsx(1 hunks)
🧰 Additional context used
🧠 Learnings (1)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/page-client.tsx (1)
Learnt from: TWilson023
PR: dubinc/dub#2538
File: apps/web/ui/partners/overview/blocks/commissions-block.tsx:16-27
Timestamp: 2025-06-18T20:26:25.177Z
Learning: In the Dub codebase, components that use workspace data (workspaceId, defaultProgramId) are wrapped in `WorkspaceAuth` which ensures these values are always available, making non-null assertions safe. This is acknowledged as a common pattern in their codebase, though not ideal.
🧬 Code Graph Analysis (1)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/audit-logs.tsx (3)
apps/web/lib/plan-capabilities.ts (1)
getPlanCapabilities(4-15)apps/web/ui/shared/simple-date-range-picker.tsx (1)
SimpleDateRangePicker(4-77)packages/ui/src/tooltip.tsx (1)
TooltipContent(90-128)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: build
🔇 Additional comments (5)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/page-client.tsx (2)
3-5: LGTM: Clean refactoring with proper component separation.The extraction of SAML, SCIM, and AuditLogs components into separate modules improves maintainability and follows good separation of concerns principles.
10-12: LGTM: Simple and clean component composition.The component now serves as a clean container for the three security feature components.
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/audit-logs.tsx (3)
72-77: LGTM: Proper date picker integration with plan gating.The date picker is correctly disabled when the user doesn't have export permissions, maintaining a consistent UI experience.
83-96: LGTM: Excellent plan-based gating with informative tooltip.The export button properly implements plan restrictions with a clear tooltip that guides users to the enterprise plan upgrade.
100-123: LGTM: Clear upgrade prompt for non-enterprise users.The footer section provides a clear call-to-action for users who need to upgrade to access audit log export functionality.
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/audit-logs.tsx
Show resolved
Hide resolved
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/audit-logs.tsx
Show resolved
Hide resolved
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/audit-logs.tsx
Outdated
Show resolved
Hide resolved
|
@CodeRabbit final review |
|
Tip For best results, initiate chat on the files or code changes. @steven-tey This is an excellent implementation of a comprehensive audit logging system! Here's my final review: 🎯 Overall Assessment: OutstandingThis PR delivers a production-ready audit logging system with exceptional attention to detail and consistency. ✅ Key Strengths1. Robust Architecture
2. Comprehensive Coverage
3. Security & Access Control
4. Developer Experience
5. User Experience
🔍 Technical Highlights// Excellent pattern used throughout:
waitUntil(
recordAuditLog({
workspaceId: workspace.id,
programId: program.id,
action: "partner.approved",
actor: { id: user.id, name: user.name },
targets: [{ id: partner.id, type: "partner", metadata: partner }]
})
);📊 ImpactThis implementation provides:
🚀 Ready for ProductionThe implementation demonstrates:
Recommendation: This PR is ready to merge. Excellent work on delivering a comprehensive, well-architected audit logging system! 🎉 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/audit-logs.tsx(1 hunks)apps/web/lib/api/audit-logs/get-audit-logs.ts(1 hunks)apps/web/lib/api/audit-logs/record-audit-log.ts(1 hunks)packages/tinybird/pipes/get_audit_logs.pipe(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- apps/web/lib/api/audit-logs/record-audit-log.ts
- apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/security/audit-logs.tsx
- apps/web/lib/api/audit-logs/get-audit-logs.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: build
🔇 Additional comments (3)
packages/tinybird/pipes/get_audit_logs.pipe (3)
1-3: LGTM - Standard Tinybird pipe syntax.The NODE endpoint declaration and SQL query structure follow Tinybird conventions correctly.
4-17: Comprehensive field selection looks good.The SELECT clause appropriately captures all essential audit log fields including actor information, timestamps, targets, and metadata for complete audit trail visibility.
24-25: Security: Proper parameterization implemented.Good use of Tinybird's
String()function for parameter sanitization to prevent SQL injection in the workspace and program ID filters.
Summary by CodeRabbit
New Features
Improvements
Bug Fixes
Chores