A universal framework for creating bots (Telegram, etc.), web backends, or full-scale monoliths. Built with Bun, TypeScript, and a modular architecture inspired by Go best practices.
The project uses a clear separation of concerns. The framework allows combining chat-bot logic and an HTTP server in a single application.
cmd/— Application entry points.internal/— Private application code.core/— Base classes (App,Loader,Router), interfaces, and system enums.application/— Business logic: modules, routes, events, and scenes.services/— Specialized services (AI, business logic, etc.).storage/— Data storage logic (Prisma, Redis).
pkg/— Public utilities and libraries.config/— Configuration files.database/— DB schemas (Prisma) and migrations.
Modules are the building blocks of the application. They are loaded automatically. Events (ModuleType.EVENT) are loaded last to ensure all dependencies are ready.
// internal/application/modules/example.module.ts
import Module, { ModuleType } from "@core/classes/module.class";
export default new Module({ type: ModuleType.MODULE }, async (deps, config) => {
// Your logic here
});Scenes are used for complex bot dialogues. The name is passed in the parameters, and Telegraf methods and deps.scene are available inside.
// internal/application/scenes/order.scene.ts
export default new Scene({ name: "order_scene" }, async (deps, config) => {
deps.scene.enter(async (ctx) => {
await ctx.reply("What would you like to order?");
});
// Handle scene steps
});Use routes to create an API or a backend for a website.
import Route from "@core/classes/route.class";
export default new Route({ path: "/api/status", method: "GET" }, async (deps, request, config) => {
return Response.json({ status: "ok" });
});By default, Telegraf support is disabled in the base version for universality. To activate it:
-
Install the library:
bun add telegraf
-
Activate core files: Rename files by removing the
.disabledextension:internal/core/classes/scene.class.ts.disabledinternal/core/interfaces/context.interface.ts.disabledinternal/core/interfaces/scene.interface.ts.disabled
-
Uncomment code:
- In
internal/core/interfaces/deps.interface.ts, uncomment Telegraf imports and theISceneDepsinterface:import { Telegraf, Scenes } from "telegraf"; // ... export interface ISceneDeps extends IBaseDeps { scene: Scenes.BaseScene<any>; }
- In
internal/core/classes/loader.class.ts, uncomment theloadScenesmethod:public async loadScenes(): Promise<Scenes.BaseScene<any>[]> { const sceneFiles = this.getFiles(this.scenesPath, this.suffix); const scenes: Scenes.BaseScene<any>[] = []; // ... return scenes; }
- In
-
Configure App: In
internal/core/classes/app.class.ts, add session and scene initialization (middleware) before loading modules.Note: You also need to add
stage: { ttl: number }to your config. Thettl(Time To Live) defines how long the scene remains active (in seconds) after being called; once it expires, the scene is closed.const scenes = await this.loader.loadScenes(); const stage = new Scenes.Stage(scenes, { ttl: config.stage.ttl }); this.deps.bot.use(session()); this.deps.bot.use(stage.middleware());
- Bun runtime
- Redis
- PostgreSQL/SQLite (via Prisma)
- Clone the repository.
- Install dependencies:
bun install. - Configure
.env(usingenv.example). - Prepare the DB:
bun run db:migrate && bun run db:generate. - Start:
bun run dev.
bun run dev— Start in development mode with hot-reload.bun run start— Start in production.bun run db:*— Commands for working with Prisma (migrate, generate, studio).bun run format— Format code via Prettier.
The project includes a Dockerfile and docker-compose.yml for quick deployment in containers.
# Start with docker-compose
docker-compose up -d
# Logs
docker-compose logs -f botNODE_ENV=production
LOG_LEVEL=warn
BOT_TOKEN=your_production_bot_token
GEMINI_API_KEY=your_production_gemini_key
REDIS_URL=redis://your-redis-server:6379This project is distributed under the MIT License. See the LICENSE file for details.
© 2026 Pavlotech. MIT License.