Traducción. Autoritativo: fs-loy-0014-wallet-passes.md.
Contexto
Un wallet pass es la tarjeta de fidelización dentro de Apple Wallet o Google Wallet: saldo, nivel y un código escaneable en el punto de venta. Elimina la mayor fricción de toda la categoría —“descárgate nuestra app”— y la reemplaza por un enlace. Para Latinoamérica importa más que en otras partes. Android domina el parque de dispositivos y Google Wallet viene preinstalado, así que la cobertura es prácticamente universal, y el pass se actualiza por push sin ninguna app nuestra en el dispositivo. ADR-020 lo ubica como la capa intermedia de la estrategia mobile. Una cosa que quedó mal ahí y se corrige acá: los wallet passes se emiten siempre bajo las cuentas propias de Softcrum, nunca las del cliente. La app necesita la cuenta de desarrollador del cliente porque compite por un listing en la tienda y la guideline 4.3 de Apple la empuja ahí; un pass no tiene listing, y su branding —logo, colores, nombre de la organización— viaja dentro del propio archivo. Un tenant que quiere algo que salga completamente bajo su nombre recibe la app white-label, que es justamente para eso. Ofrecer un tier de wallet con cuenta del cliente sería vender lo mismo dos veces y sumar gestión de certificados por cada tenant. Eso convierte un spike en bloqueante y no en modelador de tiers: si Apple exige un Pass Type ID por marca, emitir bajo nuestra cuenta podría no ser posible y la feature cambia de forma. Se responde antes de escribir el ADR.Alcance (normativo)
- Generación de passes para Apple Wallet (
.pkpass, firmado) y Google Wallet (objetos vía JWT). - Branding por tenant guiado por la misma configuración de theming que la app mobile.
- Saldo, nivel y un código escaneable de member en la cara del pass.
- Actualizaciones push al cambiar saldo o nivel, por la cascada de notificaciones existente.
loyalty.wallet_pass_registrationsregistrando qué dispositivos tienen qué pass.- Un enlace de agregar-a-billetera firmado y con expiración, apto para embeber en un correo.
Fuera de alcance (normativo)
- Pagos. Estos son passes de fidelización, nunca instrumentos de pago.
- Relevancia en pantalla de bloqueo por ubicación en la primera versión. Es una de las capacidades más potentes del formato, pero necesita coordenadas de local por tenant, que es su propio problema de datos.
- Validación offline en el punto de venta. El código se escanea y se valida contra nuestra API.
Comportamiento (normativo)
- Los passes se emiten bajo las cuentas propias de Apple y Google de Softcrum, siempre. Los certificados del cliente no se ofrecen: un tenant que quiere su propio canal recibe la app white-label (ADR-020). Las llaves de firma se guardan como secretos y se rotan sin reemitir cada pass; una llave filtrada que no se puede rotar es una reemisión completa a todos los members.
- El enlace de agregar-a-billetera es firmado y expira. Un enlace que nunca expira es una credencial permanente sentada en una bandeja de correo.
- Las actualizaciones del pass pasan por
NotificationChannelPortcomo cualquier otro canal (ADR-019), con su propio adaptador. Saltarse la cascada aquí crearía un segundo camino de entrega sin auditoría. - Los push de actualización se agrupan: varios cambios de saldo dentro de una ventana corta producen un solo push. Un member cuyo teléfono vibra con cada punto acreditado va a eliminar el pass.
- Un member puede tener el pass en varios dispositivos. Todos los dispositivos registrados reciben actualizaciones.
- Desregistrar un dispositivo detiene sus actualizaciones y nunca afecta a los demás.
- El código escaneable es un identificador de member inútil sin autenticación — escanearlo no otorga nada por sí solo. Es un identificador, no un token al portador.
- Las actualizaciones del pass son de categoría
product, nomarketing: son un cambio de estado sobre algo que el member instaló deliberadamente.
Datos (normativo)
API (normativo)
Los callbacks de plataforma siguen los protocolos propios de Apple y Google, que no nos toca diseñar.
Son el único lugar del módulo donde la forma del camino la dicta un tercero.
Eventos (normativo)
loyalty.wallet_pass.issued. Los cambios de saldo y nivel se consumen de los eventos existentes en vez
de generar nuevos.
Criterios de aceptación (normativo)
- Un
.pkpassgenerado valida contra los requisitos de firma de Apple e instala en un dispositivo. - Un objeto de Google Wallet instala desde el mismo enlace en Android.
- Un cambio de saldo empuja una actualización dentro de 60 s a cada dispositivo registrado.
- Diez cambios de saldo dentro de la ventana de agrupación producen exactamente un push.
- La rotación de llaves emite passes válidos sin invalidar los ya instalados.
- Un enlace de agregar-a-billetera vencido se rechaza con un error tipado.
- Negativo: el código escaneable por sí solo no otorga acceso a ningún endpoint — probado por un test que lo intenta sin autenticación.
Ejecución
Bloqueado por el ADR de librerías de firma (DEC-H5). Pipeline asíncrono: la generación y los push corren enbackend/workers; el adaptador de actualización de wallet es una implementación de
NotificationChannelPort.
Preguntas abiertas
Ninguna pendiente. Toda pregunta que llevaba este spec quedó respondida en el registro consolidado (../../../../design/open-questions-v1.md, v1.1) y se
incorporó a las secciones normativas de arriba.
Sigue bloqueado, pero no por una decisión: