Alexei Rojas Quiroga
← Todos los proyectos

Proyecto personal

Mirra — Armario Digital y Planificador de Outfits con IA

Fotografía tu ropa y obtén outfits armados con lo que ya tienes

Estado
En desarrollo
Rol
Individual: producto, arquitectura, app móvil, backend Supabase y edge functions, CI

Arquitectura

  • Núcleo hexagonal, sin frameworks
  • Propiedad garantizada por RLS + FKs compuestas
  • Fotos mediante URLs prefirmadas de R2
  • Modelo de visión llamado desde el servidor

El adaptador obtiene una URL prefirmada, sube la foto directo a R2, consulta al clasificador (que lee la foto y llama al modelo de visión), el caso de uso valida la propuesta en el dominio y la prenda se guarda bajo seguridad a nivel de fila.

Arquitectura · 10 nodos · 2 flujos
LO QUE CONSTRUÍExpo / React N…App móvilCaptura, grilla ydetalleSupabase AuthInicio de sesiónOTP por correo, sesiónen AsyncStorageTypeScriptCasos de usoaddGarmentFromPhoto,listWardrobeTypeScriptModelo de dominioGarment, Outfit,isWearableForTypeScriptAdaptadores deinfraestructuraRepos, almacenamientoR2, clasificador, cachéde URLsPostgres + RLSBase de datos delguardarropaPrendas, outfits,pgvectorEdge Function …Clasificador deprendasLee la foto y consultael modelo de visiónOpenAI-compati…Modelo de visiónDescribe la prenda apartir de la fotoCloudflare R2Almacenamiento defotosBucket privado de fotosde prendasEdge Function …Función de URL desubidacreate-upload-url1invoca un caso de uso23456789
  • Servicio / cómputo
  • Almacén de datos
  • IA
  • Cliente
  • Sistema externo
  • Síncrono
  • Asíncrono / bucle
Desplázate hacia los lados para ver todo el diagrama

Cómo fluye, paso a paso

Haz clic en un paso para saltar a él. Haz clic en un componente para ver detalles.

Qué hace

Mirra es una app nativa iOS/Android (Expo / React Native) que convierte la ropa del usuario en un armario digital. La foto de una prenda se sube a almacenamiento privado, un modelo de visión propone sus atributos y el usuario los confirma. La generación de outfits se apoya en un modelo de dominio puro que aplica reglas de composición.

El problema

Las personas tienen ropa que rara vez combinan bien y no cuentan con un lugar que conozca lo que hay en su armario. Catalogar a mano es tedioso, por eso la app automatiza la clasificación y deja el control final al usuario.

Qué construí

  • Núcleo hexagonal del armario (dominio / aplicación / puertos / adaptadores) con fakes en memoria para cada puerto, de modo que los casos de uso se prueban sin framework.
  • Un test de guardia arquitectónica rompe el build si el dominio o la aplicación importan React, Expo, Supabase o alias de rutas, manteniendo el núcleo portable a Deno.
  • Garantías de propiedad a nivel de base de datos: claves foráneas compuestas (outfit_id, owner_id) y (garment_id, owner_id) impiden armar outfits con prendas de otro usuario; RLS en todas las tablas, privilegios anon revocados, verificado con pgTAP.
  • Las fotos nunca pasan por Postgres ni hay secretos en la app: las edge functions emiten URLs prefirmadas de R2 de corta vida, imponen claves por propietario y llaman al modelo de visión desde el servidor.
  • Modelo de visión elegido mediante un arnés de evaluación (scripts/eval-vision) con timeout derivado de la latencia p95 medida, no estimada.
  • El CI ejecuta lint, formato, typecheck, Jest, pgTAP contra un stack local de Supabase y tests de funciones Deno.

Decisiones clave y por qué

01

Arquitectura hexagonal con tipo Result

Base de datos, almacenamiento e IA son adaptadores intercambiables detrás de puertos. Los fallos esperados devuelven Result en lugar de excepciones, obligando a manejar ambos caminos.

02

Cloudflare R2 para imágenes, solo claves en Postgres

Sin costo de egreso ni límite de 1 GB; la base de datos se mantiene pequeña y solo guarda claves y metadatos.

03

Llamadas de IA solo desde edge functions, tras un puerto intercambiable

Las claves quedan como secretos del servidor, el costo es medible en un solo lugar y el proveedor compatible con OpenAI puede cambiarse sin tocar la app.

04

Propiedad garantizada por el esquema, no solo por políticas

Las claves foráneas compuestas hacen imposible estructuralmente la composición entre usuarios, de modo que un bug en el código o en RLS no filtra datos.

05

OTP por correo sin contraseña

Sin contraseñas que almacenar ni configuración de deep links en el MVP; el login social se difiere hasta tener credenciales.

Stack tecnológico

Lenguajes
TypeScript (strict)
Frontend
Expo / React Nativeexpo-router
Datos
Supabase Postgres + RLSpgvector
Backend
Supabase Auth (email OTP)Supabase Edge Functions (Deno)
Nube
Cloudflare R2
IA
Vision LLM (OpenAI-compatible API)
Pruebas
Jest + Testing LibrarypgTAP
DevOps
GitHub Actions