Event Sourcing de primera clase
Aggregates, eventos de dominio y proyecciones con replay integrado. El log de eventos es la fuente de verdad.
Orientado a objetos y domain-driven por diseño. Construido para equipos que desarrollan SaaS complejos y multi-tenant sobre microservicios — no solo landing pages.
$ sf init
✔ Monorepo created
$ sf generate microservice crm
✔ crm microservice created
$ sf run
✔ crm microservice started → http://localhost:3000/
✔ admin panel companion started → http://localhost:3001/ La mayoría de frameworks se limitan al routing y la autenticación. SaaSFormation va más lejos.
Aggregates, eventos de dominio y proyecciones con replay integrado. El log de eventos es la fuente de verdad.
Contratos TypeScript compartidos entre fronteras de servicio. Sin sorpresas en runtime cuando los servicios se comunican.
Peticiones HTTP, comandos, queries y eventos de dominio siguen el mismo patrón de message bus. Cada bus acepta middleware: añade logging, autenticación o trazado una vez y se aplica en todas partes.
Contenedor de inyección de dependencias con reflect-metadata e inyección por constructor. Repositorios, servicios y handlers se autocablean.
Trazas OpenTelemetry y dashboards de Grafana preconfigurados. Sabe exactamente qué hacen tus servicios en producción.
JSON:API conforme al estándar con documentación Swagger integrada. Endpoints versionados y consistentes que tus consumidores pueden explorar y probar desde el primer día.
Sin espagueti. Command handlers limpios, con tipos y testeables, con las dependencias que necesitan — y nada más.
@Inject — no service locators CommandHandler<T> enforces the contract import { Inject } from "@saasformation/di";
import { CommandHandler } from "@saasformation/message-bus";
@CommandHandler(RegisterUser)
export class RegisterUserHandler
implements CommandHandler<RegisterUser>
{
constructor(
@Inject(UserRepository)
private readonly users: UserRepository,
) {}
async handle(cmd: RegisterUser): Promise<void> {
const user = User.register(
cmd.email,
await Password.hash(cmd.password),
);
await this.users.save(user);
}
} Abrimos el acceso de forma progresiva. Deja tu email y te avisaremos cuando sea tu turno.