Disponible

Alterna CMS

Plataforma de desarrollo para armar sistemas.

Identidad, workspaces, autenticación y configuración, compilados dentro del binario del proyecto. Encima escribís tus módulos.

Para desarrolladores

La base del sistema, ya resuelta

Alterna CMS es un producto para quien construye software. Cargo lo compila junto con tu proyecto y el proceso HTTP arranca con usuarios, empresas y un lugar donde enchufar módulos.

  • Un binario

    La plataforma y tu código salen del mismo cargo build.

  • Varios workspaces

    El workspace activo sale de la sesión del usuario, no de un id que mande el cliente.

  • Módulos propios

    Cada módulo declara rutas, tablas, permisos y eventos. El CMS los registra al arrancar.

Qué trae

Identidad, configuración y datos

Tres áreas listas, y el contrato técnico para extenderlas.

  • Identidad

    Usuarios, personas, workspaces, empresas, ubicaciones, sesión y roles.

  • Configuración

    Autenticación, marca, correo y su cola, auditoría, mantenimiento y biblioteca de archivos.

  • Datos

    PostgreSQL como base principal y un catálogo de bases secundarias. Limpieza de datos operativos por módulo.

  • Stack

    Rust, Tokio y Axum. Persistencia con SeaORM. Sesión de workspace en Redis. JWT, Argon2 y TOTP.

  • API

    El CMS monta /api/v1/auth. Cada módulo anida su propio prefijo.

  • Eventos

    Un módulo publica un hecho y otro lo escucha, sin importar el código del vecino.

  • Contrato

    Cada módulo declara rutas, permisos y tablas. El CMS las registra al arrancar.

  • Permisos

    El módulo publica sus permisos al boot. Los roles de sistema son owner, admin, member y viewer.

  • Correo y archivos

    Plantillas de mail en código, worker de la cola, y archivos servidos por el propio CMS.

Cómo está armado

Un workspace, dos cajones

Un proyecto nuevo es un workspace de Cargo. Abajo de crates/ hay dos lugares, y cada uno tiene un dueño distinto.

mi-sistema/

  • Cargo.toml workspace: lista los miembros
  • .cargo/config.toml índice del registry de Alterna CMS
  • crates/
    • modules/ componentes del sistema. Los plugins los usan; un módulo no depende de un plugin.
      • gateway/ el binario. Registra los plugins y sirve HTTP. Acá vive la dependencia alterna-cms.
    • plugins/ lo que definís vos. Una carpeta, un crate, una capacidad. No se importan entre sí.
      • ventas/ ejemplo: implementa Plugin
      • stock/ otro plugin. Se entera de ventas por un evento, no importando su crate.
  1. 1

    modules

    La capa compartida: el contrato Plugin, la identidad, el correo, la auditoría y el binario que arranca. Todo plugin puede usarla. Ningún plugin es dueño de esa capa.

  2. 2

    plugins

    Cada carpeta es un componente independiente. Declara sus rutas y sus permisos, y depende de modules. No depende de la carpeta de al lado.

  3. 3

    El arranque

    gateway es el único que conoce la lista completa. Al boot suma los plugins de crates/plugins junto con la identidad del CMS. Si dos plugins tienen que hablar, publican un evento.

Instalación

Se instala como un crate

Cargo baja el código, lo compila con tu proyecto y el resultado es un solo binario. El índice vive en el registry de Alterna.

1. Índice de Cargo

En la raíz del proyecto que va a compilar, commiteá .cargo/config.toml. Ese archivo no lleva secretos.

.cargo/config.toml
[registries.alterna-cms]
index = "sparse+https://crates.alternapy.com/cms/"

2. Dependencia

La raíz lista los miembros. La dependencia de Alterna CMS queda en el workspace y la usa crates/modules/gateway.

Cargo.toml
[workspace]
resolver = "2"
members = [
  "crates/modules/gateway",
  "crates/plugins/ventas",
  "crates/plugins/stock",
]

[workspace.dependencies]
alterna-cms = { version = "0.2", registry = "alterna-cms" }

3. Token y compilación

El token queda en la máquina, en ~/.cargo/credentials.toml. En CI se usa la variable CARGO_REGISTRIES_ALTERNA_CMS_TOKEN.

Terminal
cargo login --registry alterna-cms
cargo build

Hace falta PostgreSQL y la variable DATABASE_URL. Al arrancar, el CMS aplica migraciones y asegura los roles de sistema. El primer superadmin se crea una vez con el seed del binario. Redis guarda la sesión del workspace activo; si Redis no responde, la sesión se lee de la base.

Documentación básica

Registrar un módulo y hablar con la API

Lo mínimo para arrancar. El resto sale del contrato del plugin.

Plugins del CMS

alterna_cms::cms_plugins() devuelve el plugin de identidad. Tu binario lo suma a la lista y, al boot, el CMS corre migraciones, permisos, settings y rutas.

Rust
let plugins = alterna_cms::cms_plugins();

Tu módulo

Implementá el trait Plugin. El nombre es estable: con eso el CMS sabe qué permisos, tablas y rutas te pertenecen.

crates/plugins/ventas/src/lib.rs
use async_trait::async_trait;
use axum::Router;
use alterna_cms::platform_core::{AppContext, Plugin};

struct MiPlugin;

#[async_trait]
impl Plugin for MiPlugin {
    fn name(&self) -> &'static str {
        "mi_modulo"
    }

    fn register_routes(&self, router: Router<AppContext>) -> Router<AppContext> {
        router.nest("/api/v1/mi-modulo", crate::api::router())
    }
}

Hooks que podés implementar cuando hagan falta: migrations, permissions, tables, settings_defaults, mail_templates, spawn_workers y on_event.

Eventos entre módulos

Publicás un nombre y un payload. Quien escucha lo hace en on_event.

Rust
ctx.events.publish(PluginEvent::new("mi_modulo.listo", payload));

Respuesta HTTP

Todas las rutas usan el mismo sobre. El campo error es un código estable; el cliente traduce. message queda en inglés para cuando no hay traducción.

JSON
{ "success": true, "data": { }, "message": "Saved" }

{ "success": false, "error": "invalid_code", "message": "Invalid or expired code" }

Workspace activo

El aislamiento entre workspaces sale de la sesión del usuario. El cliente manda workspace_uuid solo para listar o cambiar de workspace (PUT /api/v1/auth/session/workspace). Las consultas de negocio leen el workspace de esa sesión. El JWT no trae el workspace adentro.

¿Lo armamos sobre Alterna CMS?

Agendá una charla. Vemos el proyecto y cómo encaja la plataforma.

Agendar demo