Portal interno INSTA: base de conocimiento con Magic Login y permisos por rol
Base de conocimiento para el personal del Instituto Santiago Tapia: oferta educativa (en tarjetas y en tabla), requisitos y titulacion, becas y fechas de inscripcion, links de clases de Google Meet, preguntas frecuentes, mensajes listos y datos del instituto. Acceso con Magic Login: enlace de un solo uso, 15 minutos de vigencia, y en la base solo se guarda el SHA-256 del token. El canje es atomico, asi que dos canjes simultaneos del mismo enlace no pueden crear dos sesiones. Tres roles con 19 permisos. El catalogo lo edita direccion; los links de clases, direccion y administracion; el resto del equipo consulta. El menu se pinta con lo que el servidor autoriza y cada endpoint exige la misma clave, asi que no hay pantallas alcanzables escribiendo la direccion a mano. Toda edicion pasa por una lista blanca de campos validados y queda en la bitacora. Un precio vacio no se guarda como cero, un link que no es una direccion se rechaza, y no se puede marcar una validez oficial como confirmada sin numero de acuerdo. Pensado para leerse comodo: texto de 17 px, contraste AA, areas de toque de 44 px, tema claro y bloques plegados en telefono. La oferta, los costos, las becas, los requisitos y el contacto son los reales del instituto, tomados del CSV de oferta educativa y de la base de conocimiento. Los usuarios de acceso y los links de Meet son de demostracion. Verificado: 103 comprobaciones de API y 51 pruebas en WebKit escritorio y iPhone 13. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
+36
@@ -0,0 +1,36 @@
|
||||
# =====================================================================
|
||||
# Portal interno INSTA
|
||||
# Node 22 sobre Alpine. Sin paso de compilación: el portal se sirve tal
|
||||
# como está en public/, así que la imagen solo instala las dos
|
||||
# dependencias de producción (express y mysql2).
|
||||
# =====================================================================
|
||||
FROM node:22-alpine
|
||||
|
||||
# curl para el healthcheck; tini para que las señales lleguen bien.
|
||||
RUN apk add --no-cache curl tini
|
||||
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
|
||||
# Las dependencias van primero para aprovechar la caché de capas: solo se
|
||||
# reinstalan cuando cambia el manifiesto, no en cada cambio de código.
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci --omit=dev && npm cache clean --force
|
||||
|
||||
COPY server ./server
|
||||
COPY db ./db
|
||||
COPY public ./public
|
||||
|
||||
# El puerto real del portal. Traefik apunta aquí; nunca se publica 80 ni 443.
|
||||
ENV PORT=4180
|
||||
EXPOSE 4180
|
||||
|
||||
# No corre como root.
|
||||
USER node
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=25s --retries=3 \
|
||||
CMD curl -fsS http://127.0.0.1:4180/salud || exit 1
|
||||
|
||||
ENTRYPOINT ["/sbin/tini", "--"]
|
||||
# arranque.mjs espera a MySQL, siembra si hace falta y levanta el servidor.
|
||||
CMD ["node", "db/arranque.mjs"]
|
||||
Reference in New Issue
Block a user