feat(projects): scope GET /dashboard to the caller's projects - #304
Draft
nourshoreibah wants to merge 1 commit into
Draft
feat(projects): scope GET /dashboard to the caller's projects#304nourshoreibah wants to merge 1 commit into
nourshoreibah wants to merge 1 commit into
Conversation
The dashboard aggregates were admin-only, so a non-admin got a 403 and the
frontend had no source for a project's spend or staff count -- which is why
every ProjectCard on /dashboard and /projects renders budget_used={0}
members={0}.
An admin still sees every project. Everyone else now sees the same payload
restricted to the projects they are a member of, and a caller with no
memberships gets a zeroed payload rather than an error (`where in ()` is not
valid SQL, so that case short-circuits before any aggregate query runs).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ℹ️ Issue
Prerequisite for replacing the last of the frontend's hardcoded placeholder data. Split out per "if the API is missing, put up a separate PR to add it".
📝 Description
ProjectCardon/dashboardand/projectsis rendered withbudget_used={0} members={0}— hardcoded, for every project. The real numbers already exist inGET /projects/dashboard(spent,staff_count), but that route was gatedif (!user.isAdmin) return 403, so a non-admin had no source for them at all.This makes the route work for an admin and anyone who has projects:
totalSpent,totalProjects,topExpenseCategory,projects, per-project spend, per-project staff,expensesByMonth) is filtered by that id set.where project_id in ()is not valid SQL.Duplicate membership rows are de-duped before they reach the
INlist.✔️ Verification
npx jestinapps/backend/lambdas/projects— 77 passed, 6 suites, against the local Postgres (branch_dev@localhost:5432/branch_db).New coverage:
dashboard.unit.test.ts— non-admin gets a scoped dashboard; duplicate memberships don't widen theINlist; a member of nothing gets the empty payload after exactly one query.projects.e2e.test.ts— replaces the old403: non-admin is forbiddenwith the real scoped result against seed data (user 3 → project 2 only,spent: 4500,staff_count: 1), plus the no-memberships case.🏕️ (Optional) Future Work / Notes
spent/staff_counthere to fill inProjectCard. It is stacked on this branch.403was the only thing this route did withisAdmin, so the admin path is byte-for-byte the same set of queries as before.🤖 Generated with Claude Code