Back to 0fee
0fee

Migración a SQLAdmin: del admin SolidJS al backend integrado

Cómo migramos el panel de administración de 0fee.dev de un frontend SolidJS personalizado a SQLAdmin con 16 modelos y 12 vistas. Por Juste Thales Gnimavo.

Juste Thales Gnimavo & Claude | March 27, 2026 3 min 0fee
EN/ FR/ ES
sqladminmigrationbackendormadmin-panel

El panel de administración personalizado que construimos en la sesión 020 funcionaba. Tenía rutas UUID, autenticación JWT y jerarquía de roles. Pero también tenía un problema: era una aplicación frontend completamente separada que necesitaba mantenimiento junto con el panel SolidJS principal y el sitio de marketing. Tres aplicaciones frontend para una plataforma eran dos de más.

En sesiones posteriores, tomamos la decisión de retirar el admin SolidJS personalizado y reemplazarlo con SQLAdmin -- una biblioteca Python que genera una interfaz de administración directamente desde modelos ORM de SQLAlchemy. La migración tocó 12 archivos de modelos ORM, creó 16 modelos SQLAlchemy, construyó 12 vistas de administración y eliminó miles de líneas de código frontend personalizado.

¿Por qué SQLAdmin?

CaracterísticaAdmin SolidJS personalizadoSQLAdmin
Carga de mantenimientoAlta (app separada)Baja (auto-generado desde modelos)
Pipeline de buildVite + SolidJSNinguno (renderizado en servidor)
Soporte de nuevo modeloEscribir frontend + APIAñadir una clase de vista admin
Búsqueda/filtroImplementación personalizadaIncorporado
DespliegueServicio separadoMismo proceso del backend

La compensación fue clara. Perdimos control de diseño píxel por píxel, pero ganamos cero sobrecarga de mantenimiento para operaciones CRUD de admin. Para una herramienta interna usada por una persona (Thales), esa compensación fue fácil de hacer.

Los 16 modelos SQLAlchemy

La migración requirió convertir cada tabla de base de datos a un modelo ORM de SQLAlchemy apropiado: User, App, Transaction, Provider, AppProvider, PaymentMethod, Webhook, WebhookDelivery, Invoice, Coupon, CouponUsage, ApiKey, FeatureRequest, FeatureUpvote, FeatureComment y AuditLog.

El problema del nombre de columna reservado: metadata a meta

metadata es un atributo reservado en la base declarativa de SQLAlchemy. Definir una columna con ese nombre oculta el atributo interno y causa errores crípticos. El renombrado a meta se propagó a través de cada modelo, endpoint API, SDK y la migración de base de datos misma.

Las 12 vistas de administración

Las transacciones son solo lectura (can_create = False, can_edit = False, can_delete = False) -- en una plataforma de pagos, nunca modificas un registro de transacción después de la creación. Esto es un principio fundamental de auditoría financiera: el libro mayor es solo de adición.

SQLAdmin usa sesiones basadas en cookies para autenticación. El panel ahora vive en /thales -- una ruta significativa para Thales (el CEO y único admin) mientras sigue siendo no obvia para escáneres automatizados.

La corrección de compatibilidad de column_filters

Encontramos errores 500 al usar filtros de columna en SQLAdmin. La corrección requirió especificar filtros como cadenas en lugar de atributos del modelo.

Lo que eliminó la migración

~3.000 líneas de código admin SolidJS, 7 endpoints API personalizados, un pipeline de build separado, configuración de despliegue específica del admin y enrutamiento frontend para admin.

Lecciones de la migración

Empieza con SQLAdmin si eres un equipo pequeño. El nombre de columna metadata te morderá. Las vistas de solo lectura son una funcionalidad, no una limitación. Las sesiones de cookies están bien para configuraciones de un solo admin.


Este artículo es parte de la serie "Cómo construimos 0fee.dev". 0fee.dev es un orquestador de pagos que cubre más de 53 proveedores en más de 200 países, construido por Juste Thales Gnimavo y Claude desde Abiyán sin ingenieros humanos. Sigue la serie para conocer la historia completa de la construcción.

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles

Thales & Claude deblo

El prompt decía que lo anunciara. El modelo no lo hizo. Así que lo hizo el worker: cerrar un silencio de 15 segundos en Déblo Voice

Déblo Voice se quedaba en silencio unos 15 segundos cada vez que una pregunta difícil activaba una búsqueda profunda. El prompt ya exigía un anuncio, pero el modelo de audio nativo emite la llamada a la función como su primer token. Además, el silencio tenía dos partes, la ejecución de la herramienta y la latencia de la respuesta, así que ningún prompt podía cerrarlo. Llevamos la garantía al worker de LiveKit: un anuncio pregrabado con la voz y el idioma de la sesión, y un suave sonido de tecleo mientras el agente piensa. Probado en producción el 16 de octubre de 2026: 14 y 17,5 segundos de silencio del lado del modelo, unos 0,4 segundos percibidos por el usuario.

13 min Oct 16, 2026
deblodeblo-voicevoice-aigemini-live +17
Thales & Claude zerosuite

El servidor que no dimos de baja: vaciar una máquina de producción en una noche, y cada número que comprobamos

Una noche, seis aplicaciones migradas fila por fila, tres copias de seguridad vacías, una sin destino y un servidor cuyo futuro cambió tres veces.

19 min Oct 2, 2026
caspclaude-codeclaude-opus-5.5infrastructure +10
Thales & Claude zerosuite

El orquestador no programa: trece sesiones en un día, un navegador que verifica y saber cuándo parar

Un día, una plataforma privada de un cliente, trece sesiones headless de Claude encadenadas por un orquestador que nunca escribe código. Verificar en el navegador del CEO, agrupar correcciones sin soltar la gate y escribir cuándo cerrar una sesión.

19 min Sep 30, 2026
caspclaude-codeclaude-opus-5.5multi-session +12