Cuentas por edición
Cómo se crean y aprovisionan las cuentas/empresas en Heskala según la edición de distribución (SaaS, Desktop, On-prem).
Las tres ediciones
Sección titulada «Las tres ediciones»| Edición | Backend | Control de acceso | Alta de cuenta |
|---|---|---|---|
| SaaS | la nube de Heskala (Convex) | company_subscriptions + Dodo (trial/pago) | autoservicio web (hoy vía waitlist) |
| Desktop | la nube (Tauri apunta a la misma nube) | igual que SaaS (misma cuenta) | solo login; la cuenta/billing se crea en la web |
| On-prem | el del cliente (self-host) | licencia firmada (mods/seats) + heartbeat | bootstrap in-app del primer admin |
Detección de edición
Sección titulada «Detección de edición»- Backend:
EDITION(convex/lib/config/core.ts), deprocess.env.EDITION. Defaultsaas. - Frontend:
getEdition()/isOnPremEdition()(lib/edition/edition.ts), deimport.meta.env.VITE_EDITION. - Desktop runtime:
isDesktopApp()(lib/edition/is-desktop.ts), porwindow.isTauri.
Dos tipos de “usuario nuevo”
Sección titulada «Dos tipos de “usuario nuevo”»- Dueño / primer usuario: crea la cuenta y aprovisiona empresa + plan/licencia (onboarding).
- Miembro: lo invita un admin; entra por link de activación (
/activate) o first-time-login (OTP).
Flujos por edición
Sección titulada «Flujos por edición»SaaS (web)
Sección titulada «SaaS (web)»landing (/) → "crear cuenta" → /waitlistlogin → /auth/sign-inautenticado sin empresa → OnboardingWizard → setupCompanyFromOnboarding → empresa + company_subscriptions del plan default (trial Dodo)Desktop (Tauri → nube)
Sección titulada «Desktop (Tauri → nube)»Misma cuenta/backend que SaaS. La app es login-only:
app abre en / → redirect a /auth/sign-in (detecta desktop)sign-in: "¿No tienes cuenta?" → link externo a heskala.comautenticado sin empresa → NoCompanyDesktopCard (gestionar en la web)On-prem (self-host, license-gated)
Sección titulada «On-prem (self-host, license-gated)»app abre → LicenseGate pide tokenlicencia válida + base SIN usuarios → /setup (crear primer admin) → OnboardingWizard → setupCompanyFromOnboarding(licenseToken) rama on-prem: enabledModules = mods, limits.maxUsers = seats, lifetimeadmin invita usuarios → link /activate?token=... (sin SMTP)Ver Probar on-prem localmente.
Tier de licencia (módulos/asientos)
Sección titulada «Tier de licencia (módulos/asientos)»Dos fuentes según la edición, un mismo chokepoint en la UI:
- SaaS/Desktop:
subscription.enabledModules+limits.maxUsers(plan/Dodo). - On-prem:
payload.mods/payload.seatsdel token firmado, expuestos poruseLicense().
El gating ocurre en hooks/usePermissions.ts → can(action, module) filtra los
módulos fuera del tier (salvo ALWAYS_ENABLED_MODULES). El sidebar y los
RouteGuard* cascadean. Acceso por URL a un módulo fuera del tier → pantalla
“módulo no incluido”.
Invitación de miembros (sin SMTP)
Sección titulada «Invitación de miembros (sin SMTP)»convex/system/activation/: generateActivationLink (super_admin o
company_admin), getActivationStatus (pública) y activateAccount (action, fija
la contraseña con modifyAccountCredentials). UI: ruta /activate.
El gate: AuthGuardCombined
Sección titulada «El gate: AuthGuardCombined»Para “autenticado SIN empresa”:
super_admin → accesoon-prem → OnboardingWizard (tier de licencia)desktop → NoCompanyDesktopCard (gestionar en la web)saas → /waitlistMapa de archivos
Sección titulada «Mapa de archivos»| Área | Archivos |
|---|---|
| Edición | convex/lib/config/core.ts, lib/edition/edition.ts, lib/edition/is-desktop.ts |
| Auth | convex/auth.ts |
| Routing | app/routes/_home/index.tsx, .../_public/auth/sign-in.tsx, .../_public/setup.tsx, .../_public/activate.tsx |
| Gate | components/auth/auth-guard-combined.tsx |
| Onboarding | convex/system/onboarding/*, components/onboarding/onboarding-wizard.tsx, hooks/useOnboarding.ts |
| Licencia | lib/licensing/*, convex/system/licensing/* |
| Invitación | convex/system/activation/*, components/users/user-create-dialog.tsx |