Feat(csv): adding csv exports that are server side#313
Conversation
… line in one of the project GET
…t present in the database.. :(
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds server-side workspace and project analytics, authenticated CSV export endpoints, and frontend consumption of aggregated data. It also makes secondary issue-list requests resilient to individual failures and updates web tooling versions. ChangesAnalytics feature
Issue list loading behavior
Web tooling versions
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant AnalyticsWorkItemsPage
participant GinRouter
participant AnalyticsHandler
participant AnalyticsService
participant AnalyticsStore
AnalyticsWorkItemsPage->>GinRouter: Request analytics or CSV
GinRouter->>AnalyticsHandler: Dispatch authenticated request
AnalyticsHandler->>AnalyticsService: Request analytics or exports
AnalyticsService->>AnalyticsStore: Query counts or stream issues
AnalyticsStore-->>AnalyticsService: Return analytics rows or export items
AnalyticsService-->>AnalyticsHandler: Return response data
AnalyticsHandler-->>AnalyticsWorkItemsPage: Return JSON or CSV download
Possibly related PRs
Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies" 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: 11
🧹 Nitpick comments (1)
apps/web/src/pages/IssueListPage.tsx (1)
589-590: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRemove leftover debugging statements.
These
console.logstatements appear to be debugging artifacts and should be removed to keep the production console clean.🧹 Proposed fix
- console.log(project) - console.log(workspace)🤖 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 `@apps/web/src/pages/IssueListPage.tsx` around lines 589 - 590, Remove the leftover console.log statements for project and workspace from the surrounding IssueListPage component, leaving the production logic unchanged.
🤖 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 `@apps/api/internal/handler/analytics.go`:
- Around line 254-266: Update the CSV export handler around csv.Writer creation
to check errors from both the header and per-issue writer.Write calls, and
ensure writer.Flush is executed before inspecting writer.Error(). Propagate or
return an appropriate error when any write or flush error occurs, including the
analogous export block around the second issue loop.
- Around line 14-16: Refactor AnalyticsHandler and all four analytics/export
handlers so they resolve the authenticated user and delegate authorization-aware
workspace/project access checks to a service, including validating the project
slug. Move every GORM query out of the handlers into a store called by that
service, preserving the existing response behavior only after access is
authorized.
- Around line 19-24: The analytics response contract lacks populated
created-versus-resolved trend data. In
apps/api/internal/handler/analytics.go:19-24, extend AnalyticsResponse with a
typed time-series field and populate it through the analytics handler’s existing
data flow; in apps/web/src/pages/AnalyticsWorkItemsPage.tsx:246, consume that
response field with the corresponding concrete type instead of any[] so the
chart receives real backend data.
- Around line 257-265: Update the issue row export in the analytics CSV handler
to neutralize spreadsheet formulas in user-controlled fields before passing them
to csv.Writer. Apply the same sanitization to issue.Name, issue.State, and
issue.Priority, and also to the corresponding cells in the referenced export
block around lines 300-307; preserve IDs and headers unless they are subject to
the same unsafe-value requirement.
- Around line 90-120: Update the analytics handler’s aggregate-query error
handling, including the assignee and label flows and the secondary project-query
section, so any database failure is returned or surfaced through an explicit
partial-result status instead of leaving empty maps that imply zero counts.
Preserve successful aggregation behavior and ensure the response clearly
distinguishes valid empty metrics from failed queries.
In `@apps/api/internal/router/router.go`:
- Around line 436-437: Preserve trailing slashes for both project analytics
routes in apps/api/internal/router/router.go at lines 436-437 by registering
slash-terminated paths. Update the export request in
apps/web/src/pages/AnalyticsWorkItemsPage.tsx at lines 206-208 to use the
corresponding slash-terminated URL.
In `@apps/web/src/pages/AnalyticsWorkItemsPage.tsx`:
- Line 190: Update both catch clauses in AnalyticsWorkItemsPage, including the
blocks around the existing catch handlers, to remove the unused err bindings and
use bindingless catch syntax while preserving their current error-handling
bodies.
- Line 267: Replace the fixed English user-facing labels in
AnalyticsWorkItemsPage, including the KPI, chart-axis, table, action, and export
labels near the referenced sections, with the existing t(...) translation flow.
Add or reuse appropriate translation keys for each label while preserving the
current rendered text and behavior.
- Around line 141-174: Update the workspace-loading effect around getBySlug so
the analytics and project requests are awaited before setLoading(false) runs,
rather than being launched in nested promise chains. Add and maintain an
analytics error state when the analytics fetch fails, and render that error
instead of silently treating missing analytics data as zero; preserve
cancellation checks before state updates.
- Around line 235-239: Update the KPI count logic in AnalyticsWorkItemsPage
around backlogCount, startedCount, unstartedCount, completedCount, and
totalIssues to derive counts from the configured stable state groups rather than
hard-coded display-name keys. Ensure totalIssues sums every value in
analytics.by_state, including Cancelled and custom states, while preserving the
existing KPI bucket semantics through the group definitions.
In `@apps/web/src/pages/IssueListPage.tsx`:
- Line 185: Update the safeFetch helper to use a generic type parameter, such as
the TSX-safe T, so its promise and fallback share the same type and the returned
Promise is typed accordingly. Preserve the existing fallback behavior and ensure
downstream Promise.all results are inferred without any.
---
Nitpick comments:
In `@apps/web/src/pages/IssueListPage.tsx`:
- Around line 589-590: Remove the leftover console.log statements for project
and workspace from the surrounding IssueListPage component, leaving the
production logic unchanged.
🪄 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 Plus
Run ID: bb305e98-fd9a-42a8-be2f-354597bce129
⛔ Files ignored due to path filters (1)
apps/web/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (5)
apps/api/internal/handler/analytics.goapps/api/internal/router/router.goapps/web/package.jsonapps/web/src/pages/AnalyticsWorkItemsPage.tsxapps/web/src/pages/IssueListPage.tsx
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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 `@apps/api/internal/service/analytics.go`:
- Around line 97-113: Update GetWorkspaceAnalytics and GetProjectAnalytics so
failures from GetWorkspaceAssigneeAnalytics or GetWorkspaceLabelAnalytics are
propagated as errors instead of returning successful responses with empty maps.
Preserve the existing map population for successful queries, and retain warning
logs only if compatible with the returned error flow.
- Around line 15-20: Extend AnalyticsResponse with a JSON-serialized time-series
field for created-versus-resolved trend data, using the project’s established
trend data type or shape and naming it consistently with the existing response
fields. Ensure the analytics handler populates this field so the frontend chart
receives the trend data.
- Around line 172-188: Change ExportWorkspaceCSV and ExportProjectCSV to avoid
accumulating all rows in slices; thread a row callback or io.Writer from the CSV
handler through the service and store so each item is written or processed as
StreamWorkspaceIssuesForExport/StreamProjectIssuesForExport scans it. Preserve
workspace access checks and error propagation while ensuring CSV output is
streamed incrementally.
In `@apps/api/internal/store/analytics.go`:
- Around line 47-60: The assignee analytics queries omit issues with nullable
assignee_id. In GetWorkspaceAssigneeAnalytics and GetProjectAssigneeAnalytics,
change the users join to preserve unassigned issues and group them into an
explicit “Unassigned” bucket, while retaining user email values for assigned
issues and keeping the existing workspace/project filters intact.
🪄 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 Plus
Run ID: 4d3a4a45-2996-4760-b1ab-fc1148ed7c63
📒 Files selected for processing (7)
apps/api/internal/handler/analytics.goapps/api/internal/model/analytics.goapps/api/internal/router/router.goapps/api/internal/service/analytics.goapps/api/internal/store/analytics.goapps/web/src/pages/AnalyticsWorkItemsPage.tsxapps/web/src/pages/IssueListPage.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/api/internal/router/router.go
- apps/web/src/pages/AnalyticsWorkItemsPage.tsx
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@apps/api/internal/store/analytics.go`:
- Around line 181-188: Update both workspace and project trend queries at
apps/api/internal/store/analytics.go:181-188 and
apps/api/internal/store/analytics.go:198-203 to derive resolved counts from
completed/cancelled state transitions, using state_id/states.group and
issue_activities.created_at where appropriate, instead of issues.created_at and
issues.state. Ensure resolved issues are bucketed by the timestamp when they
entered the resolved state while preserving created counts by creation date.
🪄 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 Plus
Run ID: ccc4d2b1-699f-479e-94ca-4ba11fd2e343
📒 Files selected for processing (3)
apps/api/internal/model/analytics.goapps/api/internal/service/analytics.goapps/api/internal/store/analytics.go
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/api/internal/service/analytics.go
- apps/api/internal/model/analytics.go
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@apps/api/internal/service/analytics.go`:
- Around line 189-201: Complete the CSV export contract across the workspace and
project paths: extend the reduced export models in analytics.go to carry
assignee and label values, update the corresponding store queries to select and
join those fields, propagate them through the ExportWorkspaceCSV and
ExportProjectCSV callback types, and add matching columns in the analytics
handlers’ CSV output. Keep model fields, query results, callback payloads,
headers, and row serialization aligned for both exports.
🪄 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 Plus
Run ID: 1c051704-f3a6-4db8-b484-bd6ebebda0f5
📒 Files selected for processing (3)
apps/api/internal/handler/analytics.goapps/api/internal/service/analytics.goapps/api/internal/store/analytics.go
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/api/internal/store/analytics.go
- apps/api/internal/handler/analytics.go
|
@martian56, i think i went above the scope of the assigned issues, but there is a few things i didnt add or restrained myself of adding because it was not in my scope |
Summary
This PR implements the server-side analytics endpoints and the CSV export capability for workspaces and projects, resolving the client-side scalability issues and wiring up the "Export as CSV" button in the UI.
Linked issues
Closes #204
Type of change
feat:) — user-visible new capabilitySurface
apps/api/)apps/web/)What changed
API Backend (
apps/api/)Frontend UI (
apps/web/)AnalyticsOverviewPageandAnalyticsWorkItemsPageto fetch metrics from the new backend endpoints instead of doing expensive client-side aggregation.Why this approach
Processing aggregations on the server ensures the platform scales efficiently as workspaces grow to thousands of issues. Using optimized database joins prevents the "N+1 query" performance pitfall.
Database / migrations
No schema migrations required.
Breaking changes
Test plan
npm run validatefrom the repository root passes cleanly (TypeScript check + golang test suites).go run ./cmd/api seed.Screenshots / recordings (UI changes)
AI assistance
Gemini— and AI-assisted commits include aCo-Authored-By:trailerChecklist
feat(api/ui): implement server-side analytics and working CSV export #204)--no-verifybypass).envvalues committedReview Notes & Future Improvements
While testing locally, I noticed a few behaviors and structural details to highlight:
Percentage Calculations & Charts:
doneandbacklogare visible in the data, they do not render properly inside the main chart. This might be an existing issue with how state types/cycles are mapped, which we can refine later.Database Schema Details (Assignees & Labels):
assigneeorlabelcolumns on theissuestable, and because setting up the many-to-many joins (issue_assigneesandissue_labels) was causing SQL errors, I skipped adding assignees and labels to the CSV columns for now to keep the code stable. We can add these relations in a follow-up PR once we iron out the database join logicSummary by CodeRabbit