docs: add detailed change documentation per feature phase

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
SITO 2026-04-29 01:22:40 +02:00
parent ae7f0c1a4a
commit 07403d18c4
5 changed files with 717 additions and 84 deletions

186
CONTEXT/cambio_qr.txt Normal file
View file

@ -0,0 +1,186 @@
===============================================================
CAMBIO QR — DOCUMENTACION TECNICA
(commit 54ad8a1)
===============================================================
OBJETIVO:
Añadir QR codes en tres puntos de la app para facilitar
el uso en movil: escanear en vez de copiar strings largos.
LIBRERIA:
qrcode ^1.5.4
Ya estaba en package.json (usada previamente en wallet_view.js).
Path de require dentro de las vistas:
const QRCode = require('../server/node_modules/qrcode');
Uso: QRCode.toString(string, { type: 'svg' }) -> devuelve SVG como string
Render: div({ class: 'qr-code', innerHTML: svgString })
innerHTML es un atributo que hyperaxe inyecta directamente como HTML crudo.
--------------------------------------------------------------
1. TRIBE INVITES — tribes_view.js
--------------------------------------------------------------
FUNCION MODIFICADA: renderInvitePage (linea 101)
ANTES:
exports.renderInvitePage = (inviteCode) => { ... }
DESPUES:
exports.renderInvitePage = async (inviteCode) => {
const qrSvg = inviteCode
? await QRCode.toString(inviteCode, { type: 'svg' })
: '';
// ... div con el codigo + div con innerHTML: qrSvg
}
PORQUE NO REQUIRIO CAMBIOS EN BACKEND:
backend.js ya tenia: ctx.body = await renderInvitePage(...)
El await ya estaba, hacer la funcion async no rompio nada.
QUE SE MUESTRA:
- Titulo h2 con el nombre de la tribe
- p con el invite code en texto
- SVG del QR debajo del codigo (clase: 'div-center qr-code')
- Si inviteCode es null/undefined -> qrSvg = '' -> el div QR no se renderiza
--------------------------------------------------------------
2. PUB INVITES — invites_view.js
--------------------------------------------------------------
FUNCION MODIFICADA: invitesView (linea 34)
La funcion padre invitesView ya era async (porque hace otras ops async).
El bloque del QR usa un IIFE async para poder hacer await dentro
de una expresion inline:
await (async () => {
if (!snhInvite) return null;
const qrSvg = snhInvite.code
? await QRCode.toString(snhInvite.code, { type: 'svg' })
: '';
return div({ class: 'snh-invite-box' },
h3({ class: 'snh-invite-name' }, snhInvite.name),
span({ class: 'snh-invite-code' }, snhInvite.code),
qrSvg ? div({ class: 'div-center qr-code', innerHTML: qrSvg }) : null
);
})()
POR QUE EL IIFE:
La estructura de hyperaxe es funcional (cada elemento es un argumento
pasado al elemento padre). No puedes poner un await suelto en medio
de una lista de argumentos. El IIFE resuelve eso sin reestructurar
toda la funcion.
ALTERNATIVA MAS LIMPIA (si se quisiera refactorizar):
Extraer la caja snhInvite a una funcion separada async
y llamarla antes de construir el arbol.
El IIFE funciona, pero es menos legible para alguien que no lo conozca.
DATO DEL CONTEXTO:
snhInvite viene de: src/configs/snh-invite-code.json
Formato: { name: string, code: string }
Es el invite code del pub publico de la instancia.
--------------------------------------------------------------
3. PERFIL DE USUARIO — inhabitants_view.js
--------------------------------------------------------------
TRES FUNCIONES MODIFICADAS:
--- renderInhabitantCard (linea 83) ---
async (user, filter, currentUserId)
QR SOLO se genera si isMe === true (el usuario viendo su propio perfil).
Razon: evitar generar 50 QRs en la lista de inhabitants.
const isMe = user.id === currentUserId;
const qrSvg = isMe && user.id
? await QRCode.toString(user.id, { type: 'svg' })
: '';
El QR aparece dentro de 'div.user-id-qr', junto al enlace user-link.
--- inhabitantsView (linea 177) ---
Debia hacerse async porque llama a renderInhabitantCard (que es async).
Usa Promise.all para no hacer await uno por uno:
await Promise.all(inhabitants.map(user =>
renderInhabitantCard(user, filter, currentUserId)
))
IMPORTANTE: Solo genera QR para isMe, asi que en la practica
solo hay 1 await real de QRCode.toString() en toda la lista.
El Promise.all es correcto igualmente para el futuro.
--- inhabitantsProfileView (linea 233) ---
QR se genera SIEMPRE (para cualquier perfil, no solo el propio).
Razon: la pagina de perfil individual es de una sola persona,
tiene sentido mostrar su QR para que otros lo escaneen y lo sigan.
const profileId = payload?.id || id || viewedId;
const qrSvg = profileId
? await QRCode.toString(profileId, { type: 'svg' })
: '';
Aparece en 'div.inhabitant-left' junto al avatar.
--------------------------------------------------------------
CSS PARA LOS QR
--------------------------------------------------------------
En style.css (al final del archivo):
.qr-code svg -> max-width: 200px, display block, centrado
.qr-code-inline svg -> max-width: 120px (en lista inhabitants, mas pequeno)
.qr-code-profile svg -> max-width: 150px (en perfil individual)
.user-id-qr -> flex column, align-items center
.invite-code-text -> font monospace, fondo sutil
En mobile.css:
.qr-code svg -> max-width: 180px
.qr-code-inline svg -> max-width: 120px
.qr-code-profile svg -> max-width: 150px
.qr-lightbox-overlay -> lightbox CSS puro (sin JS), para ampliar QR
.qr-lightbox-anchor -> ancla que activa el :target del overlay
En OasisMobile.css (tema oscuro):
.qr-code svg rect -> fill: #1A1A1A (fondo del QR oscuro)
.qr-code svg path -> fill: #FFD700 (puntos del QR en dorado)
--------------------------------------------------------------
QUE PUEDE GUSTAR
--------------------------------------------------------------
- No rompe nada: el backend ya tenia await en todas las rutas afectadas
- Libreria qrcode ya existia en el proyecto (no se añadio dependencia nueva)
- QR solo donde tiene sentido: no hay QRs innecesarios en cada elemento
- En lista de inhabitants, QR solo para el propio usuario = sin overhead
- SVG directo (no imagen base64 ni PNG), escala perfecto en cualquier pantalla
- El QR del perfil es el SSB ID completo (@xxx.ed25519), scaneable con
cualquier cliente SSB para seguir al usuario
- Lightbox CSS puro para ampliar QR en movil sin JS adicional
- Tema oscuro: colores del QR adaptados (#1A1A1A fondo, #FFD700 puntos)
--------------------------------------------------------------
QUE PUEDE NO GUSTAR / PUNTOS DE DISCUSION
--------------------------------------------------------------
1. El IIFE async en invites_view.js es un patron poco comun.
Funciona, pero si alguien lee el codigo por primera vez le puede
parecer raro. Alternativa: extraer a funcion separada.
2. El QR en inhabitantsProfileView se genera para TODOS los perfiles.
Si se visita el perfil de un usuario con un SSB ID muy largo,
el QR es pequeno y puede ser dificil de escanear. Considerar
mostrar solo para isMe si se quiere ser mas conservador.
3. El innerHTML con SVG crudo: hyperaxe lo inyecta tal cual.
Si el SVG tuviera algun caracter extraño o fallo de la libreria qrcode,
podria romper el HTML. En la practica qrcode es fiable, pero
es una inyeccion directa a tener en cuenta.
4. No hay boton "Copiar codigo" junto al QR.
En movil es util para pegar el invite en otro lado.
Pendiente de implementar.
5. El QR del tribe invite code es un string hex aleatorio (32 bytes = 64 chars).
No es una URL ni tiene deep link. Solo sirve para copiar/pegar en la app,
no para escanear con una app de QR generica de terceros.
El del SSB ID si que es estandar y reconocible.
6. No se ha implementado lectura de QR (solo generacion).
Leer QR desde la camara requiere acceso nativo Android.
Esto esta fuera del scope del Node.js embebido, habria que
hacerlo desde el wrapper Kotlin y pasar el resultado al servidor.