Files
osint_web/frontend
agent e792bc6e17 feat(calendar): vista mes/semana/día, TZ, selector de calendario, colores y CRUD de eventos
Backend (server/main.py):
- GET /api/calendars: lista las colecciones de calendario bajo el calendar-home
  con nombre y color (compone dav_list_calendars del registry).
- GET /api/calendar?cal=&from=&to=: eventos de una colección concreta (caché por
  colección validada por ctag). dtstart/dtend ahora en ISO con offset + tz
  original + all_day; parseo robusto de TZID/UTC/todo-el-día con zoneinfo.
- POST/PUT/DELETE /api/event[/<uid>]: CRUD de VEVENT contra Xandikos (fuente de
  verdad). Construye el VCALENDAR (con VTIMEZONE para zonas con DST), reutiliza el
  UID al editar (idempotente), trata 404 del DELETE como idempotente, invalida la
  caché de la colección tras escribir.

Frontend:
- CalendarView reescrita: conmutador Mes/Semana/Día con rejilla horaria propia
  (Mantine + dayjs, sin react-big-calendar para evitar fricción con React 19),
  mini-calendario de navegación, selector de calendario (con color), selector de
  zona horaria que recoloca los eventos, colores por evento (del VEVENT o del
  calendario).
- EventModal: alta/edición/borrado con summary, inicio/fin, todo-el-día, TZ,
  calendario, color, ubicación y descripción. Fechas en formato local 24h.
- calendar.ts: helpers de TZ (dayjs utc+timezone), posicionado por hora, semana
  empezando en lunes, locale es. api.ts: tipos y funciones de eventos/calendarios.

Verificado: ciclo real crear→editar→borrar contra Xandikos (cero residuo),
render del calendario en navegador (React 19 + Mantine v9 montan), pnpm build
verde, 40 tests verdes (+ smoke gateado). MKCALENDAR queda fuera (documentado).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 00:40:59 +02:00
..

Frontend de osint_web

Frontend web local del explorador OSINT. Lee el backend FastAPI (../server/main.py, escucha solo en 127.0.0.1:8470) y ofrece cinco vistas de lectura sobre el vault de Obsidian osint + la agenda/calendario del servidor Xandikos.

Stack

  • React 19 + Vite 6 + TypeScript + Mantine v9. Mantine v9 exige React 19 (con React 18 compila pero no monta — error "s is not a function"); por eso el package.json pina React 19. Iconos de @tabler/icons-react. Theming con createTheme() (src/theme.ts), sin Tailwind ni CSS variables custom (regla frontend_theming.md).
  • Grafo: sigma (v3) + graphology + graphology-layout-forceatlas2 (las únicas deps fuera de Mantine; KISS). Layout force-directed en un web worker (no bloquea la UI con 1199 nodos), pausable.
  • Markdown de las fichas con react-markdown. Calendario con @mantine/dates (que usa dayjs).
  • Vite proxya /apihttp://127.0.0.1:8470 en dev (sobrescribible con VITE_API_BASE).

Vistas

Vista Archivo Endpoint(s) Qué muestra
Grafo src/views/GraphView.tsx GET /api/graph, GET /api/search sigma.js force-directed; color por tipo, tamaño por grado; panel lateral con toggles de tipos + dangling + buscador (centra el nodo). Click en nodo → ficha. Layout pausable + reset de cámara.
Tablas src/views/TablesView.tsx GET /api/graph, GET /api/nodes?tipo= una pestaña por tipo real; Table Mantine con columnas deducidas del frontmatter, ordenable y filtrable. Click en fila → ficha.
Ficha src/views/NodeCard.tsx GET /api/node/<slug>, GET /api/attachment modal: frontmatter clave-valor (fechas europeas DD/MM/AAAA), cuerpo Markdown, galería de imágenes con lightbox, documentos/PDFs como enlace, wikilinks navegables.
Contactos src/views/ContactsView.tsx GET /api/contacts agenda: lista + buscador (nombre/alias/tel/email); detalle con teléfonos, correos, bloque osint (dni/país/sexo…) y nota.
Calendario src/views/CalendarView.tsx GET /api/calendar mini-calendario @mantine/dates con punto en días con eventos + lista de eventos del mes/día agrupados por fecha (hora local, lugar, descripción).

Botón global Refrescar (header) → POST /api/refresh + recarga de la vista activa.

Arrancar (dev)

Necesitas backend + frontend a la vez:

# Terminal 1 — backend (escucha solo en 127.0.0.1)
cd projects/osint/apps/osint_web
.venv/bin/python server/main.py --vault /home/enmanuel/Obsidian/osint --port 8470

# Terminal 2 — frontend
cd projects/osint/apps/osint_web/frontend
pnpm install        # primera vez
pnpm dev            # http://127.0.0.1:5173

Abrir http://127.0.0.1:5173. El proxy de Vite reenvía /api al backend, así que no hay que tocar CORS. Solo localhost (datos sensibles del vault: DNIs, fotos).

Build

cd projects/osint/apps/osint_web/frontend
pnpm install
pnpm build          # tsc -b && vite build → dist/

Gotcha pnpm 10/11 (esbuild)

pnpm bloquea por seguridad los scripts de build de dependencias. esbuild (el bundler nativo de Vite) necesita su postinstall. El pnpm-workspace.yaml lo permite con allowBuilds: { esbuild: true }. Si pnpm build falla con "esbuild ... was not found", ejecuta pnpm rebuild esbuild.

Notas

  • Grafo sin WebGL: si el navegador no expone WebGL (headless sin GPU), la vista Grafo muestra un aviso en vez de crashear; el resto de la app sigue funcionando.
  • Contactos/Calendario dependen del servidor Xandikos: si no responde, esas dos vistas muestran un aviso naranja y el grafo/tablas siguen operativos (offline).
  • Las fechas se presentan en europeo (src/format.ts): ISO de Obsidian 2026-06-0707/06/2026; iCal 20220829T133000Z → hora local 15:30.