feat: add XLSX export for quarter transactions#23
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
More reviews will be available in 21 minutes and 41 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (19)
📝 WalkthroughWalkthroughThe PR adds quarter-level opening/closing balance snapshots across multi-chain treasury accounts (gnosis, mainnet, base), introduces a new ChangesQuarter Balance Snapshots & XLSX Export
Admin/Member View Mode Toggle
Sequence Diagram(s)sequenceDiagram
rect rgba(135, 206, 235, 0.5)
note over Admin,quarterBalanceSnapshots: Balance Sync Step
end
participant Admin
participant syncQuarterBalancesStep
participant quarter_sync_state as QuarterSyncState
participant syncQuarterBalances
participant RPC
participant quarterBalanceSnapshots
Admin->>syncQuarterBalancesStep: invoke with { quarterId, runId }
syncQuarterBalancesStep->>quarter_sync_state: markQuarterSyncStepRunning("balances")
syncQuarterBalancesStep->>syncQuarterBalances: syncQuarterBalances(quarter)
syncQuarterBalances->>RPC: binary-search boundary blocks per chain
loop per account × boundary × asset
syncQuarterBalances->>RPC: getRawBalance (native or ERC-20)
syncQuarterBalances->>syncQuarterBalances: getHistoricalUsdPricing
syncQuarterBalances->>quarterBalanceSnapshots: upsert snapshot row
end
syncQuarterBalances->>quarterBalanceSnapshots: delete stale rows
syncQuarterBalances-->>syncQuarterBalancesStep: row count
syncQuarterBalancesStep->>quarter_sync_state: markQuarterSyncStepSuccess("balances") → currentStep = "finalize"
syncQuarterBalancesStep-->>Admin: updated QuarterSyncStatus
sequenceDiagram
rect rgba(144, 238, 144, 0.5)
note over Admin,XLSXBuffer: XLSX Export
end
participant Admin
participant ExportRoute as GET /export.xlsx
participant isQuarterExportReady
participant buildQuarterXlsxExport
participant DB
Admin->>ExportRoute: GET /admin/quarters/[id]/export.xlsx
ExportRoute->>ExportRoute: authenticate + authorize (401/403)
ExportRoute->>DB: getQuarterById (404 if missing)
ExportRoute->>isQuarterExportReady: check sync freshness + balancesStatus + unclassified=0
isQuarterExportReady-->>ExportRoute: false → 409 / true → proceed
ExportRoute->>buildQuarterXlsxExport: fetch ledger, membership, proposals, balances
buildQuarterXlsxExport->>DB: concurrent queries for all datasets
buildQuarterXlsxExport-->>ExportRoute: XLSX Buffer
ExportRoute-->>Admin: attachment response (Content-Disposition, XLSX MIME)
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 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.
Pull request overview
This PR adds quarter balance snapshotting and XLSX export support, extending the quarter sync workflow with a new “balances” step and expanding treasury account/asset support (including new account types and stable assets). It also introduces an admin “member view” toggle to preview reduced permissions in the UI.
Changes:
- Add quarter balance snapshot syncing (opening/closing) and surface the results in the quarter transactions admin UI.
- Add an
/admin/quarters/[id]/export.xlsxdownload route and a server-side ExcelJS export builder, gated by sync/classification readiness. - Extend treasury schema and logic (new
bankaccount type, new tracked assets, multi-chain balance syncing improvements) and add a UI view-mode toggle.
Reviewed changes
Copilot reviewed 29 out of 32 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/lib/treasury/types.ts | Expand TreasuryAssetSymbol to include new tracked symbols. |
| src/lib/treasury/transactions.ts | Normalize token addresses for operator log fetching / transfer IDs. |
| src/lib/treasury/swap-details.ts | Normalize tracked token addresses before isAddressEqual checks. |
| src/lib/treasury/pricing.ts | Add new stable symbols for historical pricing shortcuts. |
| src/lib/treasury/balances.ts | Support syncing balances across multiple chains/accounts and broaden tracked assets. |
| src/lib/treasury/assets.ts | Add DAI (mainnet) and DKUSD (Base) operator assets. |
| src/lib/treasury/accounts.ts | Add bank editable account type and new listActiveBalanceAccounts() helper. |
| src/lib/quarter-xlsx-export.ts | New ExcelJS workbook builder for quarter exports (summary, balances, ledger, raids, etc.). |
| src/lib/quarter-sync.ts | Add “balances” to quarter sync status model and step transitions. |
| src/lib/quarter-export-readiness.ts | New helper to determine when quarter XLSX export is allowed. |
| src/lib/quarter-balances.ts | New module to sync quarter boundary balances and query rows/summaries. |
| src/lib/auth/types.ts | Add viewMode to session data. |
| src/lib/auth/session.ts | Serialize session with optional “member view” permission masking. |
| src/db/schema.ts | Add bank to account enum, add balances step fields, and add quarter_balance_snapshots table + enums. |
| src/components/treasury/treasury-dashboard.tsx | Refresh logic now treats failed snapshots as refreshable. |
| src/components/auth/wallet-connect.tsx | Add profile dropdown + view-mode toggle UI and outside-click handling. |
| src/components/app-header.tsx | Replace <details> nav groups with controlled dropdown state + outside-click close. |
| src/app/api/auth/view-mode/route.ts | Add API route to persist view mode in session. |
| src/app/admin/treasury-accounts/page.tsx | Add bank account type UI labels/icons and tweak empty-state copy. |
| src/app/admin/treasury-accounts/actions.ts | Allow creating/updating bank accounts; redirect after create. |
| src/app/admin/quarters/page.tsx | Show XLSX export link when export-ready; adjust Q1 creation prompt copy/visibility. |
| src/app/admin/quarters/[id]/transactions/sync-transactions-form.tsx | Insert “Balances” step into the sync workflow UI. |
| src/app/admin/quarters/[id]/transactions/page.tsx | Display export link when ready and add quarter balances panel. |
| src/app/admin/quarters/[id]/transactions/actions.ts | Add syncQuarterBalancesStep and require balances before finalizing. |
| src/app/admin/quarters/[id]/export.xlsx/route.ts | Add XLSX export endpoint with readiness + permission gating. |
| package.json | Add exceljs dependency. |
| pnpm-lock.yaml | Lockfile updates for exceljs and transitive dependencies. |
| drizzle/meta/_journal.json | Register new migrations in the journal. |
| drizzle/0015_bumpy_green_goblin.sql | Migration: add balances enum/table + quarter sync status columns + enum value. |
| drizzle/0016_rapid_loa.sql | Migration: add bank to treasury_account_type enum. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/app/admin/quarters/[id]/transactions/actions.ts (1)
792-798:⚠️ Potential issue | 🟠 Major | ⚡ Quick winInsert the balances step before finalization in the full sync orchestrator.
syncQuarterTransactionsfinalizes immediately after membership, but finalization now requires balances success (Line 1048). This path will fail when invoked.Suggested fix
status = await syncQuarterMembershipStep({ quarterId, runId: status.runId }); throwIfStepFailed(status, "membership"); + status = await syncQuarterBalancesStep({ + quarterId, + runId: status.runId, + }); + throwIfStepFailed(status, "balances"); status = await finalizeQuarterSyncStep({ quarterId, runId: status.runId, writeAudit: true, });🤖 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 `@src/app/admin/quarters/`[id]/transactions/actions.ts around lines 792 - 798, The full sync orchestrator in syncQuarterTransactions is missing the balances synchronization step before finalization. Between the syncQuarterMembershipStep call and the finalizeQuarterSyncStep call, insert a call to sync the quarter balances (following the same pattern as the membership step), capture the result in the status variable, check for failures with throwIfStepFailed using an appropriate step name, and pass the updated runId from status to the finalization call to ensure the correct dependency order is maintained.src/app/admin/quarters/[id]/transactions/page.tsx (1)
134-136:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAlign local stable-symbol defaults with treasury pricing logic.
Line 135 omits
DAIandDKUSD, so those transfers won’t get the same stable-token USD default behavior used elsewhere.Suggested patch
function isStableAssetSymbol(symbol: string) { - return ["USDC", "XDAI", "WXDAI"].includes(symbol.toUpperCase()); + return ["DAI", "DKUSD", "USDC", "XDAI", "WXDAI"].includes( + symbol.toUpperCase(), + ); }🤖 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 `@src/app/admin/quarters/`[id]/transactions/page.tsx around lines 134 - 136, The isStableAssetSymbol function is missing DAI and DKUSD from its list of stable asset symbols. Add both DAI and DKUSD to the array alongside the existing USDC, XDAI, and WXDAI symbols to ensure consistent stable-token USD default behavior across the application.
🤖 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 `@src/app/api/auth/view-mode/route.ts`:
- Around line 17-18: The view-mode route currently defaults any invalid or
misspelled mode value to "admin" instead of rejecting it. After parsing the
request body on line 17, add validation to check if body.mode is either "member"
or "admin". If the mode is invalid, return a 400 Bad Request response with an
appropriate error message before proceeding with the session mutation. Only
execute the mode assignment on line 18 if the mode value has been validated as
one of the allowed options.
In `@src/components/auth/wallet-connect.tsx`:
- Around line 325-327: The error catch block in the wallet-connect.tsx file that
handles errors from the toggleViewMode operation is reusing getFriendlyError,
which has a fallback message of "Wallet sign-in failed." This is misleading for
/api/auth/view-mode failures since it displays wallet-related messaging instead
of view-mode-specific messaging. Replace the getFriendlyError call in this catch
block with a custom error message that is appropriate for view-mode toggle
failures, ensuring users see contextually correct error information related to
toggling view mode rather than wallet sign-in.
In `@src/db/schema.ts`:
- Around line 378-384: The quarter_balance_snapshots_unique index uses
table.accountAddress directly without normalization, but application code reads
data using .toLowerCase(), creating a case-sensitivity mismatch that allows
duplicate snapshots for addresses with different casing. Modify the
accountAddress field in the quarter_balance_snapshots_unique index definition to
apply lowercase normalization (using the appropriate database function for your
schema library) so that address case variants are treated identically for the
uniqueness constraint.
In `@src/lib/auth/session.ts`:
- Around line 44-52: The memberViewRoles variable filters out only the "admin"
role but retains other privileged roles like "cleric", which can leak through
the permissions object when viewMode is "member". Instead of filtering to remove
just "admin", normalize memberViewRoles to only contain ["member"] when in
member view mode to ensure no privileged roles are exposed through the adjusted
permissions object.
In `@src/lib/quarter-balances.ts`:
- Around line 232-233: The getBlock() calls on lines 232, 243, 285, and 286 lack
retry handling for transient RPC failures (such as 429 rate limit errors), which
causes the entire quarter sync to abort despite retry logic existing for balance
reads elsewhere. Wrap these direct getBlock() calls with the same retry
mechanism that is already implemented for balance read operations to ensure
transient failures do not interrupt the synchronization process.
- Around line 435-437: The stale cleanup logic at line 435 skips processing when
treasuryAccountId is null, and the pruning logic in lines 467-475 only handles
non-null treasuryAccountId values. This leaves stale snapshot rows for the main
treasury account (when treasuryAccountId is null) uncleaned when tracked assets
or scope changes. Remove or modify the `if (!account.treasuryAccountId)
continue;` condition so that null treasuryAccountId values are processed instead
of skipped, and update the pruning logic in the 467-475 range to also handle the
case where treasuryAccountId is null to ensure stale rows are properly removed.
In `@src/lib/quarter-xlsx-export.ts`:
- Around line 298-312: In the balanceRows.map() function, the balance field is
being converted to a Number using toNumber(row.balance), which can lose
precision for high-precision token balances. Remove the toNumber() conversion
from the balance property and keep it as a string to preserve the exact
precision of the token balance values for audit and export accuracy.
---
Outside diff comments:
In `@src/app/admin/quarters/`[id]/transactions/actions.ts:
- Around line 792-798: The full sync orchestrator in syncQuarterTransactions is
missing the balances synchronization step before finalization. Between the
syncQuarterMembershipStep call and the finalizeQuarterSyncStep call, insert a
call to sync the quarter balances (following the same pattern as the membership
step), capture the result in the status variable, check for failures with
throwIfStepFailed using an appropriate step name, and pass the updated runId
from status to the finalization call to ensure the correct dependency order is
maintained.
In `@src/app/admin/quarters/`[id]/transactions/page.tsx:
- Around line 134-136: The isStableAssetSymbol function is missing DAI and DKUSD
from its list of stable asset symbols. Add both DAI and DKUSD to the array
alongside the existing USDC, XDAI, and WXDAI symbols to ensure consistent
stable-token USD default behavior across the application.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 768b68d7-dfa9-4149-8a12-68dac1b5d534
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (31)
drizzle/0015_bumpy_green_goblin.sqldrizzle/0016_rapid_loa.sqldrizzle/meta/0015_snapshot.jsondrizzle/meta/0016_snapshot.jsondrizzle/meta/_journal.jsonpackage.jsonsrc/app/admin/quarters/[id]/export.xlsx/route.tssrc/app/admin/quarters/[id]/transactions/actions.tssrc/app/admin/quarters/[id]/transactions/page.tsxsrc/app/admin/quarters/[id]/transactions/sync-transactions-form.tsxsrc/app/admin/quarters/page.tsxsrc/app/admin/treasury-accounts/actions.tssrc/app/admin/treasury-accounts/page.tsxsrc/app/api/auth/view-mode/route.tssrc/components/app-header.tsxsrc/components/auth/wallet-connect.tsxsrc/components/treasury/treasury-dashboard.tsxsrc/db/schema.tssrc/lib/auth/session.tssrc/lib/auth/types.tssrc/lib/quarter-balances.tssrc/lib/quarter-export-readiness.tssrc/lib/quarter-sync.tssrc/lib/quarter-xlsx-export.tssrc/lib/treasury/accounts.tssrc/lib/treasury/assets.tssrc/lib/treasury/balances.tssrc/lib/treasury/pricing.tssrc/lib/treasury/swap-details.tssrc/lib/treasury/transactions.tssrc/lib/treasury/types.ts
|
Addressed the two outside-diff CodeRabbit comments in 51f3aec:
Verified with |
This pull request introduces a new "quarter balances" feature, including database migrations, backend logic, and UI components for tracking and exporting treasury account balances at the start and end of each reporting quarter. It also adds support for exporting quarter data as an XLSX spreadsheet, and updates the quarter sync workflow to include a new balances step. Additionally, the database schema is extended to support new account types and balance tracking.
Quarter Balances Feature
quarter_balance_snapshotstable and related enum/type for tracking opening and closing balances for each treasury account and asset, including USD values and price sources. Also adds indexes and foreign key constraints for efficient querying and data integrity.syncQuarterBalancesStepaction, updates to the sync workflow to require balances before finalizing, and integration with the quarter sync status. (src/app/admin/quarters/[id]/transactions/actions.tsR34, src/app/admin/quarters/[id]/transactions/actions.tsR831-R832, src/app/admin/quarters/[id]/transactions/actions.tsR994-R1031, src/app/admin/quarters/[id]/transactions/actions.tsL1006-R1048)Quarter Export Improvements
exceljsdependency for spreadsheet generation.Database Schema Updates
'bank'to thetreasury_account_typeenum to support bank accounts.Sync Workflow Updates
These changes collectively enable comprehensive quarter-end balance tracking, review, and export, improving transparency and auditability of treasury activity.
Summary by CodeRabbit
Release Notes
New Features
Enhancements