=============================================================== CAMBIO TRAZABILIDAD DE INVITES (commit 0fc10be) =============================================================== PROBLEMA QUE RESUELVE: El sistema original no tenia manera de saber: - Quien genero un invite de tribe - Cuando se uso un invite - Quien uso el invite para entrar Para pubs SSB, la aceptacion de invite no dejaba ningun rastro en el log SSB propio. -------------------------------------------------------------- PARTE 1 — TRIBE INVITES: inviteLog en tribes_model.js -------------------------------------------------------------- ARCHIVO: src/models/tribes_model.js ESTRUCTURA inviteLog (nueva): Array de objetos almacenado en el contenido del mensaje SSB del tribe. Cada entrada: { code: string (hex, 64 chars, el mismo que va en tribe.invites[]) generatedBy: string (SSB ID del usuario que genero el invite) generatedAt: string (ISO 8601) status: 'pending' | 'used' usedBy: string | null (SSB ID del usuario que entro con el codigo) usedAt: string | null (ISO 8601) } FUNCION generateInvite (linea 95): - Genera code con: crypto.randomBytes(INVITE_CODE_BYTES).toString('hex') - Lee el inviteLog actual del tribe (o [] si no existe) - Añade nueva entrada con status 'pending', usedBy/usedAt null - Guarda inviteLog junto al array invites (que ya existia) - El array invites[] sigue existiendo tal cual para la logica de join FUNCION joinByInvite (linea 132): - Busca el tribe que tiene ese code en su invites[] - Actualiza el inviteLog mapeando: si entry.code === code, marca status 'used', usedBy = userId, usedAt = now - Elimina el code de invites[] (el code queda consumido, no reutilizable) - Guarda members, invites y inviteLog juntos en una sola llamada updateTribeById FUNCIONES getTribeById / listAll: Ambas ya exponían los campos del tribe. Se añadio: inviteLog: Array.isArray(c.inviteLog) ? c.inviteLog : [] Si el tribe fue creado antes de este cambio, inviteLog sera []. DONDE SE GUARDA ESTO: El inviteLog se guarda en el contenido del mensaje SSB de actualizacion del tribe (via updateTribeById que hace ssb.publish({type:'tribe', ...})). Es decir, el log de invites esta en la blockchain SSB como parte del historial del tribe. NOTA: si alguien lee el SSB log directamente, vera el inviteLog serializado en el campo content del mensaje. -------------------------------------------------------------- PARTE 2 — PUB INVITES: SSB message en main_models.js -------------------------------------------------------------- ARCHIVO: src/models/main_models.js PROBLEMA ORIGINAL: ssb.invite.accept() es una llamada de bajo nivel del protocolo SSB. Hace el handshake de red pero NO publica ningun mensaje en tu log propio. No hay manera de saber despues que aceptaste ese pub invite. SOLUCION: Inmediatamente despues del handshake exitoso, publicar manualmente un mensaje SSB en el log propio: FUNCION acceptInvite (linea 722): 1. Convierte el invite string con toLegacyInvite() 2. Hace ssb.invite.accept(code, callback) — el handshake real 3. Parsea el code con parseRemote() para extraer host y pubId (parseRemote ya existia en main_models.js, linea 119) 4. Publica: ssb.publish({ type: 'pub-invite', pubHost, pubKey, acceptedAt }) 5. Devuelve el resultado del handshake ESTRUCTURA del mensaje SSB publicado: { type: 'pub-invite' pubHost: string | null (ej: 'pub.miservidor.net:8008') pubKey: string | null (ej: '@xxxx.ed25519') acceptedAt: string (ISO 8601) } Si parseRemote no puede extraer host o pubId, guarda null. No rompe el flujo (el await del publish usa resolve() en ambos casos). DONDE APARECE ESTO: En el blockchain explorer, en el filtro 'invites', y en cualquier lectura del SSB log propio. -------------------------------------------------------------- PARTE 3 — BLOCKCHAIN EXPLORER: blockchain_model.js + blockchain_view.js -------------------------------------------------------------- blockchain_model.js — filtro 'invites' (linea 209): filtered = filtered.filter(b => b && (b.type === 'pub-invite' || (b.type === 'tribe' && Array.isArray(b.content?.inviteLog) && b.content.inviteLog.length > 0)) ) Muestra: - Todos los mensajes SSB de tipo 'pub-invite' - Todos los mensajes de tipo 'tribe' que tengan inviteLog con entradas blockchain_view.js: - FILTER_LABELS: 'pub-invite': 'PUB INVITE', invites: 'INVITES' - CAT_BLOCK2: añadido 'invites' a la categoria de filtros secundarios - TYPE_COLORS: verde (#27ae60) para pub-invite e invites - getViewDetailsAction: case 'pub-invite' -> '/invites' renderInviteExtra(block) — funcion nueva (linea 140): Si block.type === 'pub-invite': Tabla de 3 filas: PUB HOST | PUB KEY (user-link) | ACCEPTED AT Si block.type === 'tribe' con inviteLog: Tabla de 6 columnas: CODE (primeros 12 chars + ...) | GENERATED BY (user-link, primeros 16 chars) | GENERATED AT | STATUS (badge pending/used) | USED BY (user-link) | USED AT Retorna null en cualquier otro caso. Se llama dentro del render de cada bloque en la vista del explorer. -------------------------------------------------------------- QUE PUEDE GUSTAR -------------------------------------------------------------- - La trazabilidad de tribes es completa: sabes quien genero, cuando, quien uso, cuando. Todo dentro del propio log SSB. - Para pubs: al menos queda constancia en tu log propio de que aceptaste ese pub invite y cuando. - El inviteLog es retrocompatible: tribes viejas sin inviteLog simplemente lo tienen como []. - El code de tribe se elimina de invites[] al usarse (single-use). - parseRemote ya existia y es la misma funcion que usa otro codigo del modelo, no hay logica duplicada. - Formato ISO 8601 para fechas, legible y ordenable. -------------------------------------------------------------- QUE PUEDE NO GUSTAR / PUNTOS DE DISCUSION -------------------------------------------------------------- 1. El inviteLog se guarda en el mensaje SSB del tribe. Esto significa que cada vez que alguien genera o usa un invite, se publica un nuevo mensaje SSB de tipo 'tribe' con el inviteLog actualizado. Si hay muchos invites, el historial de mensajes de la tribe crece. No es un problema grave pero es algo a tener en cuenta. 2. El pub-invite SSB message lo publica DESPUES del handshake, no antes. Si el proceso cae justo entre el handshake y el publish, el handshake ocurre pero el log no se actualiza. Es una ventana de inconsistencia pequeña pero existe. 3. El inviteLog esta en el contenido del tribe message, no en un tipo de mensaje separado. Si alguien actualiza la tribe por otra razon (cambio de descripcion, imagen...) y no incluye el inviteLog, se perderia. Habria que revisar que updateTribeById siempre hace merge de todos los campos del tribe, no solo los que se pasan. 4. El CODE en la tabla del blockchain se trunca a 12 chars. Es solo visual. El code completo sigue en el dato y en invites[]. 5. No hay manera de revocar un invite pendiente desde la UI. Solo se "consumen" al usarse. Habria que anadir una accion de revocacion.