Platform Services
Five production-ready microservices + two React SPAs + Astro landing kit — 100+ REST APIs, each independently deployable with Helm charts, 10-stage CI/CD pipelines, and dedicated databases.
IAM Service
60+ endpoints covering full identity lifecycle for multi-tenant SaaS: signup, password + magic-link, OAuth2/OIDC federation, tenant provisioning, plan enforcement, and access control.
- Self-service signup — creates user + tenant (multi) or joins default (single); platform user always created
- Signup status polling, tenant discovery, and async RabbitMQ tenant provisioning with reaper
- JWT RS256 — 15-min access, 7-day refresh with tenant_id + plan_code claims; JWKS public endpoint
- Magic link passwordless auth — initiate/resend/exchange, TTL configurable, rate-limited, personal workspace
- Brute-force protection — 5 attempts → 15-min lockout; admin unlock; failed-attempt cleanup
- Token revocation — JTI denylist (single signout) + last_global_signout_at timestamp (all sessions)
- Password reset / change — rate-limited reset; change invalidates all sessions; BCrypt strength 12
- Email verification — token-based, resend rate-limited; OAuth verified emails auto-linked
- OAuth2 / OIDC federation — Google, GitHub, Microsoft + PKCE Redis state + tenant-scoped custom OIDC
- Connected accounts — link/unlink, GitHub requires verified email, admin forced unlink remediation
- Platform tenant — 'platform' key personal workspace for every user, auto-joined as MEMBER in all modes
- Tenant owner member mgmt — list, authorities (ADMIN/MEMBER/OWNER), ban, ownership transfer guardrails
- Avatar uploads — two-phase presigned S3/MinIO, old auto-deleted, tenant-isolated prefixes
- Announcements — multi-lingual editor, DRAFT→PUBLISHED lifecycle, 1K-batch async fan-out + WebSocket broadcast
- In-app notifications — persistent table + unread count, mark-as-read bulk/dismiss, STOMP/SockJS per-user push
- Platform admin — users CRUD + set password, ban/unlock, tenants CRUD, invitations/announcements/counts
Gateway Service
Reactive Spring Cloud Gateway — the single entry point. Handles security, context propagation, plan enforcement, and cross-cutting filters so downstream services get a clean, verified request.
- JWT RS256 validation via JWKS (Spring Security OAuth2 Resource Server)
- Header sanitization — strips X-User-*, X-Tenant-ID, X-Audit-*, X-Plan-Code before JWT processing
- Context propagation — X-User-ID, X-Username, X-User-Email, X-User-Authorities, X-Tenant-ID
- Plan code header — extracts plan_code from JWT and propagates as X-Plan-Code; client value overwritten
- Plan feature enforcement — RequiresPlanFeatureFilterFactory for route-level declarative plan checks
- Audit context — AuditContextFilter injects X-Audit-IP, X-Audit-UA, X-Audit-Source
- Monitoring filter — per-tenant request rate, latency, status; Grafana dashboard included
- Correlation ID — generates or propagates X-Correlation-ID on every request; echoed in response
- Platform mode guard — polls IAM /actuator/info for rollout-mode; 503 REFUSING_TRAFFIC on mismatch
- Tenant context filter — multi-tenant from JWT, single-tenant injects default tenant key if missing
- Security response headers — X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, Referrer-Policy
- Aggregated Swagger UI — proxies downstream /api-docs through the gateway
- Configurable public paths via iqkv.gateway.public-paths (OAuth2, magic-link, signup, etc.)
- Reactive PlanResolver WebClient cache — refreshes plan catalog from billing every 10 minutes
- Prometheus metrics + structured JSON logging with MDC correlation and tenant context
Billing Service
40+ endpoints, gateway-agnostic payment abstraction. Runtime-selectable Stripe or Lemon Squeezy, tenant-to-customer mapping, FLAT + PER_SEAT pricing, trials, and normalized webhook ingestion.
- Runtime gateway selection — GatewayType (STRIPE / LEMON_SQUEEZY); @ConditionalOnGateway bean wiring
- PaymentGatewayPort abstraction — both adapters implement one unified Strategy interface
- Plan catalog — config-driven YAML; billingPeriod (MONTHLY/ANNUAL), scope (TENANT/USER), active flag
- Pricing models — FLAT (per billing period) + PER_SEAT (price per user/seat), trialPeriodDays
- Seat adjustment endpoint — PATCH seats for PER_SEAT plans; validates against plan maxUsers
- Customer provisioning — auto-created on tenant.provisioned RabbitMQ event; stores externalCustomerId
- Billing settings — billing email, company name, taxId/VAT/GST, billingAddress JSONB, currency
- Checkout sessions — Stripe Checkout / Lemon Squeezy variant checkout per tenant per plan
- Customer portal — Stripe Billing portal or Lemon Squeezy portal sessions for TENANT_OWNER
- Subscription lifecycle — create/update/cancel/pause/reactivate via gateway; isInTrial + trialDaysLeft
- Entitlements API — GET /entitlements/me: planCode, status, trials, typed PlanEntitlement quotas
- Refunds API — create/list full or partial refunds; TENANT_OWNER and PLATFORM_ADMIN access
- Idempotent webhook processing — signature verification (Stripe / Lemon HMAC-SHA256)
- Normalized webhook events — subscription, invoice, payment, charge.refunded, refund.created
- Daily scheduled jobs — trial-ending + payment-overdue notifications (ShedLock-guarded)
- PlanFeatureRegistry — in-memory O(1) feature evaluation; typed quotas (maxUsers, maxProjects)
- Grafana dashboard — MRR total, payments/subscriptions/seat adjustments, webhooks, latencies
Audit Service
Centralized, event-driven audit trail. Passively observes all RabbitMQ platform events, normalizes them, and persists them as compliance-ready, searchable records with JSONB metadata.
- Passive observation — wildcard routing keys; zero code changes required in domain services
- Event normalization — UserEvent, TenantEvent, Subscription, Invoice, etc. → AuditRecord
- Technical context enrichment — client IP and User-Agent from X-Audit-* Gateway headers
- JSONB metadata storage — full event payload preserved, custom MyBatis JsonbTypeHandler
- ActivitySeverity enum + severity filter on search/count endpoints
- SPI-based extensibility — AuditProvider interface; plug in Elasticsearch or custom SIEM
- Dedicated PostgreSQL database — high-volume logging isolated from business transaction DB
- PLATFORM_ADMIN search API — paginated, filterable by user, tenant, action, severity, date range
- Audit detail view — full record with structured JSONB metadata expansion
- RabbitMQ consumer — message converter, DLQ, conditional guards, tenantKey mapping
- Custom Prometheus metrics — event consumption (by type/source), persistence duration, search latency, storage usage
CMS Service
Content management microservice for static pages, multi-language support, and hierarchical content. Tenant-isolated with event-driven publishing.
- Static page management — draft/published status, page templates
- Multi-language support — locale-based content with en-US fallback
- Hierarchical content structure — parent/child pages with SEO-friendly slugs
- SEO metadata — title, description, Open Graph tags, canonical URLs
- Tenant isolation — schema-per-tenant architecture (MyBatisSchemaInterceptor)
- Event publishing — cms.page.created/updated/deleted to RabbitMQ
- Public API — GET /pages and GET /pages/{slug} with locale negotiation
- Platform Admin API — full CRUD for pages across any tenant
Hybrid Tenancy Model
One codebase, two deployment models. Switch multi-tenant B2B vs single-tenant B2C with platform.rolloutMode config flag. Same schema-per-tenant model in both — zero-migration symmetry.
- Multi-tenant mode — signup creates tenant (TENANT_OWNER); schema-per-tenant PostgreSQL isolation
- Single-tenant mode — signup joins pre-provisioned default tenant (MEMBER); no tenant creation
- Platform tenant — fixed 'platform' key/schema; every user auto-added as MEMBER in both modes
- Zero-migration single→multi symmetry — architectural parity; same schema-per-tenant model in both
- Liquibase per-tenant schema versioning and migrations per tenant key
- MyBatisSchemaInterceptor automatically sets t_{tenantKey} search_path per request
- RabbitMQ async provisioning — runs Liquibase, sets ACTIVE, publishes tenant.provisioned event
- Stuck provisioning reaper — ShedLock-guarded every 5 min; marks PROVISIONING as PROVISIONING_FAILED
- Rollout mode validation — validated at startup; published via /actuator/info for cross-service checks
- Gateway PlatformModeGuard — mismatches set ReadinessState.REFUSING_TRAFFIC returning 503
- Tenant lifecycle transitions — PROVISIONING→ACTIVE↔SUSPENDED→DELETED with PROVISIONING_FAILED retry
- Independent tenant status transitions — workspace stays accessible even when org tenant suspended
Tenant App
The customer-facing surface of the platform. A React 19 SPA built with Mantine UI 9, TanStack Router, and Feature-Sliced Design with runtime feature flags.
- Tenant discovery plus OAuth2/OIDC social sign-in (Google/GitHub/Microsoft) and enterprise SSO entry
- Magic link passwordless sign-in — initiate/resend screens, token exchange, VITE_ENABLE_MAGIC_LINK flag
- Self-service signup with async provisioning polling until tenant is ACTIVE
- Create organization — authenticated route to spin up additional workspaces with platform membership
- Workspace dashboard with basic stats, team member count, and plan-aware feature gating
- Team management — member list, ban/unban, role editing, ownership transfer with guardrails
- Invitation system — send, list, revoke, and accept workspace invites; plan quota-aware
- Billing self-service — Stripe or Lemon Squeezy portal, subscription view, plan catalog, billing info, refunds
- Seat adjustments — per-seat plan seat count editor for TENANT_OWNER
- Plan-based access control — EntitlementsProvider, FeatureGate, useHasFeature, useQuota hooks
- Tenant settings — organization metadata editing
- Security settings — TENANT_OWNER config for custom OIDC / enterprise SSO providers
- In-app notifications — bell, dropdown, notification center, real-time STOMP/SockJS WebSocket push
- My Account — profile editing, avatar upload, password reset, organization picker, connected accounts
- Internationalization with Lingui — en-US, bg-BG, de-DE, fr-FR catalogs; locale switcher UI
- Session security — 30-min inactivity timeout and silent token refresh in sessionStorage
- Runtime configuration via public/config.js VITE_* overrides without rebuild
Platform Admin
The internal operator console for platform management. Requires PLATFORM_ADMIN authority to access. React 19 SPA with Mantine UI 9, multi-tab detail views, and plan-aware feature gating.
- Dashboard with parallel count cards for total users, organizations, and active subscriptions
- Global User management — paginated list; 3-tab detail: Overview, Organizations, Identities; set password, ban/unban/unlock, platform authorities
- Organization administration — 5-tab detail: Overview, Members, Billing, Subscriptions, Refunds; edit metadata, manage authorities
- Invitation management — propose, edit, and revoke platform-wide cross-tenant invites
- Subscription monitoring — global paginated list with status filters; cancel/pause/reactivate via gateway, quantity update
- Plan catalog — read-only list; sourced from config-driven YAML + deployment
- Refunds management — global refund list and detail view across Stripe or Lemon Squeezy
- User identity management — view linked OIDC identities for any user; admin forced unlink remediation
- Announcements — multi-lingual editor (en-US mandatory + optional translations), publish workflow, delivery tracking
- Audit logs — global audit trail across all tenants; filter by user, tenant, action, ActivitySeverity, date range; JSONB expansion
- In-app notifications — bell, dropdown, real-time STOMP/SockJS WebSocket push
- Operator account — profile editing, password change
- Internationalization with Lingui — en-US, bg-BG, de-DE, fr-FR catalogs; locale switcher UI
- Runtime config — public/config.js VITE_* overrides without rebuild
- Strict RBAC enforcement with automated route guards and PLATFORM_ADMIN authority validation
Technology Stack
Enterprise Java without overhead — proven tools, long-term maintainability
Backend
Java 25 · Spring Boot 4.x · Spring Cloud Gateway (WebFlux) · MyBatis 3.x · PostgreSQL 17 · RabbitMQ · JJWT RS256 · ShedLock 7.x
Security
Spring Security OAuth2 Resource Server + OAuth2 Client · BCrypt strength 12 · JWKS endpoint · JTI denylist · Two-layer token revocation · Redis PKCE store
DevOps
Docker multi-stage builds · Kubernetes + Helm charts · Drone CI/CD 10-stage pipeline · Traefik · Liquibase · Three environments (local / staging / prod)
Observability
Prometheus · Grafana dashboards · Loki + Promtail · Micrometer · Structured JSON logging · Correlation ID tracing · Actuator health probes
Quality Gates
SonarQube · PMD · SpotBugs · Checkstyle (Google Java Style) · JaCoCo coverage thresholds · ArchUnit boundary validation · Testcontainers
Frontend
React 19 · TanStack Router (file-based) · TanStack Query · Mantine UI · Zustand · Lingui i18n · Vite · Astro landing kit