Deep QA & Production Hardening (auditoría)
V-3.2.0243 — Deep QA & Production Hardening (auditoría, sin cambios de código): ======================================== 1. RLS / MULTI-TENANT AUDIT ======================================== RLS habilitado: ✓ en las 58 tablas de public (verificado vía pg_class.relrowsecurity). Policies revisadas (tablas críticas): • owner_addons: SELECT (owner OR super_admin). Solo super admin puede INSERT/UPDATE/DELETE. Owners no pueden cancelar add-ons directamente — toda mutación va por RPC SECURITY DEFINER (purchaseAddon, cancelPendingAddon, sandboxPurchaseAddon). ✓ Aislamiento correcto. • cash_registers: ALL para owner OR super_admin; SELECT para cashier scopeado por get_cashier_owner. ✓ • cash_sessions: ALL para owner OR cashier (cashier_id = auth.uid()). ✓ Cashier solo ve sus propias sesiones. • cash_movements: ALL owner; cashier SELECT scopeado por owner + (user_id propio O session propia). ✓ • pos_order_refunds: ALL owner; cashier SELECT/INSERT scopeado por get_cashier_owner. ✓ • employee_memberships: ALL owner; employee SELECT solo su propia fila. ✓ Empleado no ve otros empleados. • supplier_networks: ALL supplier-owner; SELECT operator solo si tiene membership active/pending/suspended. ✓ • supplier_network_memberships: ALL supplier-owner; SELECT/UPDATE operator solo su propia fila. ✓ Operator NO ve otros operadores del mismo network. • supplier_invoices: ALL supplier; SELECT operator (+cashier del operator) solo invoices propias; UPDATE operator solo del recibo propio. ✓ • supplier_payments: scope vía invoice.operator_owner_id / supplier_owner_id. INSERT operator solo si invoice = pending. ✓ • supplier_returns / supplier_return_items: scope vía invoice. ✓ • profiles: SELECT/UPDATE/INSERT solo propio + super admin. Trigger guard_profiles_is_test_account bloquea cambios a is_test_account fuera de super admin. ✓ • user_roles: SELECT propia + super admin; ALL solo super admin. ✓ • stores: ALL owner; cashier SELECT scopeado por get_cashier_owner; shopper SELECT vía sales propias. ✓ • sales / sale_items: owner ALL; cashier scopeado; shopper SELECT solo por customer_email = JWT email. ✓ Huecos detectados (clasificación): [MEDIO] cash_deposit_evidence — no se encontró policy explícita en el snapshot. Verificar en V-3.2.0244 si hereda de cash_movements o requiere policy propia. Riesgo: storage de evidencias podría no estar correctamente scopeado a owner. [BAJO] supplier_network_audit_log — no aparece policy en pg_policies para este nombre exacto en el slice consultado. Riesgo: audit log podría estar oculto por defecto (mejor que abierto) pero conviene policy explícita SELECT supplier_owner_id para que el supplier vea su propia bitácora. [BAJO] cash_sessions — política única ALL (owner OR cashier) sin filtro por owner_id en condición de cashier. Cashier validado por cashier_id pero conviene reforzar con owner_id = get_cashier_owner(auth.uid()) por simetría con cash_movements. [INFORMATIVO] Linter de Supabase reporta 84 warnings: • 1× Extension in Public — aceptable (pg extensions estándar). • 1× Public Bucket Allows Listing — bucket store-logos es público intencionalmente. • 81× Public Can Execute SECURITY DEFINER Function — son los RPCs Postgres invocados desde el cliente (has_role, is_super_admin, get_effective_tier, warehouse_has_access, etc.). Diseño intencional; cada función ya valida internamente. • 1× otro (function_search_path mutable o similar) — revisar en patch. NINGÚN error crítico (no hay tablas sin RLS, no hay policies con USING(true), no hay leaks de columnas sensibles). ======================================== 2. QA POR MÓDULO (server-side) ======================================== A) /dashboard — getDashboardSummary filtra por owner_id resuelto (cashier via cashier_assignments). Status taxonomy correcto: completed/processing/shipped = ingreso; refunded resta; cancelled/pending no suman. ✓ B) /POS — sales/sale_items con RLS owner+cashier; refunds vía pos_order_refunds insert por cashier; cash_sessions activas filtradas por cashier_id. Multicaja respeta get_allowed_registers_for_store (trigger enforce_cash_register_rules). ✓ C) /sales — cancelaciones y refunds usan RPCs server-side; estados sincronizados con cash_movements via dispatcher. ✓ D) /cash-control — depósitos validados con evidencia (bucket cash-evidence privado); alerts calculados server-side. Riesgo medio: revisar policies de cash_deposit_evidence (ver hallazgo arriba). E) /cash-cuts — PDF + email premium ya validados en V-3.2.0238; descuentan refunds. ✓ F) /addons — pending recovery (V-3.2.0239), sandbox (V-3.2.0240), feature gates por has_role + has_feature + add-on activo. ✓ Sidebar oculta módulos sin add-on. G) Franchise Suite — supplier/operator separados por roles y por owner_id; invoices con compute_balance(); aislamiento de networks vía membership.status. ✓ H) Sandbox Mode — payment_provider='sandbox' + metadata.sandbox_mode=true; RPCs sandbox validan super_admin + is_test_account doble. ✓ ======================================== 3. RESPONSIVE (lectura de código) ======================================== Rutas revisadas: /dashboard, /pos, /addons, /cash-control, /cash-cuts, /franchise-network, /franchise-operator. Riesgos detectados: • /cash-control — tabla principal en <= 640px puede generar overflow horizontal en filas con muchas columnas (fecha/cajero/caja/monto/evidencia). Recomendación V-3.2.0244: card stack en mobile. • /franchise-network — tabla de invoices con 8+ columnas, sin scroll-wrapper visible. Riesgo overflow tablet vertical. • /franchise-operator — invoice detail dialog puede recortar en móvil pequeño (374px viewport actual del usuario). • /addons — grid de cards ya responsive (md:grid-cols-2). ✓ • /pos — layout 2-col en md+; en sm cae a 1-col. ✓ • /dashboard — V-3.2.0238 ya es mobile-first. ✓ • /cash-cuts — PDF preview no es responsive (es PDF). ✓ No se detectaron overflows en /dashboard, /addons, /pos. ======================================== 4. VPS / DOCKER / BUILD ======================================== • wrangler@3.114.17 en devDependencies (V-3.2.0242). ✓ • Dockerfile sin cambios; CMD usa npx wrangler dev --local (ya cacheado). • bunx tsc --noEmit — LIMPIO. • npm run build — EXITOSO (18.24s, sin errores). • Warnings de build: chunks >500kB (pos: 1.1MB, router: 2.2MB) — preexistente, no bloqueante; aplazar code-splitting a versión dedicada. • 3 advertencias de dynamic+static import mix (payment-links.server, email.server, email-templates.server) — preexistentes, no afectan funcionalidad. ======================================== 5. ENTREGABLE ======================================== Bugs encontrados: 0 críticos, 0 altos. Bugs corregidos: 0 (modo auditoría). Riesgos pendientes para V-3.2.0244: [MEDIO] policy explícita para cash_deposit_evidence [BAJO] policy SELECT explícita para supplier_network_audit_log [BAJO] reforzar cash_sessions con filtro owner_id en condición cashier [BAJO] responsive de /cash-control y /franchise-network en mobile [INFO] code-splitting de pos y router (chunks grandes) Riesgos aceptables: • 81 SECURITY DEFINER functions expuestas — diseño intencional (RPCs). • Bucket store-logos público — necesario para imágenes de tienda. • Extension in public — estándar Supabase. Deploy-ready: SÍ para el entorno actual. Sin regresiones. Sin migraciones aplicadas.
Aspectos destacados
- Sin cambios funcionales — auditoría profunda
- RLS verificado en 58 tablas (todas con RLS habilitado)
- 0 hallazgos críticos / 0 altos
- Riesgos medio/bajo documentados para V-3.2.0244
- Typecheck y build limpios