Architecture
How the monorepo fits together.
QQueue is a TypeScript monorepo with separate applications for the API, web UI, and background workers. Shared contracts and email provider logic live in packages so they can be reused without coupling the apps together.
Browser
|
v
apps/web ---> apps/api ---> PostgreSQL
|
v
Redis
|
v
apps/worker ---> SMTP providerMonorepo Structure
apps/api: Express API, Prisma access, HTTP routes, validation, and product modules.apps/web: Vite React dashboard for self-hosted operators and team users.apps/worker: BullMQ workers for email sending and campaign processing.packages/shared: Shared TypeScript types and Zod schemas.packages/email-engine: Email provider abstraction and SMTP provider.packages/sdk: the publishedqqueue-sdk(MIT) for transactional email.
API Responsibilities
The API owns HTTP routing, authentication, organization boundaries, SMTP connection records, contacts, templates, campaigns, transactional email endpoints, and persistence through Prisma.
Business modules are scaffolded under apps/api/src/modules. Each module starts with route, controller, and service files so implementation can grow without mixing transport and domain logic.
Web App Responsibilities
The web app provides the operator dashboard for SMTP connections, contacts, lists, segments, templates, campaigns, analytics, the inbox, queue operations, and settings.
Worker Responsibilities
Workers consume BullMQ jobs from Redis. The email sending worker sends individual email jobs through the email engine. The campaign processing worker expands campaigns into recipient email jobs.
Queue Flow
- API creates or schedules a campaign.
- API enqueues a campaign processing job in Redis.
- Campaign worker expands recipients into email jobs.
- Email sending jobs are added to the sending queue.
- Email worker sends messages through the selected provider.
- Email events are recorded for future analytics.
Email Provider Abstraction
The email engine exposes a small provider interface:
export interface EmailProvider {
send(payload: SendEmailPayload): Promise<SendEmailResult>;
}SMTP is the provider used today. Mailcow, SES, Resend, Brevo, and Postmark all connect through this same SMTP path; provider-native API classes exist only as unimplemented placeholders — use the SMTP interface.
Self-Hosted Architecture
The self-hosted version runs the web app, API, worker, PostgreSQL, and Redis in the operator's environment. The first Docker Compose file only starts PostgreSQL and Redis for local development.
Future Managed Cloud Architecture
The managed version will add hosted onboarding, billing, usage limits, tenant isolation, stricter secrets handling, operational monitoring, and multi-tenant hardening while preserving the same core API, worker, queue, and provider boundaries.