Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/VasquezRivero92/HabboCafe/llms.txt

Use this file to discover all available pages before exploring further.

HADOS enforces a four-tier role-based access control (RBAC) model. Every user has a stored role written to their HabboUser.role field in Firestore, and an effective role computed at runtime by getActiveRole() for the currently selected Dado. These two values can differ: for example, a jugador whose stored role is jugador becomes effectively a dado_admin for a Dado where Dado.adminId matches their Firebase Auth UID.

Roles overview

global_admin

The highest privilege tier. Manages the entire HADOS instance — creates Dados, assigns Dado Admins, and can view all users across every Dado. Only one or a handful of trusted operators should hold this role.

dado_admin

Owner of a specific Dado. Configures tournament info, rules, schedule, prize pool, and qualifying count. Can reset tournament scores, promote players to intermediario, and demote them back to jugador.

intermediario

Tournament staff within a Dado. Can add new players manually and modify point totals, but cannot change any configuration or role assignments.

jugador

A regular tournament participant. Read-only access to the leaderboard and tournament info. Cannot modify any data.

Permissions matrix

Actionglobal_admindado_adminintermediariojugador
View leaderboard
View tournament info / rules / schedule
Add or subtract points
Create player (manual add)
Promote / demote roles (jugadorintermediario)
Configure tournament info, rules, schedule, prize
Reset tournament scores (start new tournament)
Create a new Dado
Assign a Dado Admin
View all users across all Dados

Role storage

The role field is stored directly on the HabboUser Firestore document:
// HabboUser interface (excerpt)
role: 'global_admin' | 'dado_admin' | 'intermediario' | 'jugador';
Path: /users/{userId} → field role This field is the source of truth for persistent, cross-session role identity. However, for any UI permission check within a session, the application always calls getActiveRole() rather than reading userProfile.role directly, because Dado Admin status is derived from Dado.adminId, not from the stored role field alone.

getActiveRole() — effective role resolution

getActiveRole() computes the caller’s effective role for the currently active Dado. It runs entirely on the client from data already held in React state (no extra Firestore reads):
const getActiveRole = (): 'global_admin' | 'dado_admin' | 'intermediario' | 'jugador' => {
  // 1. No profile loaded yet → default to jugador
  if (!userProfile) return 'jugador';

  // 2. Global Admin always wins regardless of active Dado
  if (userProfile.role === 'global_admin') return 'global_admin';

  // 3. If the active Dado's adminId matches the current Firebase Auth UID,
  //    the user is the Dado Admin for this Dado
  if (activeDado?.adminId === currentUser?.uid) return 'dado_admin';

  // 4. Look up the user's participation record for the active Dado.
  //    myParticipations is the result of:
  //      query(collection(db, 'users'), where('username', '==', userProfile.username))
  //    Each record carries its own `role` field for that Dado.
  const participation = myParticipations.find((p) => p.dadoId === activeDado?.id);
  if (participation) return participation.role;

  // 5. Fallback — user has no record in this Dado
  return 'jugador';
};

Resolution order

1

Check for loaded profile

If userProfile is null (auth still loading), return 'jugador' as a safe default.
2

Check for global_admin stored role

If userProfile.role === 'global_admin', return 'global_admin' immediately. This check cannot be overridden by any Dado-level state.
3

Check Dado.adminId

If activeDado.adminId equals currentUser.uid, return 'dado_admin'. This allows a user whose stored role is still 'jugador' to act as Dado Admin the moment the batch write sets Dado.adminId.
4

Check participation records

Query myParticipations for a record where dadoId matches the active Dado. If found, return that record’s role field ('intermediario' or 'jugador').
5

Fallback

If no participation record exists for this Dado, the user has no registered presence here — return 'jugador'.

canModifyPoints() — point-editing gate

All point-modification UI (quick +10 / +50 / -10 / -50 buttons, Cargar Puntos modal, and Crear Usuario modal) is gated behind this helper:
const canModifyPoints = (): boolean => {
  const role = getActiveRole();
  return ['global_admin', 'dado_admin', 'intermediario'].includes(role);
};
Returns true for global_admin, dado_admin, and intermediario. Returns false for jugador.

Role elevation flows

Global Admin assigns a Dado Admin

Only a global_admin can elevate a user to dado_admin. The operation is a batch write that atomically updates both the Dado document and the target HabboUser document:
const batch = writeBatch(db);

// Record the admin on the Dado
batch.update(doc(db, 'dados', dadoId), {
  adminId: adminUser.id,
  adminEmail: adminUser.email,
  adminName: adminUser.username,
});

// Elevate the user's stored role and tie them to the Dado
batch.update(doc(db, 'users', adminUser.id), {
  role: 'dado_admin',
  dadoId: dadoId,
});

await batch.commit();

Dado Admin and Global Admin promote/demote intermediarios

Both dado_admin and global_admin can toggle any jugador in the active Dado to intermediario (and back). The Intermediarios tab and the Dado Admin panel both gate this action behind getActiveRole() === 'global_admin' || getActiveRole() === 'dado_admin'. The write itself is a simple updateDoc:
// Promote to intermediario
await updateDoc(doc(db, 'users', userId), { role: 'intermediario' });

// Demote back to jugador
await updateDoc(doc(db, 'users', userId), { role: 'jugador' });
This operation is a single-document write — no batch required because only one document changes.
A dado_admin cannot be demoted through the HADOS UI. The Modificar Rol table in the Dado Admin panel renders "Propietario del Dado" (read-only text) for any user whose role === 'dado_admin', and exposes no demotion button. To demote a Dado Admin you must either use the Firebase console to edit the users document directly, or write a one-off admin script using the Firebase Admin SDK.

Special accounts

Auto-recovery for vasquezrivero92@gmail.comIf a user signs in with vasquezrivero92@gmail.com and their Firestore profile document does not exist (e.g. after a database wipe or accidental deletion), HADOS automatically synthesises a recovery profile with role: 'global_admin' and writes it to /users/{uid}. No other email address triggers this recovery path — all other missing profiles receive role: 'jugador'.
// Profile auto-recovery logic (App.tsx — onAuthStateChanged)
role: user.email === 'vasquezrivero92@gmail.com' ? 'global_admin' : 'jugador'

Global Admin self-registration

A user can self-register as a Global Admin during the sign-up flow by checking Registrar como Administrador Global and supplying the correct secret code (GLOBAL2026). If the code is wrong, the registration is rejected client-side before any Firebase Auth call is made.

Role colours in the UI

The navbar renders the effective role with a colour-coded label to help staff quickly identify their access level at a glance:
RoleColour
global_adminRed (#ef4444)
dado_adminGold (#ffd700)
intermediarioPurple (#9d4edd)
jugadorGrey (#8c8c9e)

Build docs developers (and LLMs) love