Skip to main content

Architecture for Solution Developers

This page explains the platform from the solution developer’s perspective: what you can rely on, what you own, and what contracts cross the boundary. It is not a complete platform architecture deep-dive — for that, see Architecture Overview.

Three layers, your job is the top one

CRAFT has three architectural layers. Solutions live at the top: Your solution inherits platform capabilities — never reimplements them. You do not run your own Keycloak. You do not write your own OpenFGA schema. You delegate via SDK calls and let the platform do the work.

What the platform provides

What your solution owns

You own everything that is specific to your domain:
  • The UI (typically a React microfrontend remote module loaded into em-runtime-ui)
  • The backend services (FastAPI + uvicorn is the platform default; nothing stops you choosing differently)
  • Your own PostgreSQL databaseno cross-service foreign keys with platform DBs. Each service owns its data; consistency across services is by API contract, not joins.
  • Your Helm chart that wraps em-service (one alias per component)
  • Optional Prefect workflows for orchestration-heavy work
  • Optional A2A or Pydantic AI agents for agentic capabilities
  • Your CI/CD pipeline (per-repo, calling shared modules)

Integration contracts

Five contracts cross the platform-solution boundary. Get these right and the rest is implementation detail.

1. JWT (authentication)

Every request to your service carries Authorization: Bearer <jwt>. The token is issued by Keycloak in the user’s organization realm. Validate the signature against Keycloak’s JWKS, extract org_id from the issuer URL, and reject requests with no token. See Authenticate Users for code.

2. X-Project-ID header (project scoping)

JWT alone gives you organization context. The active project is communicated via X-Project-ID. Every database query, storage path, and downstream call must be scoped by both. See Concepts for the full multi-tenancy model.

3. Connections API (data sources)

When your solution needs to talk to a customer database or object store, you do not ask the customer for credentials directly. They register a Data Connection via Assets, and you fetch the configured connection at runtime. Credentials never live in your code or config.

4. obstore (shared storage)

For artifacts, files, and intermediate data, use the platform’s obstore abstraction. Same code works against S3, GCS, Azure Blob, and local MinIO — pick the backend with the configured connection. See Use Shared Storage.

5. LiteLLM gateway (LLM access)

Solutions never call OpenAI or Anthropic directly. Instead, point your OpenAI-compatible SDK at LLM_GATEWAY_URL. The gateway provides central key management, per-project cost attribution, rate-limit enforcement, and observability via Langfuse. See Access LLMs.

What does NOT cross the boundary

Next steps

Quickstart

Build a working hello-solution in 30 minutes.

Register a solution

Naming, namespaces, image registries, registration steps.

Local development

Iterate quickly with docker-compose, hot reload, and mocked platform services.

Concepts

Read the platform-side concepts (orgs, projects, X-Project-ID).