Architecture Overview
Diskus is engineered for maximum performance and maintainability. It operates as a monorepo containing three core, tightly-integrated packages. This design ensures strict separation of concerns while keeping the developer experience straightforward.
System Topology
graph TD;
ClientSite[Your Website] -->|Injects| EmbedScript[embed.js]
EmbedScript -->|Mounts Shadow DOM| Widget[Preact Widget]
Widget <-->|REST API| Backend[Hono Backend API]
Dashboard[Preact Dashboard] <-->|REST API| Backend
Backend <--> SQLite[(SQLite Database)]
1. The Backend API (/backend)
The core engine of Diskus is a robust REST API built with Hono and executed on the ultra-fast Bun runtime.
- Database: It uses SQLite for rapid, file-based data persistence.
- ORM: Database interactions and migrations are strictly typed using Drizzle ORM.
- Responsibilities: Handles all comment CRUD operations, spam filtering, JWT authentication, Markdown rendering, and strict HTML sanitization.
2. The Admin Dashboard (/dashboard)
A Preact-based Single Page Application (SPA) designed for administrators. It utilizes Vite for lightning-fast HMR during development.
- Multi-tenancy: Allows you to register and manage multiple “Apps” or Domains from a single interface.
- Moderation: Provides a clean UI to approve comments, mark submissions as spam, or permanently delete inappropriate content.
- User Management: Oversee registered commenters and manage admin roles.
3. The Embed Widget (/widget)
The component your users actually interact with. It is a highly optimized, standalone Preact application.
- The Embed Script: The lightweight
embed.jsscript dynamically creates a Web Component on your host website. - Shadow DOM: The widget mounts entirely inside a native Shadow DOM. This ensures 100% CSS isolation. The Tailwind CSS v4 styles bundled with the widget cannot bleed out and break your website’s layout, and your website’s global CSS cannot accidentally overwrite the widget’s UI.
- Bundle Size: Through aggressive minification and tree-shaking, the entire interactive widget is kept to ~23KB (gzipped).
Database Agnostic via Drizzle ORM
While Diskus defaults to SQLite out-of-the-box to eliminate the operational overhead of managing external database servers, the underlying architecture is deeply powered by Drizzle ORM.
Because Drizzle abstracts the SQL dialects, Diskus is fundamentally database-agnostic. If your website outgrows a single-file SQLite database, or if you prefer a different stack, you can easily swap the driver to connect Diskus to PostgreSQL or MySQL without rewriting the core business logic.
How to Switch to PostgreSQL
If you wish to migrate from the default SQLite to PostgreSQL, follow these steps within the backend directory:
1. Install the PostgreSQL driver:
bun add postgres
2. Update Drizzle Config (drizzle.config.ts):
Change the dialect to postgresql and update the connection URL.
import { defineConfig } from "drizzle-kit";
export default defineConfig({
dialect: "postgresql",
schema: "./src/db/schema.ts",
out: "./drizzle",
dbCredentials: {
url: process.env.DATABASE_URL!, // e.g., postgres://user:pass@host:5432/db
},
});
3. Update Database Connection (src/db/index.ts):
Switch the initializer from bun-sqlite to postgres-js.
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import * as schema from './schema';
const queryClient = postgres(process.env.DATABASE_URL!);
export const db = drizzle(queryClient, { schema });
4. Update Schema Dialects (src/db/schema.ts):
Finally, change the table imports from SQLite to PostgreSQL. For example:
// From:
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
// To:
import { pgTable, text, serial, timestamp } from 'drizzle-orm/pg-core';
After these modifications, run bun run db:push to sync your new PostgreSQL database! MySQL follows an identical workflow using the mysql2 driver.