Hüseyin DOLHüseyin DOL

CMS Platform · Spring Boot 3.5 · Java 21

Elly

A powerful multi-tenant Content Management System designed for speed, isolation, and scalability.

PostgreSQL · DB-per-Tenant
Redis Cache
RabbitMQ
JWT + OAuth2
Kubernetes-ready
1

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

Email

MailAccount → Async Queue → Thymeleaf → Gmail SMTP

All Domain Entities

PageComponentBannerWidgetPostFormUserPermissionCommentRatingAssetsEmailMailAccountRefreshTokenSeoInfoRoleFormDefinitionFormSubmission
2

Auth Architecture

JWT flow, OAuth2, and refresh tokens

JWT Login Flow

  1. POST /api/auth/login
    AdminLoginInterceptor · TenantLoginInterceptor
  2. JWT Generation
    Access + Refresh · loginSource & tenantId claim
  3. POST /api/auth/refresh
    Validate · revoke check · issue new Access

Registration & OAuth2

  1. POST /api/auth/register
    Create user · assign role · async verification email
  2. OAuth2 Providers
    Google · Facebook · GitHub → SuccessHandler → JWT
  3. Redis Auth Cache
    auth:user:{username} · TTL 30m · 3 SQL → 1 GET
FieldDescription
tokenUUID · unique per session
expiryDateLocalDateTime
revokedBoolean · logout flag
userManyToOne → User
3

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

TextFieldValidatormin/max length, regex
NumberFieldValidatorrange, integer check
SelectFieldValidatorallowed values

Submission Flow

  1. 1.Fetch FormDefinition
  2. 2.Iterate fields → ConditionEvaluator
  3. 3.Hidden → strip key from payload
  4. 4.Visible → run FieldValidator strategy
  5. 5.Cleaned → save FormSubmission (JSONB)
4

Email System

Async messaging, retry & DLQ

Async Mail Pipeline

  1. 1. POST /api/v1/emails/sendJWT-protected endpoint
  2. 2. EmailLog PENDINGPersisted to DB · 202 Accepted returned immediately
  3. 3. RabbitMQ email-queueOnly emailLogId is published
  4. 4. ConsumerFetch log → Thymeleaf render → TenantMailSenderFactory → Gmail SMTP
  5. 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.

5

Layered Architecture

Controller → Service → Repository → Entity

1
IController
Interface contracts, endpoint signatures
2
Controller
HTTP layer, request parsing, response wrapping
3
IService → Service
Business logic, caching, tenant context
4
Repository
Spring Data JPA, Entity Graph queries
5
Entity + DTO
MapStruct mapping, Entity never exposed via API
Java
21 LTS
🍃
Spring Boot
3.5.7
🐘
PostgreSQL
Multi-DB
Redis
Cache
🐇
RabbitMQ
Queues
☸️
Kubernetes
K8s
6

Multi-Tenancy

Database-per-tenant isolation

JWT Token
tenantId claim
JwtTenantFilter
TenantContext.set()
TenantDataSourceRouter
AbstractRoutingDataSource
elly_basedb
elly_tenant1
elly_tenant2

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.

7

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
RoleScopePermissions
SUPER_ADMINAll tenantsFull system · tenant management
ADMINOwn tenantAll CMS operations · user management
EDITOROwn tenantCreate/update content · publish
VIEWEROwn tenantRead-only content access
8

Performance Profile

Before/after metrics and optimization priorities

Response Time p95

2340ms456ms

Throughput

18 req/s187 req/s

DB Queries / Request

47 queries1 query
HIGH
N+1 Query Fix with @EntityGraph
47 queries → 1 query per request
HIGH
HikariCP Pool Size 10 → 50
Prevents connection exhaustion under load
HIGH
Database Indexes on FK columns
Eliminates full table scans — 5–10× speed
MID
Pagination on all list endpoints
Prevents OOM on large datasets
MID
Tenant-prefixed Redis @Cacheable
50–100× on cache hits, graceful fallback
LOW
Read replica + CDN (file uploads)
Scale read operations horizontally
9

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
10

Current Status & Roadmap

Summary metrics and next steps

3
Tenants
40+
Permissions
10×
Perf. Gain
K8s
Production-ready

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