Construye tu SaaS sobre la infraestructura de Dinaup
Cómo montar un producto multi-tenant con el SDK .NET: login de usuarios, una empresa por cliente y datos aislados, sin construir backend.
Quien monta un SaaS B2B escribe dos aplicaciones aunque solo quiera una. La primera es su producto: las pantallas y la lógica que sus clientes pagan. La segunda es el andamiaje que ningún cliente ve: registro de cuentas, login, recuperación de contraseña, 2FA, y la parte que más miedo da: que los datos de una empresa jamás aparezcan en la sesión de otra.
El SDK .NET de Dinaup incluye un patrón para quedarte solo con la primera. Tu aplicación se registra como app externa de la plataforma, y Dinaup le presta la infraestructura: autenticación de usuarios, un espacio de datos aislado por empresa y el modelo tipado de siempre. Este post recorre el patrón completo; la referencia está en la doc de apps multi-tenant.
Lo que no construyes
Con una app externa, estas piezas vienen de serie:
- Cuentas de usuario. Alta con código de activación, inicio de sesión, 2FA, recuperación y cambio de contraseña. Métodos del SDK, sin pantallas de Dinaup por medio.
- Multi-tenancy. Cada usuario pertenece a una empresa. Al autenticarse, Dinaup te dice a cuál, y su cliente de datos queda atado a ella.
- Base de datos. Secciones, informes, escrituras, archivos, anotaciones e histórico de cambios: todo lo del cliente Dinaup, por empresa.
- Copias de seguridad. Los datos de tus clientes se respaldan en la plataforma. No programas backups ni restauras nada: no hay base de datos tuya que salvar.
- Secretos. Las credenciales de tu app viven en Vault, no en el código.
Tu parte es la interfaz y el dominio de tu vertical. La suma es un producto completo con el backend ya en producción.
Las tres piezas del patrón
| Pieza | Qué hace | Ciclo de vida |
|---|---|---|
DinaupExternalAppSettings | Identifica tu aplicación ante la plataforma (AppId + AppToken). | Singleton |
DinaupAuthClient | Autentica usuarios y devuelve a qué empresa pertenecen. | Singleton |
MyAppClient | Cliente de datos de un usuario concreto, atado a su empresa. | Uno por sesión |
La clave del diseño está en la tercera. MyAppClient hereda de DinaupClientC, así que informes y escrituras funcionan exactamente igual que en cualquier app conectada al SDK. Lo que cambia es el alcance: cada instancia solo llega a los datos de la empresa del usuario que la creó.
Del login al dato
El arranque carga la identidad de la app desde Vault y registra los servicios:
var vault = new Dinaup.Vault.VaultData(vaultUrl, vaultPassword);
vault.Initialize();
var appConfig = new Dinaup.Models.DinaupExternalAppSettings(vault);
builder.Services.AddSingleton(appConfig);
builder.Services.AddSingleton(new Dinaup.Auth.DinaupAuthClient());
builder.Services.AddScoped<SessionUserContext>();Cuando un usuario inicia sesión, LoginAsync valida sus credenciales y responde con el TenantConnectionKeyword: la clave que identifica su empresa. Con ella construyes su cliente:
var authResponse = await _authClient.LoginAsync(email, password);
if (authResponse == null) throw new Exception("Credenciales inválidas");
DinaupClient = new Dinaup.MyAppClient(_appSettings, authResponse);A partir de ahí, el código es el SDK de siempre. Leer:
var ventas = new APIVentasC();
await ventas.ExecuteQueryAsync(DinaupClient, page: 1, resultsPerPage: 50);Escribir:
var wOp = new WriteOperation("", data);
await DinaupClient.RunWriteOperationAsync(VentasES._SectionIDGUID, wOp, false);
wOp.EnsureSuccess();El mismo informe tipado, la misma WriteOperation. Si ya conectaste una app .NET a tu propia empresa, ya sabes programar contra muchas: la guía de ese primer paso es Conecta tu app .NET a Dinaup.
Una empresa por cliente, un cliente por sesión
El aislamiento entre empresas se apoya en una regla de registro: MyAppClient, y todo servicio que lo use, se registran como Scoped. Cada circuito de usuario recibe su propia instancia, atada a su empresa. Un singleton aquí compartiría la sesión de una empresa con los usuarios de otra.
// Uno por usuario/circuito. Nunca Singleton.
builder.Services.AddScoped<SessionUserContext>();
builder.Services.AddScoped<VentasService>();Para que la sesión sobreviva a recargas, el navegador solo guarda una cookie HttpOnly con un id de sesión. El estado real (la empresa y el email del usuario) se serializa en el almacén clave-valor de la plataforma, MyAppKVClient, bajo ese id. Al volver, la app lee la cookie, recupera el estado del KV y reconstruye el cliente. El código completo está en la doc.
En procesos sin sesión interactiva (importaciones, tareas programadas), DinaupContext.WithUser(userId) atribuye las operaciones a un usuario concreto: autor del alta, histórico y anotaciones quedan a su nombre.
La sesión no vive en tu servidor: despliega los nodos que quieras
Ese detalle de guardar la sesión en el KV tiene una consecuencia que vale una sección: tu app queda stateless. Ni los datos ni las sesiones viven en el proceso; todo lo recuperable está en la plataforma.
- El mismo contenedor desplegado en dos, tres o N nodos detrás de un balanceador. La cookie de sesión vale en cualquiera, porque el estado se lee del KV.
- Si un nodo cae, otro atiende la siguiente petición sin que el usuario vuelva a hacer login.
- Sin sesiones pegajosas en el balanceador, sin un Redis propio que administrar, sin disco que replicar.
Alta disponibilidad con la pieza más barata del catálogo: un id en una cookie y un GetKVAsync.
Las cuentas de tus usuarios, desde tu interfaz
El registro, la activación y las contraseñas se gestionan con métodos del cliente. Tu formulario, tu diseño; Dinaup guarda las credenciales:
| Necesitas | Método |
|---|---|
| Crear una cuenta | Session_RegisterAccountAsync y su código de activación |
| Activarla | Session_ConfirmAccountRegistrationAsync |
| Iniciar sesión con 2FA | Session_SignInAsync + Session_CheckTwoFactor |
| Recuperar contraseña | Session_CreatePasswordRecoveryCodeAsync + Session_ChangePasswordWithCodeAsync |
Todas reciben el userAgent y la IP del usuario final, para que el acceso quede registrado con su origen real y no con el del servidor de tu app.
Lo que sí pones tú
- La interfaz. Tu web o tu app, con tu marca. Dinaup no impone framework: el SDK es un paquete .NET.
- El dominio. Las secciones y los informes de tu vertical, tipados en tu paquete MyDinaup. Cómo funciona ese modelo: el SDK .NET por dentro.
- La configuración de tu app. Para estado propio del producto (flags, ajustes globales, las sesiones de tus usuarios) tienes
MyAppKVClient, un almacén clave-valor que además sirve de health check de la conexión.
Preguntas frecuentes
Siguiente paso
- Apps multi-tenant — la referencia del patrón: montaje, login, cuentas y almacén clave-valor.
- Cliente Dinaup — informes, filtros, escrituras, archivos y anotaciones.
- Vault — las credenciales de tu app, fuera del código.
- MyDinaup — tu modelo de datos convertido en clases.