CMS Platform · Spring Boot 3.5 · Java 21
Elly
A powerful multi-tenant Content Management System designed for speed, isolation, and scalability.
What is Elly?
Overview and four pillars
Elly is a headless CMS and rapid MVP platform built on Spring Boot 3.5. Pages, components, dynamic forms, asynchronous email and user authentication — all isolated per tenant.
Content
Page → Component → Banner / Widget → Post → Comment / Rating
Auth
User → Role → Permission · Login · Register · RefreshToken · OAuth2
Form
FormDefinition (JSONB) → ConditionEvaluator → FormSubmission
MailAccount → Async Queue → Thymeleaf → Gmail SMTP
All Domain Entities
Auth Architecture
JWT flow, OAuth2, and refresh tokens
JWT Login Flow
- POST /api/auth/loginAdminLoginInterceptor · TenantLoginInterceptor
- JWT GenerationAccess + Refresh · loginSource & tenantId claim
- POST /api/auth/refreshValidate · revoke check · issue new Access
Registration & OAuth2
- POST /api/auth/registerCreate user · assign role · async verification email
- OAuth2 ProvidersGoogle · Facebook · GitHub → SuccessHandler → JWT
- Redis Auth Cacheauth:user:{username} · TTL 30m · 3 SQL → 1 GET
| Field | Description |
|---|---|
| token | UUID · unique per session |
| expiryDate | LocalDateTime |
| revoked | Boolean · logout flag |
| user | ManyToOne → User |
Form System
JSONB schema, validation strategy, conditional fields
FormDefinition (JSONB)
- idUUID · Primary Key
- versionInteger · schema versioning
- schemaJSONB → FormSchema (fields + config)
- activeBoolean · publish state
FieldDefinition
- typetext · select · number
- validationmin · max · regex pattern
- conditionConditionRule: field · operator · value
- operatorsEQUALS · NOT_EQUALS · GT · LT
Strategy Pattern
Submission Flow
- 1.Fetch FormDefinition
- 2.Iterate fields → ConditionEvaluator
- 3.Hidden → strip key from payload
- 4.Visible → run FieldValidator strategy
- 5.Cleaned → save FormSubmission (JSONB)
Email System
Async messaging, retry & DLQ
Async Mail Pipeline
- 1. POST /api/v1/emails/sendJWT-protected endpoint
- 2. EmailLog PENDINGPersisted to DB · 202 Accepted returned immediately
- 3. RabbitMQ email-queueOnly emailLogId is published
- 4. ConsumerFetch log → Thymeleaf render → TenantMailSenderFactory → Gmail SMTP
- 5. Success / FailureSENT · retry-queue TTL 30s · max 3× → FAILED + DLQ
MailAccount (Per Tenant)
- smtpHostsmtp.gmail.com
- smtpPort587 (TLS)
- passwordAES-256 encrypted
- verifySMTP test before send
EmailLog & Rescue Job
EmailLog fields: recipient · subject · templateName · payloadJson · status · retryCount · errorMessage · sentAt
EmailRescueJob: @Scheduled every 5 minutes · finds PENDING records older than 5 minutes · re-queues batches of 50.
Layered Architecture
Controller → Service → Repository → Entity
Multi-Tenancy
Database-per-tenant isolation
Full Isolation
Each tenant has its own PostgreSQL database. Cross-tenant data leaks are impossible.
ThreadLocal Context
TenantContext uses ThreadLocal for request-scoped isolation; guaranteed cleanup in finally blocks.
HikariCP Pools
Each tenant DB has its own optimized HikariCP pool — no resource contention.
Redis Cache Isolation
Cache keys prefixed: {tenantId}::{cacheName}::{key} — automatic tenant-scoped scope.
Security & Authentication
JWT, OAuth2, RBAC and granular permissions
JWT Auth
- Access + Refresh token pair
- tenantId & loginSource claims
- Redis auth cache — TTL 30m
- 3 SQL → 1 Redis GET
OAuth2
- Google · Facebook · GitHub
- OAuth2AuthenticationSuccessHandler
- Seamless JWT integration
- Stateless by design
RBAC
- User → Role → Permission (M2M)
- SUPER_ADMIN · ADMIN · EDITOR · VIEWER
- 40+ granular permission constants
- @PreAuthorize · @EnableMethodSecurity
| Role | Scope | Permissions |
|---|---|---|
| SUPER_ADMIN | All tenants | Full system · tenant management |
| ADMIN | Own tenant | All CMS operations · user management |
| EDITOR | Own tenant | Create/update content · publish |
| VIEWER | Own tenant | Read-only content access |
Performance Profile
Before/after metrics and optimization priorities
Response Time p95
Throughput
DB Queries / Request
Deployment & Infrastructure
Kubernetes, observability, mail system, CI/CD
Kubernetes Setup
- App Deployment2a-app-deployment.yaml
- Burst Config2b-app-burst.yaml
- HPA Autoscaler5-hpa.yaml
- Monitoring6-monitoring.yaml
Services & Observability
- PostgreSQLMulti-DB · Backup CronJob
- RedisTTL=10min · Graceful fallback
- RabbitMQemail-queue · retry · DLQ
- PrometheusSpring Actuator metrics
- GrafanaReal-time dashboards
- SonarQubeCI quality gate
Mail System
- Tenant SMTPAES-256 encrypted credentials
- Async sendingRabbitMQ email-queue
- Retry logic3× with 30s backoff
- Dead letter queueFAILED + DLQ on exhaustion
- Verification endpointSMTP test before send
CI/CD & Load Tests
- GitHub ActionsBuild → Test → Deploy
- DockerDockerfile + docker-compose
- k6 Load Testsbaseline · stress · write suites
- SonarQubeQuality gate in pipeline
Current Status & Roadmap
Summary metrics and next steps
Now · High Priority
- Database index rollout
- Connection pool → 50
- Entity Graph for N+1 fix
- Pagination on all lists
Soon · This Sprint
- DTO pattern everywhere
- Redis cache rollout
- Async file upload
- Load test baseline + retest
Later · Scaling
- Read replica setup
- CDN for file uploads
- Multi-region K8s
- Dynamic tenant onboarding