Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/danitocsc/transporte-unrc-web-public/llms.txt

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

Transporte Tijuana es un sitio de transparencia pública. Toda la información que se presenta en él proviene de una encuesta voluntaria respondida por 192 estudiantes de UNRC Unidad Tijuana. Dado que esas respuestas incluyen campos sensibles —como la dirección de origen o la matrícula— el proyecto aplica tres capas de protección antes de que cualquier dato llegue al navegador del visitante. Esta página documenta cada una de esas capas, qué campos se publican, cuáles se retienen, y qué controles técnicos adicionales se aplican a nivel de servidor y cabeceras HTTP.

Garantía principal

Ningún nombre, correo, teléfono, matrícula ni dirección exacta de ningún estudiante aparece en ningún archivo público, en ninguna ruta de la API ni en ningún archivo del repositorio público.
El README del proyecto lo establece de manera explícita:
“No se expone en ningún lugar la matrícula, nombres, correos o direcciones exactas de los estudiantes.”
Y la sección de metodología del summary.json lo reitera punto a punto:
"methodology": [
  "La base original se conserva para analisis interno y la publicacion web solo usa datos anonimizados.",
  "Las coordenadas publicas usan jitter determinista para evitar exponer puntos exactos de origen.",
  "Los agregados de turnos, dias, colonias y sugerencias se calculan sobre la encuesta completa procesada.",
  "No se publican nombres, apellidos, correos, telefonos, matriculas ni enlaces de mapas compartidos por estudiantes."
]

Las tres capas de protección

Capa 1 — Filtrado de campos

El tipo interno SurveyRecord (definido en web/types/transport.ts) modela la estructura del dataset en crudo:
export interface SurveyRecord {
  matricula: string;         // nunca publicado
  turno: Turno | null;
  dias_asistencia: string | null;
  licenciatura: string | null;
  lugar_origen: string | null; // nunca publicado
  lat: number | null;          // nunca publicado
  lng: number | null;          // nunca publicado
}
Los campos matricula, lugar_origen, lat y lng son procesados únicamente por el script Python interno. No se escriben en ningún archivo dentro de web/public/. Lo que llega al cliente es el tipo PublicPoint, que solo retiene datos de colonia, turno, días, licenciatura y coordenadas desplazadas.

Capa 2 — Jitter de coordenadas

El campo lat_publica y lon_publica en PublicPoint no son las coordenadas reales geocodificadas a partir de la dirección del estudiante. El script de procesamiento aplica un desplazamiento aleatorio (jitter) de unos metros antes de escribir los archivos JSON de salida.
export interface PublicPoint {
  // ...
  lat_publica: number;               // coordenada real + jitter aleatorio
  lon_publica: number;               // coordenada real + jitter aleatorio
  fuente_coordenada_publica: string; // p. ej. "nominatim"
  // ...
}
El campo fuente_coordenada_publica indica solamente el proveedor de geocodificación (por ejemplo "nominatim"), no la cadena de dirección original que fue geocodificada. Esto impide la ingeniería inversa de las direcciones a partir de las coordenadas expuestas.

Capa 3 — Sanitización en servidor (SSR)

La ruta /mapa-demanda está marcada como force-dynamic y ejecuta su lógica exclusivamente en el servidor. El código en web/app/mapa-demanda/page.tsx lee paradas.json y aplica un .map() explícito que selecciona únicamente los campos necesarios para la UI:
// web/app/mapa-demanda/page.tsx
export const dynamic = 'force-dynamic';

const stops = (stopsRaw.stops ?? [])
  .filter((s: any) => s.active)
  .map((s: any) => ({
    id: s.id,
    name: s.name,
    lat: s.lat,
    lng: s.lng,
    route_id: s.route_id,
    turno: s.turno,
    dias_raw: s.dias_raw,
  }));
El arreglo students[] —si existiera en el JSON fuente— nunca se pasa al componente cliente. Solo llegan al navegador los siete campos explícitamente enumerados arriba.

Qué se publica vs. qué se protege

Datos públicos

Los siguientes datos son accesibles libremente en el sitio y en los archivos descargables:
DatoDónde aparece
Estadísticas de turnos, días y colonias/informe, summary.json
Puntos de densidad en el mapa (con jitter)/informe, map_points.json
Sugerencias textuales anónimas (sin nombre ni matrícula)/informe, summary.json
Paradas y rutas piloto propuestas/mapa-demanda, paradas.json, custom_routes.json
Reporte PDF con análisis completo/downloads/reporte-demanda-transporte.pdf
Dataset descargable de puntos anonimizados/downloads/public_points.csv

Datos protegidos

Los siguientes datos existen únicamente en el dataset interno y no aparecen en ningún recurso público:
DatoMotivo de protección
Matrícula del estudianteIdentificador personal directo
Nombre, apellido o correoIdentificadores personales directos
TeléfonoIdentificador personal directo
Dirección exacta de origen (lugar_origen)Información domiciliaria sensible
Coordenadas GPS reales (lat, lng)Permiten deducir el domicilio exacto
Enlaces de Google Maps compartidos por estudiantesReferencian ubicaciones domiciliarias precisas

Cabeceras de seguridad HTTP

El archivo web/next.config.ts configura las siguientes cabeceras en todas las rutas del sitio (/(.*)):
// web/next.config.ts
async headers() {
  return [
    {
      source: "/(.*)",
      headers: [
        { key: "X-Frame-Options",           value: "DENY" },
        { key: "X-Content-Type-Options",     value: "nosniff" },
        { key: "Referrer-Policy",            value: "strict-origin-when-cross-origin" },
        { key: "Permissions-Policy",         value: "geolocation=(self)" },
      ],
    },
  ];
},
CabeceraValorEfecto
X-Frame-OptionsDENYImpide que el sitio sea incrustado en iframes externos, bloqueando ataques de clickjacking.
X-Content-Type-OptionsnosniffPreviene que el navegador interprete recursos con un tipo MIME diferente al declarado.
Referrer-Policystrict-origin-when-cross-originLimita la información de referrer enviada a dominios externos; envía solo el origen (sin path ni query).
Permissions-Policygeolocation=(self)Restringe el acceso a la API de geolocalización del navegador al propio origen; los scripts de terceros no pueden solicitarla.

Aviso para colaboradores

Nunca incluyas datos crudos de encuesta en el repositorio público. Los archivos que contienen la hoja de cálculo original, cualquier exportación directa de Google Forms, o cualquier dataset que incluya matricula, lugar_origen, lat real o lng real deben mantenerse fuera del repositorio de forma permanente.El repositorio público (transporte-unrc-web-public) solo debe contener los archivos JSON ya procesados y anonimizados dentro de web/public/data/. Si necesitas regenerar esos archivos, hazlo localmente con el script de procesamiento interno y copia únicamente los artefactos de salida.

Build docs developers (and LLMs) love