Feature modules
Synaplan's core — chat, documents and RAG, assistants, the widget, the API — runs on every installation. Around that core sit optional features: sidecar services, extra AI providers, payment channels and messaging channels that an installation may or may not have. Each of those is a feature module.
A module is switched on by its configuration, never by a build flag: set the environment variable (or paste the key in the admin UI) and the feature exists; leave it empty and the platform behaves as if the feature was never written. The Docker image, the API surface and the documentation are the same everywhere — what differs is which modules an operator has configured.
This section has one page per module. Every page answers the same four questions: what the module adds, what happens without it, how to enable it, and how to check that it works.
The modules
| Module | Id | What it adds | Switched on by |
|---|---|---|---|
| Apache Tika | tika |
Text extraction from PDFs and Office files | TIKA_BASE_URL |
| Docling | docling |
Layout-aware document conversion (tables, headings) | DOCLING_BASE_URL |
| Office conversion | office_convert |
PDF export, thumbnails, previews, combine-as-PDF via Collabora | OFFICE_CONVERT_URL |
| SearXNG web search | searxng |
Self-hosted web search — no query leaves your network | SEARXNG_BASE_URL |
| Piper text-to-speech | piper_tts |
Spoken answers from a local voice service | SYNAPLAN_TTS_URL |
| Local AI (Ollama) | local_ai |
Chat and embedding models on your own hardware | OLLAMA_BASE_URL |
| Higgsfield | higgsfield |
Cinematic image and video generation | HIGGSFIELD_API_KEY + HIGGSFIELD_API_SECRET |
| Google AI | google_ai |
Gemini chat and vision, Imagen, Veo, transcription | Google API key (env or admin UI) |
| TheHive | thehive |
Flux and SDXL image generation | THEHIVE_API_KEY |
| Stripe billing | stripe_billing |
Paid tiers, checkout, top-ups, billing portal | Real Stripe keys and price ids |
| Mobile in-app purchases | mobile_iap |
Apple / Google subscriptions for your own app build | IAP_PRODUCT_* |
| WhatsApp channel | whatsapp |
The assistant answers on WhatsApp | WHATSAPP_ENABLED + access token |
Everything not in this table — widgets, OIDC/SSO, e-mail channels, MCP, Synaplan Desktop — is core or has its own switch and is documented on its own page.
Where you see them
Operate → Feature Status (/admin/features, admin only) lists every module with a state badge, the one-line status message, and which keys configure it — key names only, never values. Each row links to its page here.
The same information is available on the command line, which is what you want on a server without a browser:
docker compose exec backend php bin/console app:modules:list # table
docker compose exec backend php bin/console app:modules:list --json # same shape as the API below
And in the API:
GET /api/v1/config/features(admin) — amodulesarray withid,state,configured,healthy,message,details,configured_by,capabilities,docs_anchor.GET /api/v1/config/runtime(every user) —modules: { "<id>": { "configured": bool, "gated": bool } }, which the web app uses to hide surfaces of absent modules.
The three states
| Badge | Meaning | Typical cause |
|---|---|---|
| Not installed | The module's configuration is empty. Nothing is probed. | The variable is unset, or set to disabled. |
| Needs setup | Configured, but the service did not answer its health check. | Sidecar not started, wrong URL, network policy, container still warming up. |
| Available | Configured and the health check passed. | — |
Configured is decided from the configuration alone and costs nothing; only configured modules are probed, and each probe has a short timeout. A key you paste into the admin UI counts within five minutes at most — no restart.
What happens without a module
The rule is degrade, never break:
- Sidecars fall back. A missing Docling hands the document to Tika; a missing Collabora leaves Office files searchable but without thumbnails or PDF export; a missing SearXNG means chat searches through the cloud provider you selected instead.
- Providers hide their models. Without a Google key the Gemini rows simply are not offered.
- Commerce stays off. Without Stripe the install runs in open-source mode: no plans, no quotas, no upgrade prompts.
- Channels show a notice. The WhatsApp card on Channels becomes a short "WhatsApp channel is not available on this installation" notice with a How to enable it link to the module's page; admins additionally get Open feature status.
The feature_not_configured answer
An API request that only makes sense for an absent module can answer
HTTP 404
{ "error": "feature_not_configured", "module": "whatsapp", "docs": "modules/whatsapp" }
instead of a generic error. The web app turns this into the same notice. Which routes belong to a module is declared by the module itself; health, runtime config, API docs, the routes an admin uses to configure a module, and the store / Meta webhooks that must keep their own status codes are never in that list.
Gates are opt-in
That 404 is only sent while the module's gate is on. Gates are per-module BCONFIG rows, group MODULES, setting GATE_<ID> (upper-case module id: GATE_WHATSAPP, GATE_STRIPE_BILLING, …). They are seeded off, so an existing installation keeps answering exactly as it did before modules existed. A configured module is never gated regardless of the flag.
Turn a gate on under Operate → System configuration (group MODULES), or in SQL:
INSERT INTO BCONFIG (BOWNERID, BGROUP, BSETTING, BVALUE)
VALUES (0, 'MODULES', 'GATE_WHATSAPP', '1')
ON DUPLICATE KEY UPDATE BVALUE = '1';
No restart is required; the next request reads the new value.
Minimal installations
A stack with no module configured is a supported target, not an accident. The production deploy/compose.yaml starts with Tika only; every other module waits for you to set its variable or add its Compose profile. The developer compose files are wired differently: they pre-fill the sidecar URLs (http://docling:5001, http://collabora:9980, …) so that starting a profile is enough — which is why a fresh dev stack shows those modules as Needs setup rather than Not installed until the container is up. The CI lane that proves the core carries no optional feature uses:
docker compose exec backend php bin/console app:modules:list --assert-none-configured # exit 1 if any module is configured
Related pages
- Administration — providers and keys, users, models and pricing
- AI infrastructure — the extraction, web search and rerank plugs several modules plug into
- Production Deployment — the
deploy/contract and Compose profiles - Quickstart & Self-Hosting — what the standard and minimal installs contain