Kaizex — Marketing Operating System
SMAT (Kaizex backend) is a Spring Boot multi-module system that automates the full content lifecycle for marketing teams. Organizations connect social channels via PKCE OAuth2 (LinkedIn live, X wired, Instagram planned), configure a content strategy per channel (audience, pillars, tone, automation mode, posting cadence), and add knowledge sources — URLs or raw text — into theme-based Buckets. Three independent RabbitMQ pipelines handle content processing (knowledge extraction from sources), content generation (AI draft creation from strategy + knowledge), and post dispatch (platform publishing). Generated posts flow through a status lifecycle: DRAFT → PENDING_REVIEW → SCHEDULED → IN_PROGRESS → PUBLISHED/FAILED. A Redis time-slot engine (24 hourly slots per day, 7-day TTL) manages scheduling; four crons handle slot hydration, dispatch, cleanup, and strategy-triggered generation. BYO-AI supports five provider adapters: OpenAI/OpenRouter, Anthropic, Google Gemini, Ollama (local), and a fully configurable Custom endpoint with dot-path response extraction. Multi-tenant RBAC is enforced at method level via @PreAuthorize, with 15 default permissions seeded per org on creation.
$ Architecture
- →Independent worker services, not a monolith — smat-api-runner (REST API + security filter chain, no queue listeners of its own), smat-automation (pipeline execution engine + its own RabbitMQ trigger/step consumers), smat-consumer (content-gen/processing/post-dispatch consumers), smat-cron-runner (scheduling). Each ships as its own Spring Boot executable jar with a dedicated main class — independently deployed, independently scaled.
- →Three RabbitMQ pipelines — content-processing-queue (source URL/text → Jsoup extraction → AI knowledge → Elasticsearch processed_content_index), content-generation-queue (strategy → prompt from knowledge context → AI generation → route by automation mode), post-processing-queue (task ID → platform handler → LinkedIn UGC post / X stub / Instagram stub).
- →Redis time-slot scheduling — 24 hourly list keys per day (TTL 7d). Midnight cron hydrates all PENDING/IN_PROGRESS tasks into slots (3-thread pool). Top-of-hour cron LPOP dispatches due task IDs to post-processing-queue. 5-min-past-hour cron fails and clears any tasks left in the previous slot.
- →BYO-AI via Spring Cloud OpenFeign — five provider adapters: OpenAI/OpenRouter (/v1/chat/completions), Anthropic (messages API), Google Gemini (generateContent), Ollama (local /api/generate), Custom (configurable URL + payload template + dot-path JSON response extractor). One active config per org.
- →Social channel OAuth2 PKCE — LinkedIn (token exchange + UGC post publish fully live), X (token exchange + createTweet/removeTweet implemented; dispatch handler stubbed pending approval), Instagram (auth scaffolded). Anti-replay state via Redis TTL-bound keys consumed on callback.
- →Multi-tenant RBAC — 15 AppPermission entries seeded on org creation, custom permissions + roles per org, @PreAuthorize on every endpoint. 15 MariaDB tables via Liquibase changelogs. Three Elasticsearch indices: posts, processed_content_index, instagram_analytics.
- →Embeddable chat widget — vanilla-JS shadow-DOM script served as a static resource, session created via POST /widget/sessions before input unlocks (prevents messages sent into a session that does not exist yet). Optimistic message bubbles get tagged with the real server id once the send confirms, so the next poll tick recognizes and skips them instead of rendering a duplicate.
- →Reset conversation — restarts the bot’s pipeline position for a room (deletes its UserFlowStateEntity pointer) without creating a new room or a new visitor identity. widget_session.last_reset_at is a server-enforced floor applied to both the poll and full-history endpoints, so the reset survives a page reload instead of only clearing the client’s in-memory view. Admin inbox stays unfiltered and renders an archived/current divider at that boundary instead of hiding anything.