Platform overview
The shape of Adapstory — bounded contexts, plugin runtime, and where your code runs.
Adapstory is built around a minimal core of bounded contexts (BCs) and a plugin runtime that hosts everything else.
Core bounded contexts
| BC | Name | What it owns |
|---|---|---|
| BC-01 | Plugin Gateway | MCP tool registry, LLM routing, OpenAPI aggregation |
| BC-02 | Plugin Lifecycle | Install / update / rollback of plugin manifests |
| BC-10 | Identity | Users, tenants, SSO, RBAC (Keycloak-backed) |
| BC-15 | Data Model Engine | Dynamic entities, schemas, validation, event projection |
| BC-16 | Identity Runtime | JWT issuance, token introspection, per-tenant keys |
| BC-19 | Multi-Tenant Runtime | Plugin isolation, per-tenant DB walls, sidecar injection |
Everything outside this list is a plugin.
Two-plane architecture
Control plane (Java 25 + Spring Boot 4): the BCs above, each as its own microservice with its own PostgreSQL database. jOOQ for data access, Kafka for events, CloudEvents 1.0 on the wire.
Data plane (Python 3.12 + FastAPI): AI microservices behind the Plugin Gateway. LangChain / LangGraph, vLLM or Ollama for inference, PyTorch for custom models. One service per capability.
Plugin runtime (BC-19): your plugin ships as a signed container image. At install time the runtime schedules it into the tenant's namespace with the right secrets, resource limits, and network policies.
How plugins plug in
A plugin declares its integration points in plugin.yaml:
apiVersion: adapstory.com/v1
kind: Plugin
metadata:
name: course-recommender
version: 1.4.0
spec:
mcpTools:
- name: recommend_next_course
description: Suggest the next course for a given learner
endpoint: /mcp/recommend
dataModels:
extends: [bc15.course, bc15.enrollment]
events:
produces: [course.recommended.v1]
consumes: [enrollment.completed.v1]
llm:
gatewayBudget: 500000 # tokens/day per tenant
defaultModel: claude-sonnet-4-6
guardrails:
content:
- no-pii
- education-safeAll fields in plugin.yaml are versioned and immutable once published. To change anything material, publish a new version and let the lifecycle controller migrate tenants.
Data boundaries
- Java ↔ Python — strictly over REST or Kafka. No shared databases. Ever.
- Plugin ↔ Core — MCP tools (for LLM-driven calls) or Kafka (for async workflows). No direct SQL into core tables.
- Tenant ↔ tenant — isolated at the schema level (PostgreSQL) and namespace level (Kubernetes). The runtime enforces; you don't have to.
Where to go next
- Bounded contexts in detail — what each BC exposes and its contracts.
- Runtime architecture — how the Multi-Tenant Runtime schedules and isolates plugins.
- Plugin quickstart — ship your first plugin.