← back to projects
LIVE2025

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.

$ Tech Stack

JavaSpring BootNext.jsTypeScriptRabbitMQRedisElasticsearchMariaDBLiquibaseSpring Cloud OpenFeignDockerNginx

$ Outcomes

→Three independent async RabbitMQ pipelines: knowledge extraction, AI generation, platform dispatch — each failure-isolated and independently scalable
→Five AI provider adapters: OpenAI/OpenRouter, Anthropic, Google Gemini, Ollama (local), Custom endpoint — zero model lock-in, one active config per org
→Three automation modes per channel: MANUAL (always draft), REVIEW (human approval before scheduling), AUTOPILOT (auto-schedule on generation)
→Redis time-slot engine: 24 hourly buckets per day, midnight hydration, top-of-hour dispatch, 5-min slot cleanup — reliable scheduling without a heavyweight queue
→Content Knowledge Pipeline: add URLs or raw text as Sources → async AI knowledge extraction → Elasticsearch → context injected into every generation prompt
→OAuth2 PKCE for LinkedIn (fully live), X (auth + tweet API wired), Instagram (auth scaffolded) — extensible connector architecture
→Method-level RBAC via @PreAuthorize, 15 default permissions auto-seeded per org, full custom role and permission management
→Elasticsearch post store with 8-dimension dynamic search: channel, platform, status, source, content pillar, hashtag, and date range
→Two-way live chat handoff — human agent replies render visually distinct from bot replies (labeled, distinct color) so a visitor can tell when a person joins the conversation
→Reset conversation button — restarts the bot’s pipeline for a room without spawning a new one; durable across page reloads via a server-enforced timestamp floor, not a client-side cursor