Files
gridpilot.gg/docs/league/actor-and-permissions.md
2025-12-28 12:04:12 +01:00

3.5 KiB
Raw Blame History

League Actor Model & Permissions (Canonical)

This document defines the canonical backend actor model and the permission rules for league admin/owner operations.

It is the source of truth for Subtask 0A in plans/league-admin-mvp-plan.md.


Session identity (source of truth)

What the authenticated session contains

Mapping: userIddriverId

Current canonical mapping (for MVP):

Rationale:

  • The current system uses the session user identity as the same identifier used by racing/league membership repositories (e.g. seeded admin user is driver-1 in session).
  • If/when we introduce a real user ↔ driver relationship (1:N), this function becomes the single authoritative mapping point.

Canonical actor model

The APIs canonical “actor” is:

type Actor = { userId: string; driverId: string };

Returned by getActorFromRequestContext().

Rules:

  • All auth/permissions decisions use the actor derived from the authenticated session.
  • Controllers and services must never use request-body “performer/admin IDs” for authorization decisions.

League permissions: admin/owner

Meaning of “league admin/owner”

A driver is authorized as a league admin if:

  • They have an active membership in the league, and
  • Their membership role is either owner or admin.

Authoritative check:

How it is validated server-side

Canonical enforcement entrypoint (API layer):

This helper:


Contract rule (non-negotiable)

No league write operation may accept performer/admin IDs for auth decisions.

Concretely:

  • Request DTOs may still temporarily contain IDs for “target entities” (e.g. targetDriverId), but never the acting user/admin/performer ID.
  • Any endpoint/service that needs “who is performing this” MUST obtain it from session-derived actor, not from request payload, params, or hardcoded values.

Tests:

  • Actor derives from session, not payload: ActorFromSession.
  • Permission helper uses session-derived actor consistently: ActorFromSession.
  • Example application in a league write-like operation (joinLeague) ignores payload driverId and uses session actor: LeagueService.