A unified, containerised application that bundles frontend, backend, database, and LLM integration — with no external infrastructure dependencies.
The problem
Traditional chatbot deployments demand separate services for the database, backend, frontend, and an LLM proxy. That infrastructure complexity becomes prohibitive for internal apps or customer-deployed solutions.
What we built
1. Single-process architecture
A unified Express server handles both API requests and serves the compiled React interface as static assets. SQLite manages persistence inside the container. The only external dependency is the call to an LLM provider.
- Express backend delivering API and static frontend
- SQLite for conversation history
- React frontend built and served by the same process
- Single-container deployment to Docker or Railway
2. Conversation surface
The chat interface renders messages token by token, and SQLite keeps conversation history across container restarts.
- Streaming message rendering as tokens arrive
- Conversation history persisted across sessions
- File-upload support for context attachments
- Lightweight UI with no external font or asset dependencies
3. Pluggable LLM client
The LLM integration uses an abstraction layer. Groq is the default; switching to OpenAI or Anthropic is a config change.
- Provider-agnostic LLM client
- Groq as the default for fast inference
- Swappable to OpenAI or Anthropic via config
Tech stack and rationale
Self-containment guided every architectural decision:
- Express — a mature Node framework handling API and static file serving in one process.
- SQLite — a single-file database, no separate database service required.
- React + Vite — compact builds served as static assets by Express.
- Multer — standard Express middleware for file uploads.
- Groq SDK — optimal inference speed at the price point, behind an interchangeable provider abstraction.
- Lucide React — a minimal bundle footprint with consistent iconography.
- Docker / Railway — a single-container deployment model.
Outcome
The application deploys as a unified artifact and runs reliably in any containerised environment — no additional infrastructure provisioning.
FAQ
What about scale?
Single-container deployments suit internal tools and per-customer installations. Future scaling allows extracting SQLite into a managed database and replicating containers behind a load balancer. Complexity defers until it's necessary.
How is conversation history backed up?
SQLite is a single file. Backups are a file copy; restoration is replacing the file — simpler than a managed database for this operational scale.