Outclass is a production-grade, metadata-driven, multi-tenant low-code platform built with .NET 8, Next.js, and Cloud-Native technologies.
- Microservices: Identity, Tenant, Metadata, Document, Workflow, Automation, FileStorage.
- Frontend: Next.js 14 (App Router) with TypeScript and Tailwind CSS.
- Gateway: YARP Reverse Proxy.
- Infrastructure: PostgreSQL, Redis, RabbitMQ.
- Communication: Event-driven architecture using RabbitMQ and MassTransit stylistic patterns (raw RabbitMQ client implemented).
- Docker Desktop or Docker Engine + Compose
- .NET 10 SDK (for local development)
- Node.js 24+ (for frontend)
Run the entire platform using Docker Compose:
docker-compose up --build -dThis will start:
- Postgres (Port 5432)
- Redis (Port 6379)
- RabbitMQ (Port 5672, Management UI on 15672)
- All Microservices
- API Gateway (Port 5000)
Note: The databases passed to connection strings are automatically created by the infra/init-db/01-create-dbs.sh script mounted in the Postgres container.
The frontend is located in src/Web/Outclass.Web.
cd src/Web/Outclass.Web
npm install
npm run devAccess the frontend at http://localhost:3000.
- Admin User:
admin@outclass.com - Password:
Admin123! - System Tenant ID:
11111111-1111-1111-1111-111111111111(used for system admin)
You can access the individual service APIs directly if exposed, but all traffic should go through the Gateway at http://localhost:5000.
Endpoints:
- Identity:
http://localhost:5000/api/auth - Tenants:
http://localhost:5000/api/tenants - Metadata:
http://localhost:5000/api/entitydefinitions - Documents:
http://localhost:5000/api/documents
dotnet builddotnet testProprietary - Outclass Platform.
Version: 1.0.0 Status: DRAFT Author: Principal Architect Team Date: February 17, 2026
Outclass is architected as a next-generation, metadata-driven SaaS platform designed to enable rapid application development and deployment within a multi-tenant ecosystem. By abstracting data models, workflows, and business logic into metadata, Outclass empowers organizations to build bespoke enterprise solutions without incurring the technical debt of custom software development.
The platform addresses the convergence of enterprise control and low-code agility. Traditional SaaS is rigid; custom development is slow. Outclass bridges this gap by offering a fully programmable, event-driven infrastructure that treats "application logic" as data, scalable horizontally across thousands of tenants.
To become the definitive operating system for enterprise business processes, supporting an ecosystem where metadata definitions are the primary unit of value exchange, capable of handling petabyte-scale data ingestion and millisecond-latency event processing.
Outclass utilizes a Microservices Architecture orchestrated via a centralized API Gateway (YARP). The system is composed of localized bounded contexts (Identity, Tenant, Metadata, Document, Workflow, Automation, File) that communicate asynchronously via an Event Bus (RabbitMQ) for eventual consistency and decoupling.
Architecture Diagram (Conceptual)
graph TD
Client[Web/Mobile Clients] -->|HTTPS| Gateway[YARP API Gateway]
subgraph "Core Domain Services"
Gateway --> Identity[Identity Service]
Gateway --> Tenant[Tenant Service]
Gateway --> Metadata[Metadata Service]
Gateway --> Document[Document Service]
Gateway --> Workflow[Workflow Service]
Gateway --> Automation[Automation Service]
Gateway --> File[File Service]
end
subgraph "Infrastructure"
Identity -->|AuthN/Z| PGS[PostgreSQL]
Tenant -->|Config| PGS
Metadata -->|Definitions| PGS
Document -->|JSONB Data| PGS
Workflow -->|State| PGS
Services -->|Events| Broker[RabbitMQ]
Services -->|Cache| Redis[Redis Cluster]
end
The system prioritizes Isolation over Convenience. Microservices share no database tables. All inter-service communication occurs via well-defined APIs (synchronous read) or Integration Events (asynchronous write/react). This ensures that individual components can evolve, scale, and fail independently.
Decomposition of the domain into autonomous services prevents the monolithic "big ball of mud." Each service encapsulates a specific business capability (e.g., "Manage Identity," "Execute Workflow").
Strict adherence to Domain-Driven Design (DDD). The concept of a "User" in the Identity Service (auth credentials) is distinct from a "User" in the Workflow Service (actor in a process).
Write operations enabling cross-context side effects MUST be asynchronous. This decoupling is enforcing via the Outbox Pattern to guarantee atomic persistence and event publication.
To ensure loose coupling, every microservice owns its private database schema. Direct database access across service boundaries is strictly prohibited.
Multi-tenancy is enforced at the Middleware Layer (Identity Injection) and the Data Layer (Row-Level Security / Discriminator Columns). This "Defense in Depth" strategy prevents data leakage.
No service is deployed without structured logging, distributed tracing (OpenTelemetry), and health checks. "If you can't measure it, you can't manage it" is a core tenet.
- Responsibility: Authentication (AuthN), Token Issuance (JWT), and User/Role Management.
- Owned Data: Users, Roles, Permissions, Refresh Tokens.
- Exposed APIs:
/api/auth/login,/api/auth/register,/api/auth/refresh. - Published Events:
UserCreated,UserRoleAssigned.
- Responsibility: Lifecycle management of tenants (Organization accounts).
- Owned Data: Tenants, Subscription Plans, Tenant Settings.
- Published Events:
TenantCreated,TenantSuspended,TenantPlanUpdated.
- Responsibility: Definition of dynamic entity structures (Schemas) and fields.
- Owned Data: EntityDefinitions, FieldDefinitions.
- Scaling: High-read, low-write. heavy caching via Redis.
- Responsibility: Storage and retrieval of dynamic data instances based on Metadata definitions.
- Owned Data: DynamicDocuments (JSONB).
- Extensibility: Supports versioning and soft-deletes natively.
- Responsibility: State machine execution engine. Manages transition logic and process history.
- Owned Data: WorkflowDefinitions, WorkflowInstances, TransitionHistory.
- Consumed Events:
DocumentStatusChanged(triggers transitions).
- Responsibility: Rule-based background processing triggered by system events.
- Owned Data: AutomationRules, TriggerDefinitions, ExecutionLogs.
- Pattern: Consumes all integration events; evaluates rules; dispatches commands.
- Responsibility: Binary object storage management (S3/Local abstraction).
- Owned Data: FileMetadata, Blobs (reference).
- Responsibility: L7 Routing, SSL Termination, Rate Limiting, Request Correlation Injection.
- Owned Data: None (Stateless).
We utilize PostgreSQL 16+ as the primary persistence store. Each service connects to a dedicated logical database (e.g., outclass_identity, outclass_tenant).
The Document Service utilizes PostgreSQL's JSONB column type to store schemaless data, allowing runtime definition of fields without DDL changes, while maintaining potential for GIN indexing on specific JSON paths.
All tables include a TenantId (GUID) column.
- Write Path: Application-layer validation ensures
TenantIdis injected from the authenticated context. - Read Path: Global Query Filters in EF Core automatically append
WHERE TenantId = @CurrentTenantIdto all queries.
To guarantee eventual consistency, modifying data and publishing an event is an atomic transaction.
- Application transaction starts.
- Entity state is updated.
- Event is serialized and written to
OutboxMessagestable in the same transaction. - Transaction commits.
- Background worker (CDC or Polling) publishes
OutboxMessagesto RabbitMQ.
RabbitMQ is the backbone. We use a Topic Exchange (outclass.events) allowing services to subscribe to specific routing keys (e.g., identity.user.created).
Consumers must handle duplicate message delivery.
- Pattern: Trace
EventId. CheckProcessedEventstable before execution. - Recovery: If processing fails, the message is NACK'd and retried with exponential backoff.
Events that fail processing after maximum retries are routed to a Dead Letter Queue (DLQ) for human inspection and manual replay.
- Gateway Layer: Identifies tenant via
X-Tenant-Idheader or subdomain (future). - Context Layer: Middleware validates the existence of the tenant and injects
ITenantContextinto the DI container.
Current implementations use Discriminator-based partitioning (Shared Database, Shared Schema).
- Pros: Operational simplicity, efficient resource usage.
- Cons: "Noisy neighbor" risk.
The architecture supports upgrading premium tenants to Database-per-Tenant isolation by changing the connection string resolution logic in the Repository layer, without rewriting business logic.
Standard OAuth 2.0 / OIDC flows.
- Client requests token from Identity Service.
- Identity Service validates credentials and issues signed JWT (Access Token) and Refresh Token.
- Gateway validates JWT signature at the edge.
Permissions are embedded in JWTs as claims.
- Service-Level:
[Authorize(Roles = "Admin")] - Resource-Level: Logic checks
User.HasPermission("document.write").
Internal traffic is secured via mTLS (infrastructure) or Client Credentials (application level) to ensure zero-trust networking.
The Next.js frontend retrieves EntityDefinitions from the Metadata Service and dynamically generates form layouts and data grids.
- Advantage: New fields logic added by admins appear instantly without redeployment.
- Server State: Handled via React Query / SWR (stale-while-revalidate).
- UI State: Local React Context or Zustand.
All frontend routes (except public/system) are protected by a TenantGuard which ensures a valid tenant context is active before loading distinct modules.
OpenTelemetry is instrumented in every service. A strict TraceId propagation policy ensures a request can be tracked from Nginx -> Gateway -> Identity -> Database.
Logs are structured (JSON) utilizing Serilog. They include correlation IDs, Tenant IDs, and Environment data, ingestible by ELK or Seq.
/health and /ready endpoints expose the status of the service and its dependencies (DB, Redis, RabbitMQ) for the container orchestrator.
Docker containers are stateless and immutable. Configuration is injected via Environment Variables (ASPNETCORE_ENVIRONMENT, ConnectionStrings__*).
Services are designed to be run as ReplicaSets.
- State: No sticky sessions. State is offloaded to Redis/Postgres.
- Workers: Background workers use distributed locking (Redis) to prevent race conditions when multiple instances run.
- Build: Parallel builds of Docker images.
- Test: Unit tests run in isolation; Integration tests run against ephemeral containers (Testcontainers).
- Push: Semantic version tagging.
- Deploy: Helm charts update Kubernetes manifests.
- Scalability: System must support 10,000+ concurrent tenants per cluster.
- Performance: P95 API latency < 200ms for core read operations.
- Data Durability: RPO (Recovery Point Objective) < 5 minutes (WAL archiving).
- Availability: 99.9% uptime uptime SLA.
Compute is cheap. We utilize Kubernetes HPA (Horizontal Pod Autoscaling) based on CPU/Memory/Request metrics.
- Read Replicas: CQRS queries can be offloaded to read-only replicas.
- Sharding: Future roadmap includes consistent hashing to shard Tenant Data across multiple physical database clusters.
Redis serves as a 2nd-level cache. Aggressive caching of Metadata definitions is critical for performance.
Trunk-Based Development. Short-lived feature branches merged via Pull Request.
Conventional Commits standard (feat:, fix:, chore:) to automate changelog generation.
All public APIs must be versioned (/api/v1/...). Breaking changes require a new version or content negotiation strategy.
| Risk | Impact | Mitigation Strategy |
|---|---|---|
| Distributed Transactions | Data Inconsistency | Implement Sagas and Eventual Consistency (Outbox). |
| Tenant Data Leak | Critical Security Failure | Enforce TenantID filters at global DB context level; comprehensive unit testing of filters. |
| System Complexity | Developer friction | Extensive documentation; SDKs; Local development containerization. |
Establish Identity triggers, Dynamic Schema engine, Basic Workflow transitions, and deployment pipelines.
SSO/SAML integration, Audit Log export, Database-per-tenant option, Advanced Analytics.
Marketplace for "Solution Templates", Public API SDKs, Webhooks system, Mobile layout rendering.
AI-assisted workflow generation, Predictive analytics on tenant data, Natural Language querying.