The GCS virtual office implements a two-tier access model that combines a user’s role with a boolean eligibility flag. The role determines which rooms a user can enter once inside the office; the eligibility flag acts as a prerequisite gate — a user must pass it before any room is rendered at all. Both values are stored in the authenticatedDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/gcsconsultores/centros-estrategicos-gcs/llms.txt
Use this file to discover all available pages before exploring further.
User object managed by AuthContext and persisted to localStorage between sessions.
User Model
The full shape of an authenticated user is defined inlib/types.ts:
UserRole is a union of exactly two string literals:
cliente— External visitors, prospective customers, or existing clients accessing the office to explore services or run diagnostics.consultor— GCS internal team members who need unrestricted access to all rooms including private meeting and strategy spaces.
Room Access Types
Every room in theROOMS constant carries a type field of type RoomAccess:
| Room | RoomId | Access Type |
|---|---|---|
| Lobby Principal | lobby | public |
| Sala de Compliance | compliance | public |
| Sala de Innovación | innovacion | public |
| Sala Ejecutiva | ejecutiva | private |
| Sala de Estrategia | estrategia | private |
| Sala de Training | training | private |
consultor role.
Access Logic
Room-level access is evaluated insideVirtualOffice each time currentRoom changes. The relevant line from VirtualOffice.tsx is:
- Consultores —
user?.role === 'consultor'istrue, sohasAccessis alwaystrue. They can enter every room, including all private ones. - Clientes — Access is granted only when
currentRoomData.type === 'public'. Attempting to navigate to a private room renders the “No tienes acceso” error and a button to return to the Lobby.
The
Header and Lobby components apply the same role-based filter to their navigation items. A cliente user will not see private rooms in the nav bar or the Lobby card grid at all — so the access-denied screen is a fallback for direct URL manipulation or programmatic navigation rather than a primary UX path.Eligibility Gate
Theeligible boolean is checked in VirtualOffice before any room — including the Lobby — is rendered:
User object in localStorage) but whose eligible field is false see only this gate screen. The intended flow is that users complete the Revisoría Fiscal evaluation at /evaluacion, which sets eligible: true in their stored profile before they are admitted to the office.
Authentication Flow
Visit /login
The user navigates to
/login, which renders LoginPage — a centered card with GCS branding, a name text input, and a role selector.Enter name and select role
The user types their name and chooses either
cliente or consultor from the dropdown. Both options are available with no server-side validation at this stage.AuthContext.login() persists the User
Clicking Ingresar calls
login({ name, role, eligible }), which saves the User object to localStorage under the key 'user' and updates the in-memory user state.Redirect to / (the virtual office)
useRouter().push('/') sends the user to the root route, which mounts VirtualOffice.AuthContext API
All authentication state and actions are accessed via theuseAuth() hook exported from context/AuthContext.tsx:
| Value | Type | Description |
|---|---|---|
user | User | null | The currently authenticated user, or null if not logged in. |
loading | boolean | true while the initial localStorage read is in progress. Use this to avoid flash-of-unauthenticated-content on first render. |
login | (userData: User) => void | Persists the provided User to localStorage and sets it as the active user. |
logout | () => void | Removes 'user' from localStorage and sets user to null. |
Lobby component consumes both user and loading:
cliente user.
Extending Access Control
As the platform matures, you may need to add roles, granular permissions, or a backend-driven eligibility check. Here are the recommended extension points:- Add a new role — Extend the
UserRoleunion inlib/types.ts(e.g.'admin' | 'cliente' | 'consultor'), then update thehasAccessexpression inVirtualOfficeand the filter functions inHeaderandLobbyto handle the new value. - Per-room role requirements — Add an optional
requiredRole?: UserRolefield to theRoominterface inlib/types.ts, populate it inlib/constants.ts, and reference it in thehasAccesscheck instead of the hardcoded'consultor'string. - Backend eligibility check — In
AuthContext, replace thelocalStorage-onlyuseEffectwith an API call (e.g.GET /api/user/eligibility) that validates the stored session token and returns the currenteligiblestatus from a database or SharePoint list. - Session tokens — Store a JWT or Azure AD access token alongside the
Userobject inlocalStorage. Validate it server-side in each API route using the Microsoft Graph SDK that is already referenced inlib/types.tsvia theMSGraphConfiginterface.