Conversation
Backend half of the new per-team mentor coordination panel. Pairs with the
matching frontend PR in opportunity-hack/frontend-ohack.dev.
Today the OHack mentor experience is documented but invisible to other
mentors during an event — multiple mentors visit the same teams, work gets
duplicated, off-shift mentors miss what others saw, and there's no durable
record of which teams were under-supported. This change gives every team
on /hack/<event_id>/team/<team_id> a public mentor support surface with
coverage attribution, public notes, ownerable concern flags, and a
4-criterion judging-readiness rubric.
New module: api/mentors
- api/mentors/mentors_service.py
* MENTOR_COVERAGE_ITEMS — 6-item team-observation checklist (intro_made,
scope_reviewed, architecture_discussed, repo_health_checked,
criteria_walkthrough, demo_devpost_reviewed). Slugs MUST stay in
lockstep with the frontend MENTOR_COVERAGE_ITEMS array.
* user_is_mentor_for_event() — auth gate. Translates the PropelAuth UUID
to OAuth user_id + email via get_propel_user_details_by_id, then looks
up a volunteers doc with volunteer_type='mentor', event_id=<this event>,
isSelected=True. Matches by email OR user_id for robustness (same
identity gotcha pattern as user_is_on_team in api/teams).
* get_mentor_self_status() — backs the new /api/volunteer/<event_id>/me
endpoint with a lean {is_mentor, volunteer} payload.
* toggle_mentor_coverage / add_mentor_note / delete_mentor_note /
raise_mentor_flag / take_over_mentor_flag / resolve_mentor_flag /
set_mentor_rating — full CRUD over the new mentor_* fields on the
team doc.
* Slack volume is intentionally QUIET: only flag-raises,
flag-resolutions, and the first-time 'all 6 covered' milestone
broadcast to the team's slack_channel. Flag-raises also heartbeat the
per-event mentor channel (hackathon.mentor_slack_channel, falling
back to f'{event_id}-mentors'). Coverage toggles, notes, take-overs,
and ratings are silent (still audit-logged via send_slack_audit).
* All write paths route the response through get_team() so DocumentRefs
on users[] are flattened + enriched (same fix pattern as #227).
- api/mentors/mentors_views.py — 7 routes under /api/team/<teamid>/mentor/...
All @auth.require_user; service-layer gates on user_is_mentor_for_event.
api/__init__.py — registers the new mentors blueprint.
api/volunteers/volunteers_views.py — new GET /api/volunteer/<event_id>/me
endpoint (mentor type only for now). Frontend uses this to decide
interactive vs. read-only rendering of the panel.
api/leaderboard/leaderboard_service.py — new
collect_mentor_panel_opportunities() injects two derived signals into the
existing mentor_opportunities array consumed by the 'Teams Ready for a
Boost' widget on /hack/<event_id>#stats:
- Any team with an open mentor flag (cap of 2 per team to limit noise)
- During the live event window only: any team with mentor_last_touched_at
> 4 hours ago
Best-effort: any failure here is logged and ignored so the broader
leaderboard never breaks.
common/utils/validators.py — allows mentor_slack_channel as a top-level
field on hackathon docs (optional string, ≤80 chars). Falls back to a
name-derived guess at runtime if unset.
New optional Firestore fields on a team doc (no migration; legacy docs
stay valid):
mentor_checklist: { [slug]: {done, checked_at, checked_by_propel_id,
checked_by_name, note?} }
mentor_notes: [{id, created_at, author_propel_id, author_name,
body, deleted_at?, deleted_by_propel_id?}]
mentor_flags: [{id, created_at, raised_by_propel_id, raised_by_name,
severity, body, owner_propel_id, owner_name,
resolved_at?, resolved_by_propel_id?,
resolved_by_name?, resolution_note?}]
mentor_ratings: [{rated_at, rated_by_propel_id, rated_by_name,
criterion, score, note?}]
mentor_last_touched_at, mentor_last_touched_by_name,
mentor_open_flag_count, mentor_coverage_completed_at,
mentor_coverage_completed_by_name (denormalized; the leaderboard reads
these directly).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The /about/judges page has accessibility as a special-category prize alongside the four main criteria. Mentors still need to coach for it, so it belongs in the same ALLOWED_CRITERIA set the rating endpoint accepts. Also updates the criteria_walkthrough coverage item blurb to list all five criteria so it stays in lockstep with the frontend mentorCoverage.js change in the matching frontend PR. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
[Mentors] Per-team mentor support panel + leaderboard boost signals
[Perf] Email caching
| note = body.get("note") | ||
| if item is None or done is None: | ||
| return {"error": "Both 'item' and 'done' are required"}, 400 | ||
| return toggle_mentor_coverage(auth_user.user_id, teamid, item, bool(done), note=note) |
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.
No description provided.