Klaaro Card
Una billetera nativa para iOS de tarjetas de presentación que cualquiera puede abrir sin la app. Lo más difícil estuvo en el backend: propiedad sin cuentas y una seguridad a nivel de fila que resiste consultas directas a la API.

El producto
Klaaro Card es una billetera de tarjetas de contacto profesionales. Diseñas tu propia tarjeta y la compartes por código QR o con un toque. El QR codifica un enlace de klaaro.cards, así que quien lo escanea no necesita la app: los Universal Links abren la app si está instalada, y una página de Next.js muestra la tarjeta si no lo está.
Fui PM y desarrollador principal en un equipo de 4 personas en la Apple Developer Academy, trabajando en la app SwiftUI, las páginas web y el backend en Supabase.
Propiedad sin cuenta
Nadie quiere crear una cuenta solo para entregar una tarjeta de presentación, así que por defecto no hay login. - Cada tarjeta pertenece a un token secreto del dispositivo guardado en el Llavero, sincronizado por el Llavero de iCloud cuando está disponible. - Las políticas de escritura de la seguridad a nivel de fila de Postgres comparan ese token con un header de la petición. - Iniciar sesión con Apple es opcional y solo añade sincronización. - Al reinstalar, la app restaura la tarjeta con una función de base de datos que compara el token y nunca lo devuelve.
El bug que restauraba la tarjeta de un desconocido
Al principio, la restauración usaba una consulta simple. Las tarjetas tenían dos políticas de lectura: cualquiera puede leer las tarjetas públicas, y los dueños pueden leer la suya con el token. Postgres combina las políticas permisivas con OR, así que en un dispositivo sin token coincidente la consulta igual devolvía todas las tarjetas públicas, y la app podía restaurar la tarjeta de un desconocido al azar.
Moví la restauración a una función SECURITY DEFINER que lee directamente el header del token y devuelve solo la tarjeta que coincide, o nada.
Cerrar una fuga de tokens
La seguridad a nivel de fila decide qué filas puede leer un rol, no qué columnas. Con la clave pública de la API, cualquiera podía consultar la columna del token de dispositivo de las tarjetas públicas, y ese token es justo en lo que confía cada política de escritura, así que habría permitido apoderarse de la tarjeta de otra persona. Los IDs de los dueños y los datos de pago que habían elegido ocultar quedaban expuestos de la misma forma.
Revoqué el acceso de lectura a toda la tabla y volví a conceder solo las columnas que necesitan los clientes públicos.
Ese arreglo rompió la sincronización de tarjetas. Los upserts de la app hacían que PostgREST volviera a leer la columna del token, algo que los nuevos permisos prohíben, así que cada guardado fallaba con un 401. Volver a conceder la columna habría reabierto la fuga. En su lugar, un trigger de la base de datos ahora rellena el token a partir del header de la petición, y la app dejó de enviarlo en el cuerpo. Para los clientes públicos, el token ahora es de solo escritura.
Trabajo que la app no debería hacer
Las Edge Functions de Supabase se encargan de las tareas que no deberían ejecutarse con una clave pública: una envía notificaciones push cuando alguien recibe una tarjeta, y otra elimina una cuenta y sus datos.
Resultados
- 30+ usuarios beta antes del lanzamiento en la App Store.
- Disponible en la App Store desde septiembre de 2026.