# 🎨 vibe code: tu propio panel de administración

> **Copia este prompt completo, pégalo en ChatGPT, Claude, Gemini o el agente
> que uses, y genera tu dashboard admin autónomo en 5 segundos.**
>
> Después ábrelo en el navegador, pon tu `psk_` y manejas todo desde ahí.
> Quieres cambiar colores, mover weás, agregar secciones? Dile al mismo agente.
> Es **tu** panel, personalízalo como quieras.

---

```
Eres un ingeniero frontend. Genera un archivo HTML único (con CSS y JS
inline) que sea un dashboard de administración completo para el servicio
personnn-verificador (registro de consentimientos Ley 21.719, Chile).

El usuario tiene una API key de administración que empieza con "psk_" y
el endpoint base es https://verificador.personnn.com.

TODOS los llamados llevan el header:
  X-API-Key: psk_...

---

END POINTS DISPONIBLES:

GET /v1/consents/{id}/certificate.pdf
  Certificado PDF imprimible de un evento (hashes, sello RFC 3161,
  instrucciones de verificación). Content-Type application/pdf.

GET /v1/consents?subject_id={id}
  Historial de consentimientos de un usuario. Opcional &status=true para
  estado vigente por versión. Muestra id, terms_version, action, purposes,
  accepted_at, chain_index, evidence_hash, doc_type.

GET /v1/permissions?subject_id={id}
  Permisos granulares por propósito. Opcional &purpose=xxx para check
  booleano {granted: true/false}.

POST /v1/terms
  Registrar documento: body {version, type, content, url?}.
  type: tyc | consentimiento | privacidad | mandato | otro.
  content se hashea automáticamente.

GET /v1/terms
  Lista documentos registrados (version, type, sha256, url, created_at).

GET /v1/report?from=YYYY-MM-DD&to=YYYY-MM-DD
  Agregados por día × versión × acción.

GET /v1/usage
  Eventos por mes + créditos restantes ({months: [{month, events}],
  credits_remaining: number|"unlimited"}).

GET /v1/verify
  Recomputa la cadena de hashes. Responde {valid: bool, checked: int,
  broken_at: string|null}.

GET /v1/whoami
  Identidad de la cuenta: {tenant, email, origins, credits_remaining,
  created_at}. Úsalo al cargar para mostrar de quién es la key.

GET /v1/origins
  Dominios actualmente permitidos: {origins: [...]}. Cárgalo ANTES de
  pedir al usuario que escriba dominios — normalmente ya están fijados.

POST /v1/origins
  Restringir dominios: body {origins: ["https://tusitio.cl"]}.
  Vacío = cualquiera (solo desarrollo).

POST /v1/erasure
  Derecho de supresión: body {subject_id}. Tombstonea PII conservando
  la cadena verificable.

GET /v1/anchors
  Sellos RFC 3161. Cada anchor tiene id, chain_index, chain_hash,
  anchored_at, chain_matches (bool).

GET /v1/anchors/{id}/token
  Descarga el token .tsr para verificación independiente.

GET /v1/audit
  Historial de accesos admin de la cuenta (últimos 100): id, ip, method,
  path, new_ip (bool), created_at. new_ip=true significa que la psk_ se
  usó desde una IP nunca antes vista para este tenant — muéstralo como
  alerta de seguridad destacada.

NOTAS LEGALES IMPORTANTES:
- La ley 21.719 presume NO libre el consentimiento si va dentro del
  contrato. Por eso hay tipos separados: "tyc" y "consentimiento".
- Cada propósito (purpose) es un scope revocable individualmente.
- La supresión (erasure) no destruye la cadena, solo borra PII.
- verify revisa que nadie haya alterado los registros.

---

DISEÑO:
- UI moderna, limpia, modo oscuro por defecto con toggle a claro.
- Sidebar con secciones: Dashboard, Consents, Documentos, Reportes,
  Seguridad, Supresión, Anclajes.
- Arriba a la derecha: input para la psk_ y botón "Conectar".
- SEGURIDAD (reglas INNEGOCIABLES sobre la psk_):
  * La psk_ se pide en CADA sesión y vive SOLO en una variable en memoria.
    PROHIBIDO guardarla en localStorage, sessionStorage, cookies o IndexedDB:
    este archivo puede ser compartido o subido a un hosting, y una key
    persistida en él queda expuesta a cualquiera que lo abra.
  * Al abrir el archivo, la primera pantalla es SOLO el campo de la psk_
    (type="password", autocomplete="off") — sin key no se ve nada más.
  * Botón "Cerrar sesión" que borra la variable y recarga la página.
  * Banner permanente arriba: "⚠️ NUNCA subas este archivo a internet ni lo
    compartas con tu psk_ dentro — úsalo solo en tu computador".
- Diseño responsive, que funcione en celular también.

CADA SECCIÓN:

1. DASHBOARD (resumen):
   - Tarjetas con: total consents, créditos restantes, última verificación,
     documentos registrados.
   - Llamar a /v1/usage, /v1/terms, /v1/verify al cargar.

2. CONSENTS:
   - Input de subject_id + botón "Buscar".
   - Tabla con resultados: id, version, action, purposes, accepted_at,
     evidence_hash (truncado), chain_index.
   - Botón "Certificado PDF" por fila → abre
     GET /v1/consents/{id}/certificate.pdf (documento imprimible con el
     sello RFC 3161, para presentar en una fiscalización).
   - Botón "Ver estado vigente" que llama con &status=true.
   - Botón "Permisos" que abre modal con /v1/permissions.

2b. PERMISOS GRANULARES (KYC / scopes):
   - Input subject_id + botón "Consultar permisos" → GET /v1/permissions.
   - Muestra, por versión de documento, los scopes VIGENTES como chips
     (ej. kyc:email, kyc:foto). "*" significa consentimiento total.
   - Verificador puntual: input de un purpose (ej. kyc:rut) + botón
     "¿Autorizado?" → GET /v1/permissions?subject_id=X&purpose=Y, muestra
     semáforo verde (granted: true) / rojo (false).
   - Botón "Revocar scope" al lado de cada chip → POST /v1/consents con
     {subject_id, terms_version, action:"revoke", purposes:[ese scope]}
     (la psk_ también puede registrar consents). Confirmación antes.
   - Explica en un tooltip: los purposes son scopes revocables por
     atributo — el caso KYC: autorizar email+rut+foto y revocar solo uno.

3. DOCUMENTOS:
   - Tabla de /v1/terms: version, type, sha256, url, created_at.
   - Formulario para registrar nuevo documento: version, type (select),
     content (textarea), url.
   - Botón "Registrar" → POST /v1/terms.

4. REPORTES:
   - Date pickers: desde / hasta.
   - Tabla: día, versión, acción, total.
   - Total general abajo.

5. SEGURIDAD (origins + auditoría):
   - Input para agregar origins (uno por línea).
   - Lista actual con botón "Eliminar" al lado de cada uno.
   - Botón "Guardar" → POST /v1/origins.
   - Tabla de /v1/audit: fecha, IP, método, ruta. Las filas con
     new_ip=true destacadas en rojo/ámbar con aviso "psk_ usada desde
     IP nueva".

6. SUPRESIÓN (erasure):
   - Input subject_id + botón "Ejecutar supresión".
   - Confirmación antes de borrar.
   - Muestra resultado: erased_events, erasure_id, erased_at.

7. ANCLAJES (anchors):
   - Tabla de /v1/anchors: id, chain_index, anchored_at, chain_matches
     (check verde/rojo).
   - Botón "Descargar token" al lado de cada uno.
   - Tooltip/explicación de qué es RFC 3161.

REQUISITOS TÉCNICOS:
- Sin frameworks ni librerías externas (HTML + CSS + vanilla JS).
- CSS Grid/Flexbox para layout.
- Fetch API para los llamados HTTP.
- Manejo de errores: si la API responde error, mostrarlo en UI.
- Loader/spinner mientras carga.
- La psk_ NUNCA en localStorage/sessionStorage/cookies: pedirla cada vez
  (ver reglas de SEGURIDAD arriba). Sin persistencia de la key en ningún caso.
- El panel debe funcionar standalone: solo un archivo .html que el
  usuario abre LOCALMENTE en su navegador (file://). Nada de servidor.

Cuando termines, devuélveme SOLO el código HTML completo listo para
guardar y abrir. No expliques nada, solo el código.
```

---

Una vez que el agente te entregue el HTML, guárdalo como
`dashboard-admin.html` y ábrelo EN TU COMPUTADOR (doble click, file://).
Pegas tu `psk_` cada vez que lo uses — el panel no la guarda a propósito.

**⛔ Nunca subas este archivo a internet** (ni tu sitio, ni GitHub Pages, ni
un bucket, ni se lo mandes a nadie con la key dentro). Es una herramienta
local, como tu gestor de contraseñas.

**Quieres cambiar algo?** Dile a tu agente: *"agrega un gráfico de
uso en el dashboard"*, *"cambia el color a naranjo"*, *"agrega una
sección de export CSV"*. Cada vez que quieras, pega de nuevo el
prompt completo + tu instrucción.

---

Hecho en Chile por Personnn — https://personnn.com — soporte: niccolas@azomland.com
