1
0
Fork 0
polaris-task-force/src/utils/AGENTS.md
Z8MB1E 33174572cc docs: refresh AGENTS.md guides
Update root and per-directory AGENTS.md files to reflect the current
state of the codebase: collection inventory, RBAC registry, base
management, personnel pages, training minigames, Discord bot transfer
and evaluation-reminder flows, banking currency config, migration
wrapper, and Playwright/Vivaldi e2e details.
2026-09-06 05:32:53 -04:00

2.9 KiB

AGENTS.md — Utilities & Access Control

Parent: ../../AGENTS.md — RBAC overview, permission groups, event system.

Overview

10 files across 3 subdirectories. Core cross-cutting concerns: three-layer RBAC, fire-and-forget event logging, XP resolution.

Structure

utils/
  access-control/        8 files    Permission checking, role gates, qualification queries
  event-log/             3 files    Event emitter, type constants, formatting
  xp/                    1 file     Level resolver

Access control layers

Three independent access mechanisms, each used in different contexts:

1. hasPermission(payload, user, "domain:action")

Full RBAC check against src/permissions/index.ts (100+ permissions). Superuser bypass. Cached 30s via loadUserPermissions. Used in server actions and collection access functions.

2. isRole(role) / hasRoles(roles[])

Lightweight role checks. Used for quick conditional rendering (e.g., isRole("admin") for admin-only UI). No Payload call — reads from the user object directly.

3. hasLogisticsQualification() / hasIntelligenceQualification()

Queries Profiles.progression.qualifications for specific qualification strings (case-insensitive). Admin/developer always pass. Used to gate logistics-only and intelligence-only UI sections.

Event log system

Emitter: emitGameEvent(payload, { type, message, ... })

Fire-and-forget create on game-event-logs. Always sets system: true. Silent error catch (no throw). Always called AFTER successful mutation in server actions.

Event types: EventTypes constants (~105 types across 15+ categories)

Defined in eventTypes.ts. Use these constants for TypeScript narrowing on the type field. Categories include: mission:*, finance:*, market:*, structure:*, staff:*, logistics:*, bank:*, notification:*, locker:*, xp:*, ticket:*, wiki:*, minigame:*, attendance:*, system:*.

Display: formatType(type) — human-readable label for event types.

Where to look

Task Path
Add new RBAC permission src/permissions/index.ts + use in hasPermission calls
Add qualification gate access-control/hasLogisticsQualification.ts (or create similar)
Add event type constant event-log/eventTypes.ts (add to EventTypes object)
Emit event from action import { emitGameEvent } from "@/utils/event-log/emit"
Check qualification in layout Use hasLogisticsQualification(payload, user)
Modify XP calculation xp/resolveLevel.ts

Anti-patterns

  • NEVER throw in emitGameEvent — it's fire-and-forget by design
  • NEVER use isRole for permission-sensitive operations — use hasPermission instead
  • NEVER hardcode qualification strings — use the constants in the qualification collection
  • NEVER add event types without adding to EventTypes constants (breaks TypeScript narrowing)