Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Renzo717/Aula-Virtual-Universidad-Radiolocucion/llms.txt

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

NuestraVoz is organized as a pnpm monorepo with two applications and one shared library, all managed from a single repository. The workspace topology — declared in pnpm-workspace.yaml — ensures that internal packages resolve through pnpm’s workspace protocol rather than being published to a registry. This keeps types, validation schemas, and utility helpers in sync across the frontend and backend without any duplication.

Monorepo Layout

Aula-Virtual-Universidad-Radiolocucion/
├── apps/
│   ├── web/                  # @nuestravoz/web — Astro + React frontend
│   │   ├── src/
│   │   │   ├── pages/        # Astro SSR pages (.astro)
│   │   │   ├── components/   # React islands (.tsx)
│   │   │   └── layouts/      # Shared Astro layouts
│   │   └── astro.config.mjs  # Astro + Vite configuration
│   │
│   └── api/                  # @nuestravoz/api — Express.js REST API
│       ├── src/
│       │   ├── index.ts      # App bootstrap, middleware, route mounting
│       │   ├── lib/          # config, supabaseClient, auth helpers
│       │   └── routes/       # One file per domain (auth, aula, foro, …)
│       └── .env.example      # Environment variable template

├── packages/
│   └── shared/               # @nuestravoz/shared — Types + Zod schemas
│       └── src/
│           ├── types.ts       # Domain interfaces and type aliases
│           ├── schemas.ts     # Zod validation schemas + inferred types
│           ├── horarios.ts    # Schedule formatting and parsing helpers
│           ├── database.types.ts  # Auto-generated Supabase DB types
│           └── index.ts       # Re-exports for all of the above

├── supabase/
│   ├── config.toml            # Supabase CLI project config
│   └── migrations/            # Versioned SQL (001 → 019)
│       ├── 001_initial_schema.sql
│       ├── 002_fix_rls_policies.sql
│       ├── ...
│       └── 019_preceptor_notas_finales_write.sql

├── package.json               # Root scripts: dev, build, typecheck
└── pnpm-workspace.yaml        # Declares apps/* and packages/*

Package Roles

@nuestravoz/web — Astro + React Frontend

The web application is a server-side-rendered Astro site using the @astrojs/node adapter in standalone mode. Static shell pages (.astro) handle routing, authentication guards, and layout; interactive components (.tsx) are hydrated as React islands where needed. Key dependencies from apps/web/package.json:
PackageVersionPurpose
astro^5.5.3SSR framework + dev server
@astrojs/react^4.2.1React island integration
@astrojs/node^9.1.0Node.js standalone adapter
@astrojs/tailwind^6.0.0Tailwind CSS integration
react^19.0.0UI component library
@nuestravoz/sharedworkspace:*Local types and schemas
The Astro config sets output: 'server' (full SSR), runs on port 4321, and registers a Vite proxy that forwards every /api/* request to the Express server at http://localhost:3001.

@nuestravoz/api — Express.js REST API

The API is a standard Express.js + TypeScript server. It mounts the following route groups, each in its own file under src/routes/:
GET  /api/health              → liveness probe
/api/auth        → login, logout, session refresh
/api/users       → CRUD for platform users (admin only)
/api/carreras    → career management
/api/cursos      → course management
/api/inscripciones → enrollment management
/api/dashboard   → per-role dashboard stats
/api/aula        → classroom resources, activities, announcements
/api/foro        → discussion threads and replies
/api/perfil      → profile updates, password change
/api/finales     → final grade recording and retrieval
/api/boletines   → per-student academic bulletins
Middleware stack (in order):
  1. helmet — sets security-oriented HTTP headers; crossOriginResourcePolicy is set to cross-origin to allow Supabase Storage URLs.
  2. cors — restricts origins to the value of CORS_ORIGIN with credentials enabled, so cookies are sent cross-origin in production.
  3. express.json() — parses JSON request bodies.
  4. cookie-parser — parses the nv_session cookie used for session authentication.
Configuration is read from apps/api/.env through a lib/config.ts module that exports typed constants (config.port, config.corsOrigin, etc.).

@nuestravoz/shared — Shared TypeScript Library

packages/shared is the single source of truth for every type and validation rule consumed by both the frontend and the backend. Its src/index.ts re-exports four modules:
export * from './types.js';       // Domain interfaces
export * from './schemas.js';     // Zod schemas + inferred input types
export * from './horarios.js';    // Schedule formatting utilities
export type { Database } from './database.types.js'; // Supabase DB types
Domain types (types.ts) include: UserRole, UserStatus, CarreraTipo, Profile, AuthUser, Carrera, Materia, Curso, Inscripcion, Actividad, Entrega, ForoHilo, ForoRespuesta, NotaFinal, BoletinMateriaFila, DashboardStats, and many more. Zod schemas (schemas.ts) mirror every write operation — loginSchema, registerSchema, createUserSchema, createCarreraSchema, createMateriaSchema, createActividadSchema, upsertNotaFinalSchema, and so on. Each schema is paired with an inferred TypeScript input type (e.g. LoginInput, CreateUserInput) so both API route handlers and frontend form validation share identical rules. Schedule helpers (horarios.ts) provide formatHorarios, parseHorarioLegacy, horariosFromDb, and sanitizeHorarios — pure functions that normalize the HorarioCursado[] structure used across Materia and Curso records.

Data Flow

Browser

  │  HTTP request (fetch / form)

Astro SSR  (apps/web — port 4321)
  │  Server-renders pages with session cookie
  │  React islands hydrate interactivity client-side

  │  /api/* → Vite proxy (dev) / reverse proxy (prod)

Express API  (apps/api — port 3001)
  │  Validates session cookie → resolves AuthUser
  │  Parses + validates body with @nuestravoz/shared Zod schemas
  │  Executes business logic

  │  Supabase JS client (service-role key)

Supabase / PostgreSQL
  │  Row Level Security enforced at DB layer
  │  Storage buckets for file uploads (resources, activity submissions)
  │  19 versioned migrations track schema evolution
The browser communicates exclusively with the Astro server. In SSR pages, the Astro server calls the Express API directly (server-to-server). In React islands, the browser calls /api/* which is proxied to Express. The Supabase service-role key never reaches the browser.

Supabase: Auth, Storage, and RLS

Supabase serves three roles in the platform: PostgreSQL database — All application data lives in Supabase’s managed Postgres. The database.types.ts file (auto-generated by the Supabase CLI) provides fully-typed table and view definitions consumed by both the API and the shared package. Row Level Security — RLS policies (first introduced in migration 002_fix_rls_policies.sql and refined through 010_preceptor_role.sql) enforce per-role visibility at the database layer. Even if the API were compromised, users could only read and write rows their role is authorized for. Supabase Storage — Activity material attachments, student submission files, and resource documents are stored in Supabase Storage buckets. The API uploads files server-side using the service-role key and returns signed or public URLs to the frontend. Versioned Migrations — The supabase/migrations/ directory contains 19 sequential SQL files. Notable milestones include the initial schema (001), preceptor role addition (010), final grades (011, 016, 017), subject-in-courses relationship (018), and the most recent preceptor write-access grant (019_preceptor_notas_finales_write.sql).

pnpm Workspace Configuration

The pnpm-workspace.yaml at the repo root declares which directories are workspace packages:
packages:
  - apps/*
  - packages/*

allowBuilds:
  esbuild: true
  sharp: true

onlyBuiltDependencies:
  - esbuild
  - sharp
The allowBuilds and onlyBuiltDependencies keys restrict native build scripts to esbuild (used by the API’s TypeScript compilation) and sharp (used by Astro for image optimization), improving install security and reproducibility. The root package.json dev script compiles the shared package before launching servers in parallel:
{
  "scripts": {
    "dev": "pnpm --filter @nuestravoz/shared build && pnpm -r --parallel dev",
    "build": "pnpm -r build",
    "typecheck": "pnpm -r typecheck"
  }
}
This guarantees that both @nuestravoz/web and @nuestravoz/api import freshly-built type declarations from packages/shared/dist/ at startup.

Further Reading

Quickstart

Step-by-step instructions to clone, configure, seed, and run the platform locally in under 10 minutes.

Introduction

Overview of the platform’s four user roles, core capabilities, and feature set.

Build docs developers (and LLMs) love