Skip to content

Bunches of things#231

Merged
gregv merged 5 commits into
mainfrom
develop
May 29, 2026
Merged

Bunches of things#231
gregv merged 5 commits into
mainfrom
develop

Conversation

@gregv
Copy link
Copy Markdown
Contributor

@gregv gregv commented May 29, 2026

No description provided.

gregv and others added 5 commits May 27, 2026 12:09
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
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)
@gregv gregv merged commit 83d300a into main May 29, 2026
9 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants