# napi — Retroalimentación Personalizada a Estudiantes

## ✅ Estado: PRODUCCIÓN — 2 grupos activos (2026-02-25)

---

## Contexto

Proyecto minimalista para proporcionar retroalimentación personalizada a los estudiantes, cerrando el bucle profesor → alumno.

El profesor (Fénix) mantiene ficheros `notas.md` por alumno con:
- Tabla resumen de todas las prácticas (nota + estado)
- Feedback detallado por práctica
- Próximos pasos concretos

Los alumnos acceden desde cualquier dispositivo con su navegador, sin instalar nada.

**Sin backend. Sin base de datos. Sin framework. Sin CDN.**

---

## Grupos Activos

| Grupo | URL | Alumnos | Datos local | Datos zzz |
|:------|:----|:-------:|:------------|:----------|
| **DDAW2** | `https://notas.qu3v3d0.tech` | 19 | `~/napi-data/` | `/var/www/napi/data/` |
| **ASIR1** | `https://asir1.qu3v3d0.tech` | 21 | `~/napi-data2/` | `/var/www/napi2/data/` |

---

## Arquitectura

```
PROFESOR (aldebaran / anka4)         SERVIDOR (zzz / qu3v3d0.tech)
────────────────────────────         ─────────────────────────────
~/napi-data/   ←── sshfs ──→  /var/www/napi/data/   (DDAW2, 19 alumnos)
~/napi-data2/  ←── sshfs ──→  /var/www/napi2/data/  (ASIR1, 21 alumnos)

                                     /var/www/napi[2]/
                                       ├── viewer.html
                                       ├── marked.min.js
                                       └── twemoji.min.js

                                     Nginx + auth_pam → $remote_user
                                       → data/$remote_user/notas.md
                                       → viewer.html renderiza con marked.js
```

### Stack

| Componente | Tecnología | Dónde |
|:-----------|:-----------|:------|
| **Datos** | Ficheros `notas.md` (Markdown) | zzz |
| **Transporte** | sshfs mounts persistentes (systemd) | aldebaran/anka4 → zzz |
| **Servidor web** | Nginx (1 server block por grupo) | zzz |
| **Autenticación** | `libnginx-mod-http-auth-pam` | zzz |
| **Renderer** | `marked.min.js` + `twemoji.min.js` + `viewer.html` | zzz |
| **Notificaciones DDAW2** | `nginx-user-config-watcher.sh` (v3) + XMPP | zzz |
| **Notificaciones ASIR1** | `python-upload-watcher.sh` (v7) + XMPP | zzz |
| **SSL** | Certificado wildcard `*.qu3v3d0.tech` | zzz |

---

## Alumnos

### DDAW2 (19) — usernames = nombre de pila

```
anas, carlos, carlosv, daniel, danieln, erick, evelin, gianfranco,
giorgio, joel, jorge, josue, juanan, juanjesus, kasandra, marius,
miguel, pablo, patrick
```

SFTP chroot: `/home/USER/html/`

### ASIR1 (21) — usernames = apellido en minúsculas

```
barja, barrios, cayo, contrera, duque, florea, gomes, izquierdo,
jara, lillo, linares, macedo, martinez, munoz, olcina, ponce,
posada, quiroz, reynoso, sierra, torrero
```

SFTP chroot: `/home/USER/python/` · Contraseñas: leet-speak (`a→4, e→3, i→1, o→0`)

---

## SSH / Conexión a zzz

```bash
ssh fenix@qu3v3d0.tech   # clave sin -i, fenix tiene sudo
```

---

## Ficheros Clave

### En zzz

| Ruta | Descripción |
|:-----|:------------|
| `/var/www/napi/` | App DDAW2 (viewer + marked + twemoji + data/) |
| `/var/www/napi2/` | App ASIR1 (idem) |
| `/etc/nginx/sites-enabled/napi` | Server block DDAW2 |
| `/etc/nginx/sites-enabled/napi2` | Server block ASIR1 |
| `/usr/local/bin/python-upload-watcher.sh` | Watcher ASIR1 (v7) |
| `/usr/local/bin/nginx-user-config-watcher.sh` | Watcher DDAW2 (v3) |
| `/usr/local/bin/xmpp-notify.py` | Bot XMPP one-shot |

### En aldebaran/anka4

| Ruta | Descripción |
|:-----|:------------|
| `~/napi-data/` | sshfs → DDAW2 data |
| `~/napi-data2/` | sshfs → ASIR1 data |
| `~/.config/systemd/user/home-fenix-napi\x2ddata.mount` | Mount DDAW2 |
| `~/.config/systemd/user/home-fenix-napi\x2ddata2.mount` | Mount ASIR1 |

---

## Pendiente

- [ ] Renovar certificado SSL wildcard cuando expire (generado 2026-02-04, válido 365 días)
