BarakoCMS β
A full-stack CMS suite for .NET. An event-sourced engine, opt-in modules, an admin UI, and a PWA kit.
BarakoCMS is more than a headless engine. You put it together like a coffee order: the engine is the coffee, each module is a shot that makes it stronger, the admin UI is the milk that makes it easy to serve, and pwa-kit is the to-go lid that turns any frontend into an installable, offline app. Order it black and headless, or fully loaded.
TIP
Try it before you read a line of docs. A full instance is running at playground.baryo.dev/barakocms. Sign in with demo_admin / BarakoDemo2026! and use it. Or pull it and run it yourself in one command:
docker compose -f docker-compose.hub.yml up -dWhy BarakoCMS β
Every content project starts with the same tax. You pick a big platform and spend months bending it to your shape, or you pick a headless engine and rebuild the boring parts yourself before you ship a single feature: sign-in, roles, an admin screen, file uploads, email, audit history.
BarakoCMS pays that tax for you. The engine gives you content modeling, event sourcing, and RBAC on day one. The modules cover the parts every real app needs but nobody wants to write again: files, email, device trust, external sign-in, accounting, feature flags, import and export. The admin UI ships with it. And pwa-kit makes the whole thing installable on a phone.
So your time goes to the product, not the plumbing. And you only carry what you use.
The suite β
You do not install one product. You compose a few, and decide how strong the pour is.
- Barako, the full pour. The engine with every module stirred in. It gets stronger and more capable the more modules it carries.
- Decaf, the lean core. The engine on its own, for teams that add only the modules they need.
- The shots. Opt-in modules, each a NuGet package your host adds in one line: Accounting, Import, Files, Email, Device Trust, External Auth, Feature Flags, Portability.
- Milk. The admin UI (
barako-admin). Or take it black and run the API headless behind your own frontend. - The to-go lid. pwa-kit turns any frontend into an installable, offline app.
- The starter kit. create-baryo-app scaffolds a new app on the suite.
- A named drink. A finished product on top, like BaryoClub: the engine, a few modules, a custom UI, and the to-go lid, served as one installable app.
Coffee comes in endless blends, and so does this. Take the modules that fit your product, leave the ones that don't, and pour the flavor that suits you. The core stays lean, and the combination is yours to make.
Stability. BarakoCMS follows semantic versioning. Breaking changes land only on major versions and are documented in the changelog. The security surface (auth, RBAC, and the write path) has been through a dedicated hardening pass: rotating refresh tokens with reuse detection, optimistic concurrency on every write, SSRF-guarded outbound webhooks, rate limiting, and fault-isolated workflows that can never block a content save.
BarakoCMS is built on FastEndpoints and MartenDB, so content is event-sourced in PostgreSQL: every change is an event, the current state is a replay, and rolling back is a first-class operation rather than a restore from backup.
π― Try it β three steps β
1. Play with the live demo. A full instance runs at playground.baryo.dev/barakocms β sign in with demo_admin / BarakoDemo2026!. Model a content type, mark a field Sensitive or Hidden, publish an entry, then roll a change back from its history.
2. Run it yourself in one command. Pull the published images and start the API + admin UI (no build, no clone):
docker compose -f docker-compose.hub.yml up -d
# admin UI β http://localhost:3000 Β· API β http://localhost:5005See Docker Hub for the image tags and a ready-to-use compose file.
3. See a real app built on it. BaryoClub is a club membership and treasury manager that composes the Accounting, Import, Files, and Email.Resend modules on top of BarakoCMS β roster import, dues and levies, payments with receipt photos, printable statements, and real double-entry accounting underneath. Its README has a full local setup guide, so you can run the sample end to end.
π¦ Quick Start β
Prerequisites β
- .NET 8 SDK
- Docker Desktop (or PostgreSQL 16+)
1. Clone & Setup β
git clone https://github.com/yourusername/barakoCMS.git
cd barakoCMS
docker compose up -d # Start PostgreSQL2. Configure β
Update barakoCMS/appsettings.json:
{
"ConnectionStrings": {
"DefaultConnection": "Host=localhost;Database=barako_cms;Username=postgres;Password=postgres"
},
"JWT": {
"Key": "your-super-secret-key-that-is-at-least-32-chars-long"
}
}3. Run β
dotnet run --project barakoCMSOpen Swagger UI: http://localhost:5000/swagger
π₯οΈ Admin UI (New!) β
BarakoCMS includes a full-featured Admin Dashboard built with Next.js 16.
Features β
- Dashboard: Health status, quick stats
- Content Management: Create, Edit, List, Search, Filter
- Schema Management: Define and view Content Types
- Workflows: Create and manage automation rules
- Roles & UserGroups: RBAC administration
- Settings Management: Runtime configuration toggles (Kubernetes, HealthChecks UI, Logging)
- Monitoring: System metrics, Kubernetes cluster status (when enabled)
- Ops: Health Checks, Logs, Backups (Create, Download, Restore, Delete)
Running the Admin UI β
cd admin
npm install
npm run devOpen Admin Dashboard: http://localhost:3000
Default Login: arnex / password123 (or see seeded data)
π What's New in v2.0 (Phase 1: Advanced RBAC) β
Production-Ready Enterprise Features: Advanced role-based access control with granular permissions
β¨ Advanced RBAC System β
Complete Role & Permission Management:
- Roles: Create roles with content-type-specific CRUD permissions
- UserGroups: Organize users into groups for easier management
- User Assignment: Assign roles and groups to users dynamically
- Granular Permissions: Per-content-type Create, Read, Update, Delete controls
- Conditional Access: JSON-based conditions (e.g.,
"author": { "_eq": "$CURRENT_USER" }) - System Capabilities: Global permissions beyond content (e.g.,
view_analytics)
API Endpoints (18 new endpoints):
# Role Management
POST /api/roles # Create role
GET /api/roles # List roles
GET /api/roles/{id} # Get role
PUT /api/roles/{id} # Update role
DELETE /api/roles/{id} # Delete role
# UserGroup Management
POST /api/user-groups # Create group
GET /api/user-groups # List groups
GET /api/user-groups/{id} # Get group
PUT /api/user-groups/{id} # Update group
DELETE /api/user-groups/{id} # Delete group
POST /api/user-groups/{id}/users # Add user to group
DELETE /api/user-groups/{id}/users/{userId} # Remove user
# User Assignment
POST /api/users/{id}/roles # Assign role to user
DELETE /api/users/{id}/roles/{roleId} # Remove role
POST /api/users/{id}/groups # Add user to group
DELETE /api/users/{id}/groups/{groupId} # Remove userExample - Create Role:
POST /api/roles
Authorization: Bearer {ADMIN_TOKEN}
{
"name": "Content Editor",
"description": "Can edit own articles",
"permissions": [{
"contentTypeSlug": "article",
"create": { "enabled": true },
"read": { "enabled": true },
"update": {
"enabled": true,
"conditions": { "author": { "_eq": "$CURRENT_USER" } }
},
"delete": { "enabled": false }
}],
"systemCapabilities": ["view_analytics"]
}π‘οΈ v1.2 Features (Still Available) β
- β Optimistic Concurrency Control - Prevent data conflicts
- β Async Workflow Processing - Non-blocking background tasks
- β Resilience Patterns - HTTP retries, circuit breakers
π§© v2.1 Workflow System (Phase 2) β
BarakoCMS includes a powerful plugin-based workflow system:
- 6 Built-in Actions: Email, SMS, Webhook, CreateTask, UpdateField, Conditional
- Custom Plugins: Create your own actions without touching core code
- Template Variables: Dynamic content substitution (
{{data.FieldName}}) - Dry-Run Testing: Test workflows without side effects
- JSON Schema Validation: Catch errors before execution
- Execution Logging: Full audit trail of workflow runs
- Auto-Discovery: New actions automatically appear in API
Quick Example:
# Create custom plugin
public class SlackAction : IWorkflowAction
{
public string Type => "Slack";
public async Task ExecuteAsync(...) { /* send to Slack */ }
}
# Use in workflow
{
"actions": [{
"type": "Slack",
"parameters": {
"message": "New order: {{data.OrderNumber}}"
}
}]
}See Plugin Development Guide and Migration Guide to get started.
π¦ Official modules β
Core stays lean and generic. Specialized capabilities ship as optional NuGet modules you opt into per project β the same IBarakoModule contract you can implement yourself. Each is MPL-2.0.
| Module | Package | What it adds |
|---|---|---|
| Accounting | A chart-of-accounts-agnostic double-entry ledger β accounts, balanced journal entries, and reporting. | |
| Import | Bulk import .xlsx/CSV into content via the zero-dependency Talaan reader, through the CMS's own validation, permissions, and event sourcing. | |
| Files | File upload + download stored in Postgres via Marten β receipts, photos, and documents attached to your records. | |
| Email.Resend | An IEmailService backed by the Resend API, so password-reset, OTP sign-in, and workflow emails deliver for real. |
Enable the ones you want when you register the CMS β core knows nothing about them:
builder.Services.AddBarakoCMS(builder.Configuration, modules =>
{
modules.Add(new BarakoCMS.Accounting.AccountingModule());
modules.Add(new BarakoCMS.Files.FilesModule());
modules.Add(new BarakoCMS.Import.ImportModule());
modules.Add(new BarakoCMS.Email.Resend.ResendEmailModule());
});
// After the app is built, run any module seeders (roles, reference data):
await app.RunBarakoModuleSeedersAsync();BaryoClub is a sample app that composes all four into a club membership and treasury manager.
π Core Features β
β‘ Unmatched Speed β
- FastEndpoints: Minimal overhead, maximum throughput
- MartenDB: PostgreSQL-backed JSON document store with event sourcing
- Async-First: Non-blocking I/O throughout
π§© Infinite Extensibility β
- Plugin Architecture: Swap
IEmailService,ISmsService,ISensitivityService - Custom Content Types: No schema migrations needed
- Workflow Engine: Event-driven automation
- Projections: Transform events into read models
π‘οΈ Enterprise-Grade Robustness β
- β Advanced RBAC: Granular role-based access control with conditions
- β Event Sourcing: Full audit trail, time travel, replay
- β Idempotency: Duplicate request protection
- β Optimistic Concurrency: Race condition prevention
- β Sensitive Data: Field-level masking/hiding
- β Resilience: Built-in retries, circuit breakers
Problem Solved: Prevents data loss when multiple users edit the same content simultaneously.
How It Works:
// Client sends version with update
PUT /api/contents/{id}
{
"id": "...",
"data": { "title": "Updated Title" },
"version": 1 // β¬
οΈ Must match current DB version
}
// β
If version matches β Update succeeds (version becomes 2)
// β If version mismatches β 412 Precondition FailedUser Experience:
User A: Saves changes (v1 β v2) β
User B: Tries to save with v1 β
Gets error: "Content modified by another user. Please refresh."
User B: Refreshes, sees latest content (v2)
User B: Makes changes, saves (v2 β v3) β
Developer Usage:
# Get current content (includes version in event stream)
GET /api/contents/{id}
# Update with version check
PUT /api/contents/{id}
{
"id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"data": { "Name": "Updated Name" },
"version": 2 # Current version from DB
}β‘ Async Workflow Processing β
Problem Solved: Heavy workflows (emails, notifications) no longer block API responses.
Architecture:
sequenceDiagram
participant Client
participant API
participant DB
participant AsyncDaemon
participant WorkflowEngine
Client->>API: PUT /api/contents/{id}
API->>DB: Save ContentUpdated event
API-->>Client: 200 OK (instant response)
Note over AsyncDaemon: Background Processing
AsyncDaemon->>DB: Poll for new events
AsyncDaemon->>WorkflowProjection: Process event
WorkflowProjection->>WorkflowEngine: Execute workflows
WorkflowEngine->>WorkflowEngine: Send emails, notificationsPerformance Impact:
- Before: 500-2000ms (includes email sending)
- After: 50-100ms (instant API response)
- Workflows: Process in background within 1-2 seconds
π‘οΈ Resilience & Health Checks β
- HTTP Retries: Automatic retry with exponential backoff for external services
- Circuit Breaker: Prevents cascade failures
- Health Endpoint:
/healthmonitors database connectivity
π Core Features β
β‘ Unmatched Speed β
- FastEndpoints: Minimal overhead, maximum throughput
- MartenDB: PostgreSQL-backed JSON document store with event sourcing
- Async-First: Non-blocking I/O throughout
π§© Infinite Extensibility β
- Plugin Architecture: Swap
IEmailService,ISmsService,ISensitivityService - Custom Content Types: No schema migrations needed
- Workflow Engine: Event-driven automation
- Projections: Transform events into read models
π‘οΈ Enterprise-Grade Robustness β
- β Event Sourcing: Full audit trail, time travel, replay
- β Idempotency: Duplicate request protection
- β Optimistic Concurrency: Race condition prevention
- β RBAC: Role-based access control
- β Sensitive Data: Field-level masking/hiding
- β Resilience: Built-in retries, circuit breakers
π Developer Guide β
Content Management Workflow β
1. Define Content Type (Schema) β
POST /api/content-types
Authorization: Bearer <TOKEN>
{
"name": "Blog Post",
"fields": {
"title": "string",
"body": "richtext",
"author": "string",
"publishDate": "datetime",
"tags": "array"
}
}2. Create Content (Draft) β
POST /api/contents
Authorization: Bearer <TOKEN>
Idempotency-Key: unique-request-id-123
{
"contentType": "blog-post", # Auto-generated slug
"data": {
"title": "Getting Started with BarakoCMS",
"body": "<p>Welcome to our CMS...</p>",
"author": "Jane Doe",
"publishDate": "2024-01-15T10:00:00Z",
"tags": ["tutorial", "cms"]
},
"status": 0, # 0=Draft, 1=Published, 2=Archived
"sensitivity": 0 # 0=Public, 1=Sensitive, 2=Hidden
}
# Response
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"message": "Content created successfully"
}3. Update Content (with Concurrency Check) β
PUT /api/contents/550e8400-e29b-41d4-a716-446655440000
Authorization: Bearer <TOKEN>
Idempotency-Key: unique-request-id-456
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"data": {
"title": "Getting Started with BarakoCMS (Updated)",
"body": "<p>Welcome! This guide has been updated...</p>",
"author": "Jane Doe",
"publishDate": "2024-01-15T10:00:00Z",
"tags": ["tutorial", "cms", "getting-started"]
},
"version": 1 # β¬
οΈ IMPORTANT: Current version
}
# Success: 200 OK
# Conflict: 412 Precondition Failed4. Publish Content β
PUT /api/contents/550e8400-e29b-41d4-a716-446655440000/status
Authorization: Bearer <TOKEN>
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"newStatus": 1 # Publish
}5. Query Content β
# Get all published blog posts
GET /api/contents?contentType=blog-post&status=1
# Get specific content
GET /api/contents/550e8400-e29b-41d4-a716-446655440000Authentication & Authorization β
Login β
POST /api/auth/login
{
"username": "admin",
"password": "SecurePassword123!"
}
# Response
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiry": "2024-01-16T10:00:00Z"
}Use Token β
# Include in every authenticated request
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...Workflow Automation β
Create event-driven workflows that trigger automatically when content changes.
How Workflows Work β
- Event Triggered - Content created/updated/status changed
- Async Processing - Background daemon picks up event (no API delay)
- Workflow Matched - System finds workflows matching content type + event
- Actions Executed - Email, SMS, webhooks, etc. run automatically
Create a Workflow β
POST /api/workflows
Authorization: Bearer {ADMIN_TOKEN}
{
"name": "Attendance Confirmation Email",
"description": "Send email to attendee after record creation",
"triggerContentType": "AttendanceRecord",
"triggerEvent": "Created",
"conditions": {
"status": "Published"
},
"actions": [
{
"type": "SendEmail",
"config": {
"to": "{{data.Email}}",
"subject": "Attendance Record Created - {{data.FirstName}} {{data.LastName}}",
"body": "Hello {{data.FirstName}},\n\nYour attendance record has been successfully created.\n\nThank you!"
}
}
]
}Template Variables β
Use dynamic values from the content in your workflows:
{
"to": "{{data.Email}}", // Field from record data
"subject": "Record {{id}} Created", // Record ID
"body": "Status: {{status}}" // Record status
}Example: Email to Record's Email Field β
When creating an attendance record:
POST /api/contents
{
"contentType": "AttendanceRecord",
"data": {
"FirstName": "John",
"LastName": "Doe",
"Email": "john.doe@company.com", # Email recipient
"BirthDay": "1990-01-01"
},
"status": 1 // Published
}The workflow automatically sends email to john.doe@company.com using the {{data.Email}} template variable.
Available Actions (Current) β
- SendEmail - Email notifications with templates
- SendSms - SMS alerts (via ISmsService)
Supported Events β
Created- When content is first createdUpdated- When content is modifiedStatusChanged- When content status changesDeleted- When content is removed
Conditional Execution β
Add conditions to control when workflows run:
{
"conditions": {
"status": "Published", // Only for published content
"data.Salary": { "_gt": 100000 } // Only if salary > 100k
}
}Multiple Actions β
Chain multiple actions in one workflow:
{
"actions": [
{
"type": "SendEmail",
"config": {
"to": "{{data.Email}}",
"subject": "Record Created"
}
},
{
"type": "SendEmail",
"config": {
"to": "manager@company.com",
"subject": "New Submission: {{data.FirstName}}"
}
}
]
}Performance: All workflows run asynchronously in background - zero impact on API response time.
Advanced Features β
Event Sourcing & Time Travel β
# View all versions
GET /api/contents/{id}/history
# Response
[
{
"version": 1,
"eventType": "ContentCreated",
"timestamp": "2024-01-15T10:00:00Z",
"data": { ... }
},
{
"version": 2,
"eventType": "ContentUpdated",
"timestamp": "2024-01-15T11:30:00Z",
"data": { ... }
}
]
# Rollback to version 1
POST /api/contents/{id}/rollback/1Sensitive Data Protection β
# Create content with sensitive fields
POST /api/contents
{
"contentType": "employee-record",
"data": {
"name": "John Doe",
"ssn": "123-45-6789",
"salary": 75000
},
"sensitivity": 1 # Sensitive
}
# Standard user gets masked data
GET /api/contents/{id}
# Response
{
"name": "John Doe",
"ssn": "***-**-6789", # Masked
"salary": "****" # Masked
}
# SuperAdmin gets full data
GET /api/contents/{id}
Authorization: Bearer <SUPERADMIN_TOKEN>
# Response
{
"name": "John Doe",
"ssn": "123-45-6789", # Full
"salary": 75000 # Full
}Idempotency Protection β
# Prevent duplicate submissions
POST /api/contents
Idempotency-Key: unique-client-generated-uuid
# If retried with same key β Same response, no duplicate
POST /api/contents
Idempotency-Key: unique-client-generated-uuid # Same key
# Returns: 409 Conflict (already processed)π§ͺ Testing β
Run Full Test Suite β
dotnet testRun Specific Tests β
# Stabilization tests (concurrency, async workflows)
dotnet test --filter "FullyQualifiedName~StabilizationVerificationTests"
# Attendance POC tests
dotnet test AttendancePOC.Tests/AttendancePOC.Tests.csprojTest Coverage (v1.2) β
- β
Optimistic Concurrency: Verified via
StabilizationVerificationTests - β Async Workflows: Infrastructure verified, daemon operational
- β Sensitive Data Masking: Multiple role-based tests
- β Idempotency: Duplicate request handling
- Overall: 64/74 tests passing (86%)
π¦ Use as NuGet Package β
Installation β
dotnet add package BarakoCMSSetup β
// Program.cs
using barakoCMS.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Register BarakoCMS services
builder.Services.AddBarakoCMS(builder.Configuration);
var app = builder.Build();
// Use BarakoCMS middleware
app.UseBarakoCMS();
app.Run();Configure β
// appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Host=localhost;Database=your_db;Username=postgres;Password=postgres"
},
"JWT": {
"Key": "your-secret-key-minimum-32-characters-long"
}
}ποΈ Architecture β
Technology Stack β
- Framework: .NET 8
- API: FastEndpoints (high-performance minimal API)
- Database: PostgreSQL + MartenDB (Event Sourcing)
- Authentication: JWT Bearer Tokens
- Resilience: Polly (retry, circuit breaker)
- Testing: xUnit + TestContainers
Key Design Patterns β
- Event Sourcing: All changes stored as events
- CQRS: Separate read/write models via projections
- Repository Pattern:
IDocumentSessionabstracts data access - Dependency Injection: Constructor injection throughout
- Async/Await: Non-blocking I/O
π§ͺ Attendance POC (Real-World Example) β
See how BarakoCMS handles a real-world scenario with sensitive data and workflows.
Features β
- Sensitive Fields: SSN (Hidden), BirthDate (Masked)
- RBAC: Different views for SuperAdmin, HR, Standard users
- Workflows: Auto-email on submission
- Idempotency: Duplicate submission prevention
Run POC β
cd AttendancePOC
dotnet run
# Seeds sample data automatically
# Try: GET /api/contents with different role tokensπ Troubleshooting β
Database Connection Failed β
Error: Npgsql.NpgsqlException: Failed to connect
Solutions:
- Check PostgreSQL is running:
docker ps - Start database:
docker compose up -d - Verify connection string in
appsettings.json - Check port 5432 is not blocked
Port Already in Use β
Error: IOException: Failed to bind to http://localhost:5000
Solutions:
- Change port in
Properties/launchSettings.json - Kill process using port 5000:
lsof -ti:5000 | xargs kill -9(macOS/Linux)
Concurrency Conflict (412) β
Error: 412 Precondition Failed when updating content
Cause: Content version changed since you loaded it
Solution:
- Refresh content to get latest version
- Retry update with new version number
Health Check Returns Unhealthy β
Error: /health endpoint shows database unhealthy
Solutions:
- Verify PostgreSQL is running
- Check connection string
- Ensure database user has proper permissions
Kubernetes Monitoring Not Working β
Symptom: Admin UI shows "Kubernetes monitoring is disabled or not available in this environment"
Prerequisites:
- Docker Desktop installed
- Kubernetes enabled in Docker Desktop
Setup Kubernetes in Docker Desktop:
- Open Docker Desktop
- Go to Settings (gear icon)
- Click on Kubernetes in the left sidebar
- Check "Enable Kubernetes"
- Click "Apply & Restart"
- Wait for the green Kubernetes indicator (bottom left)
Verify Kubernetes is Running:
# Check if kubectl is working
kubectl cluster-info
# Should see something like:
# Kubernetes control plane is running at https://kubernetes.docker.internal:6443Restart BarakoCMS:
docker compose restart appCheck Logs:
docker compose logs app | grep -i kubernetes
# Should see:
# Kubernetes client initialized using local kubeconfigEnable in Settings:
- Open Admin UI at
http://localhost:3000/settings - Toggle Kubernetes Monitoring to ON
- Visit
/ops/healthpage to see cluster status
Note: If you don't need Kubernetes monitoring, simply keep the toggle OFF in Settings. The feature is optional.
π Additional Resources β
Documentation β
- DEVELOPMENT_STANDARDS.md - Field types, naming conventions, validation
- CHANGELOG.md - Version history
- CONTRIBUTING.md - Contribution guidelines
- CODE_OF_CONDUCT.md - Community standards
For AI Agents β
- llms.txt - Codebase context for LLMs
- .cursorrules - Coding standards for AI assistants
- CITATIONS.cff - Citation metadata
π€ Contributing β
We welcome contributions! All contributors must sign our Contributor License Agreement (https://github.com/BaryoDev/barakoCMS/blob/master/CLA).
Why CLA? β
The CLA protects both you and the project:
- β You retain ownership of your contributions
- β You grant BarakoCMS permission to use your code
- β Prevents legal issues around commercial licensing
- β Enables future dual-licensing (CE/EE) without re-permission
How It Works β
First-Time Contributors:
- Open a Pull Request
- @cla-assistant will automatically comment
- Click the link to sign the CLA (takes 30 seconds)
- Your PR will be automatically updated
After Signing:
- Your GitHub username is permanently recorded
- No need to sign again for future PRs
- Start contributing immediately!
See CLA.md for full agreement text.
Development Workflow β
- Fork the repository
- Create feature branch:
git checkout -b feature/amazing-feature - Make changes and add tests
- Ensure tests pass:
dotnet test - Commit:
git commit -m 'Add amazing feature' - Push:
git push origin feature/amazing-feature - Open Pull Request (CLA will be requested automatically)
Code Standards β
- Follow existing code style (FastEndpoints vertical slices)
- Add tests for new features
- Update README if adding user-facing features
- Keep PRs focused and small
See CONTRIBUTING.md for detailed guidelines.
π License β
Apache License 2.0
- β Commercial use allowed
- β Modification allowed
- β Distribution allowed
- β Patent use allowed
- π Attribution required
See LICENSE for full terms.
π Support This Project β
If BarakoCMS helps you build better applications, consider supporting the development!
π¨βπ» Author β
Arnel Robles
GitHub: @arnelirobles
Built with β€οΈ by developers, for developers.