Skip to content

Access Module

Location: apps/api/src/shared/access/

The Access module provides a centralised capability matrix. It answers "what can this user do?" without importing other module services — it reads directly from reputation_snapshots and users tables.


Capabilities

CapabilityThresholdLogic
canVoteWikiTotal rep ≥ 5Sum across all interests
canMentorInterest rep ≥ 30 (or total ≥ 50)Per-interest check; total fallback
canModeraterole = 'moderator' or role = 'admin'Role-based only
canProposeGuildAlways falseWave 2 stub
canPostJournalismAny single interest rep ≥ 20findFirst with value >= 20

Thresholds

typescript
const MENTOR_INTEREST_THRESHOLD = 30;
const MENTOR_TOTAL_FALLBACK = 50;
const WIKI_VOTE_REP_THRESHOLD = 5;
const JOURNALISM_REP_THRESHOLD = 20;

AccessMatrixService

MethodDescription
canVoteWiki(userId)Total rep ≥ 5
canMentor(userId, interestId?)Interest ≥ 30 or total ≥ 50
canModerate(userId)Role check
canProposeGuild(userId)Stub → false
canPostJournalism(userId)Any interest ≥ 20
getMatrix(userId)Returns all capabilities as Capabilities object

Capabilities Type

typescript
type Capabilities = {
  canVoteWiki: boolean;
  canMentor: boolean;
  canModerate: boolean;
  canProposeGuild: boolean;
  canPostJournalism: boolean;
};

HTTP Endpoint

GET /api/v1/access/me
Authorization: Bearer <token>

Returns the caller's capability matrix:

json
{
  "canVoteWiki": true,
  "canMentor": false,
  "canModerate": false,
  "canProposeGuild": false,
  "canPostJournalism": true
}

@RequiresRep Decorator

typescript
@RequiresRep({ min: 20, interestField: 'interestId' })
async createPost(...)

Applied to a controller handler to enforce a reputation threshold before the handler runs. Works in tandem with ReputationGuard.

ReputationGuard

ReputationGuard reads @RequiresRep() metadata and checks:

  1. Extracts interestId from the request body or params (using interestField).
  2. Looks up ReputationSnapshot for (userId, interestId).
  3. Throws ForbiddenException if value < min.

Usage Example

typescript
// In posts.controller.ts
@Post()
@UseGuards(JwtAuthGuard, ReputationGuard)
@RequiresRep({ min: 20, interestField: 'interestId' })
async createJournalismPost(...) {}

AccessController

MethodPathAuthDescription
GET/access/meJwtAuthGuardReturn Capabilities for current user

Regulus — invite-only social-knowledge platform