more adding - #313
Conversation
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
|
Visit the preview URL for this PR (updated for commit fa71f8f): https://hacklytics2027--pr-313-55dwvq8k.web.app (expires Wed, 12 Aug 2026 21:19:58 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: c48ba34db61581e25fe2978355160b5eefe0e83f |
|
| Filename | Overview |
|---|---|
| packages/api/src/routers/initiative.ts | Implements global initiative ownership, applications, proposal review, and leader administration; the previously reported cross-edition boundary no longer exists. |
| packages/db/src/schemas/initiatives.ts | Removes edition foreign keys and makes project-leader appointments unique per user globally. |
| packages/api/src/middleware/procedures.ts | Adds a global project-leader authorization gate with administrator fallback. |
| packages/api/src/services/portal-context.ts | Exposes the global project-leader role in portal context independently of the current hackathon. |
| packages/api/src/routers/member.ts | Aligns membership status and registration with paid, unexpired terms. |
| packages/db/src/services/membership.ts | Centralizes active-membership evaluation around enabled and unexpired membership records. |
| README.md | Documents the intentional global club model and the required one-time schema transition. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
U[Signed-in user] --> M{Paid and unexpired member?}
M -->|Yes| I[Browse, apply, or propose]
M -->|No| B[Browse initiatives only]
A[Administrator] --> R[Review proposals and manage leaders]
R --> L[Global project-leader appointment]
L --> G[Manage year-round club initiatives]
I --> G
Reviews (3): Last reviewed commit: "more" | Re-trigger Greptile
| eq(initiatives.id, input.id), | ||
| eq(initiatives.leaderUserId, ctx.userId), | ||
| // Only while it is still untouched. Once it is approved it is a | ||
| // real initiative with applicants, and archiving is the way out. | ||
| eq(initiatives.status, "proposed"), | ||
| ), |
There was a problem hiding this comment.
Cross-edition proposal mutations
When a proposer supplies their still-pending proposal ID from an earlier edition, withdrawProposal deletes it without checking its hackathon; similarly, reviewProposal accepts an earlier edition's proposal ID and can change its status or reactivate its project-leader assignment. These ID-based mutations bypass the current-edition boundary enforced by the corresponding proposal lists and leader-management procedures, causing historical proposal and role data to be changed.
| reviewNote: input.note ?? null, | ||
| updatedAt: new Date(), | ||
| }) | ||
| .where(eq(initiatives.id, proposal.id)); |
There was a problem hiding this comment.
Review proposal ignores edition
Medium Severity
reviewProposal loads and updates a proposal by id only. Unlike listProposals, it never checks the row belongs to resolveHackathonId’s current edition, so an admin with a foreign UUID can approve or decline another hackathon’s proposal.
Reviewed by Cursor Bugbot for commit 3329ad5. Configure here.
| maxMembers: input.maxMembers ?? null, | ||
| status: "proposed", | ||
| }) | ||
| .returning(); |
There was a problem hiding this comment.
Proposal cap race window
Low Severity
propose enforces at most three pending proposals using a separate count query and insert, with no transaction or lock. Concurrent requests can each see a count below three and insert more than the intended limit.
Reviewed by Cursor Bugbot for commit 3329ad5. Configure here.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.
There are 5 total unresolved issues (including 2 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit fa71f8f. Configure here.
| .max(500) | ||
| .nullable() | ||
| .optional() | ||
| .default(DEFAULT_TEAM_SIZE - 1), |
There was a problem hiding this comment.
Update omits cap becomes three
Medium Severity
Shared initiativeInput applies .default(3) to maxMembers, and update writes fields.maxMembers ?? null. When an update payload omits maxMembers, Zod supplies 3, so an uncapped initiative (null in the database) is persisted as capped at three even though the leader meant to leave it unlimited.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit fa71f8f. Configure here.
| status: z | ||
| .enum([ | ||
| "draft", | ||
| "announced", |
There was a problem hiding this comment.
Current edition cache not cleared
Medium Severity
After hackathon.update, the handler clears hackathons:* but not the server cache key hackathon:current-id used by resolveHackathonId. For up to 60 seconds after an announced edition moves to open, membership, initiative gates, and check-in can keep resolving the previous hackathon.
Reviewed by Cursor Bugbot for commit fa71f8f. Configure here.
| ...opts, | ||
| year: "numeric", | ||
| }); | ||
| return sameYear ? `${startText} – ${endText}` : `${startText} – ${endText}`; |
There was a problem hiding this comment.
Cross year start date wrong
Low Severity
formatRange omits the year on the start date when the range crosses calendar years. The sameYear branch and the else branch return the same string, so multi-year ranges can read as if both dates share one year.
Reviewed by Cursor Bugbot for commit fa71f8f. Configure here.


Note
High Risk
Large cross-cutting change: new auth gates, membership semantics, and a required manual DB step before schema push; incorrect migration or ordering could lock leaders out or leave duplicate rows.
Overview
This PR separates club initiatives from hackathon editions, adds pre-registration interest for announced hackathons, and fixes several membership and “current edition” bugs that were gating the portal incorrectly.
Club initiatives get new schema (
project_leader,initiative,initiative_application) with leaders and initiatives no longer tied to a hackathon. A fullinitiativetRPC router covers leader management, applications, member proposals, and admin review;isProjectLeadermiddleware and portalisProjectLeaderexpose the leader tab with cache eviction on role changes. README documents a one-off SQL migration beforemigrate:pushbecauseproject_leaderuniqueness moved from per-edition to per-user.Hackathon interest adds
hackathon_interestand anannouncedstatus so editions can be public before registration opens. New procedures (getUpcoming,registerInterest,withdrawInterest,listInterest) keep interest off the participants table; the portal/hacklyticspage and the Hacklytics 2027 site swap Typeform links for the portal interest URL and “Notify me” CTAs.Membership no longer grants a year on
member.register—only profile rows withisActive: falseand no end date until payment viacreateOrUpdateMembership.checkStatusand portal context alignisMemberwith paid-and-unexpired, addhasLapsedfor renew UX, andresolveCurrentHackathonIdskipsdraftandannouncedso announcing next year does not retarget memberships or club gates.Portal UI splits dashboard into Club vs Hackathon tabs, adds initiatives and admin project-leader pages, and improves lapsed-member messaging. Audit log cron deletes by age instead of truncating the whole table. Tests expand across API and db packages.
Reviewed by Cursor Bugbot for commit fa71f8f. Bugbot is set up for automated code reviews on this repo. Configure here.