Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Edfermachado/proyectoSistemas/llms.txt

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

UniEvents is built around a two-level multi-tenant hierarchy. At the top sits a University — the institutional anchor that groups together a set of faculties or organizations. Below it are Tenants, each representing an individual faculty, club, or department. Every tenant owns its own users, physical spaces, and events, yet is always traceable back to its parent university. This separation lets a single UniEvents deployment serve an entire institution while keeping each faculty’s data cleanly isolated.

Universities

A university is the top-level public entity in the system. It acts as the discovery layer: visitors can browse /universities/[slug] to explore all the faculties and events that belong to it.
FieldTypeNotes
iduuidPrimary key, auto-generated
namevarchar(255)Unique display name
slugvarchar(300)URL-safe identifier, unique
descriptiontextOptional public description
logoUrlvarchar(500)Link to the institution’s logo
createdAttimestampAuto-set on creation
// src/db/schema.ts
export const universities = pgTable('universities', {
  id: uuid('id').primaryKey().defaultRandom(),
  name: varchar('name', { length: 255 }).notNull().unique(),
  slug: varchar('slug', { length: 300 }).unique(),
  description: text('description'),
  logoUrl: varchar('logo_url', { length: 500 }),
  createdAt: timestamp('created_at').defaultNow(),
});

Tenants (Faculties)

A tenant maps to a single faculty, club, or organizational unit within a university. Each tenant belongs to exactly one university and one category (e.g., Engineering, Sports, Cultural). Tenant-scoped data — users, spaces, and events — is always filtered by tenantId, making the boundary of each faculty’s data explicit at the database layer.
FieldTypeNotes
iduuidPrimary key, auto-generated
namevarchar(255)Unique display name
slugvarchar(300)URL-safe identifier, unique
descriptiontextOptional public description
universityIduuidFK → universities.id
categoryIduuidFK → categories.id
createdAttimestampAuto-set on creation
// src/db/schema.ts
export const tenants = pgTable('tenants', {
  id: uuid('id').primaryKey().defaultRandom(),
  name: varchar('name', { length: 255 }).notNull().unique(),
  slug: varchar('slug', { length: 300 }).unique(),
  description: text('description'),
  universityId: uuid('university_id').references(() => universities.id),
  categoryId: uuid('category_id').references(() => categories.id),
  createdAt: timestamp('created_at').defaultNow(),
});
Drizzle relations make the full tenant graph traversable in a single query:
// src/db/schema.ts — Tenant relations
export const tenantsRelations = relations(tenants, ({ one, many }) => ({
  university: one(universities, {
    fields: [tenants.universityId],
    references: [universities.id],
  }),
  category: one(categories, {
    fields: [tenants.categoryId],
    references: [categories.id],
  }),
  users: many(users),
  spaces: many(spaces),
  events: many(events),
}));

Categories

Categories classify tenants so that events can be browsed by faculty type. A superadmin manages categories globally from the /admin portal.
FieldTypeNotes
iduuidPrimary key, auto-generated
namevarchar(255)Unique category name (e.g., “Engineering”)
slugvarchar(300)URL-safe identifier, unique
iconvarchar(100)Material Symbols icon name
createdAttimestampAuto-set on creation
// src/db/schema.ts
export const categories = pgTable('categories', {
  id: uuid('id').primaryKey().defaultRandom(),
  name: varchar('name', { length: 255 }).notNull().unique(),
  slug: varchar('slug', { length: 300 }).unique(),
  icon: varchar('icon', { length: 100 }), // Material Symbols icon name
  createdAt: timestamp('created_at').defaultNow(),
});
The icon field stores the raw icon name from the Material Symbols library (e.g., "school", "sports_soccer", "palette"). The front-end renders it directly inside a <span class="material-symbols-outlined"> element.

Slug-Based Routing

Both universities and tenants expose human-readable URL slugs that are auto-generated from their name field at creation time (and regenerated on rename). The slug is guaranteed to be unique within its table.

University pages

Public university landing pages are served at /universities/[slug], listing all tenants and featured events for that institution.

Faculty event filtering

Event listings can be scoped to a specific faculty by passing its slug as a query filter, so students can browse only their faculty’s upcoming events.
Slugs are generated by a shared generateUniqueSlug helper that appends a numeric suffix when a collision is detected, guaranteeing uniqueness even for faculties with identical names across different universities.

Data Hierarchy at a Glance

The full ownership chain flows like this:
University (1)
└── Tenants / Faculties (many)
    ├── Users (many)        ← scoped by tenantId
    ├── Spaces (many)       ← physical venues
    └── Events (many)
        └── Attendees (many)
LevelTableKey relationship
InstitutionuniversitiesRoot entity
Faculty/ClubtenantsuniversityId → universities.id
VenuespacestenantId → tenants.id
EventeventstenantId → tenants.id, spaceId → spaces.id
Staff/StudentuserstenantId → tenants.id (null for superadmin)
RegistrationattendeeseventId → events.id, userId → users.id

Build docs developers (and LLMs) love