Qollabi · Senior Software Developer & DevOps Engineer · Jan 2024 – Apr 2026
Qollabi 2.0 — aground-up rewrite
Multi-tenant B2B SaaS for partner and channel management — workspaces, partner and customer records, opportunities, objectives and key results (OKRs), campaigns with a visual email builder, smart lists, shared partner spaces and CSV import. It is a ground-up TypeScript rewrite of the legacy PHP and React platform, deployed under the internal project name qollabi-ai.
Qollabi 2.0 — platform scaleBun workspacesSheet 017 + 26
Apps & shared packages
81
Design-system components
Team-built platform; my own contribution is in section 01.
01 · My role
Product · pipelines · cloud- Product engineering on the Remix apps — feature work across shelf and dashboard, from Bloom command handlers and Drizzle schemas down to the shared design-system components.
- Realtime without a broker — I built the Server-Sent Events client over PostgreSQL
LISTEN/NOTIFY, so live updates reach the apps on the database already in the stack. - The delivery pipeline — the Docker-based development environment, the UAT and production pipelines, and the per-branch ephemeral environments with their own database and Keycloak realm.
- The AWS and Swarm footprint — Terraform codebase, Docker Swarm cluster, Route 53, RDS, Amazon MQ, S3 and IAM, plus the VPN and reverse tunnel the team develops through.
- Integrations and data migration — AWS Lambda functions, the Activepieces automation infrastructure and the Salesforce migration scripts used to onboard clients onto the new platform.
02 · Architecture
Bloom · CQRS · RLS tenancy- Bun workspaces monorepo — end-to-end TypeScript with no build step between packages; apps import backend logic directly as a workspace dependency rather than over HTTP.
- “Bloom” — an in-house application framework — a
Kernel with a build/boot plugin lifecycle, a typed DI service container, Zod-validated per-plugin env schemas and recursive plugin dependency resolution; every capability (CQRS, queue, KV, auth, wizard, emitter) ships as a Bloom plugin. - CQRS + domain events —
Command / CommandHandler / DomainEvent primitives with an extensible stamp metadata system (eventId, aggregateId, occurredOn, versioning) and an event recorder that only dispatches events once the command commits, so failed requests never emit side effects. - Multi-tenancy via PostgreSQL Row-Level Security — a Hono middleware opens a pooled connection, starts a transaction, sets
SET LOCAL ROLE tenant_user and app.current_workspace_id from the JWT, and pins the transaction into AsyncLocalStorage so every repository call inside the request is tenant-scoped automatically; a separate non-isolated middleware exists solely for the cross-workspace admin dashboard. - Backend-as-a-library —
@qollabi/backend exposes no HTTP API of its own; the Remix apps, webhooks service and worker each mount it and dispatch commands/queries in-process. - Postgres as the only infrastructure dependency — relational store, job queue (Graphile Worker), KV store (Keyv) and pub/sub (a reconnecting
LISTEN/NOTIFY emitter) all run on the same database.
03 · Apps in the monorepo
Seven deployablesshelfCustomer-facing Remix SPA and SSR app for partnerships, opportunities and OKRs (473 route modules).
dashboardInternal admin app for organizations, workspaces and campaign/smart-list templates.
spacesExternally shared partner spaces app.
backendThe domain layer: schemas, repositories, commands, events and jobs, consumed in-process by the apps.
workerGraphile Worker process (3 replicas locally) plus a React Email preview server.
webhooksStandalone Hono service for inbound webhooks (Postmark, integrations).
public-apiPylon GraphQL surface for third-party integrations.
04 · Backend
Bun · Hono · PostgreSQL 17Runtime
Bun 1.2 / Node 22, TypeScript 5.5
Framework
Bloom (in-house kernel + plugin system), Hono 4
Database
PostgreSQL 17, Drizzle ORM 0.36 + drizzle-zod, postgres / pg drivers
Migrations
Custom @bloom/drizzle-migrations CLI on Drizzle Kit — generate, up/down, status, rebase, validate, fresh, refresh (Jest-tested)
Auth
Keycloak 26 (OIDC) via remix-auth-oauth2, jsonwebtoken, Keycloak Admin Client SDK wrapper, bcrypt-edge
Queues / jobs
Graphile Worker (Postgres-backed), typed job registry, 19 background jobs
Pub/Sub
@bloom/postgres-emitter — LISTEN/NOTIFY client with channel mapping, auto-reconnect and backoff
KV / cache
Keyv with a PostgreSQL adapter (@keyv/postgres)
Validation
Zod 3 everywhere — command schemas, env schemas, @hono/zod-validator, zod-validation-error
Email
Postmark (transactional + inbound webhooks), React Email for templates, Maily for the customer-facing drag-and-drop builder
Storage
AWS S3 SDK v3 + presigned URLs (LocalStack in dev)
Data import
Streaming CSV pipeline — csv-parser, chardet + iconv-lite encoding detection, S3 staging, chunked job processing
i18n
i18next + remix-i18next, per-module translation catalogs (en / fr / nl)
Logging
Pino (pino-pretty in dev)
Errors
Sentry (toucan-js) and Rollbar
Public API
@getcronit/pylon — GraphQL generated from plain TypeScript functions (early scaffold)
05 · Frontend
Remix 2 SSR · React 18.3Core
React 18.3, TypeScript 5.5, Remix 2 (Vite 5), SSR
Routing
remix-flat-routes, typed search params via nuqs, remix-hono server adapter
Components
shadcn/ui on Radix UI primitives (~22 packages) — shared @bloom/ui-web with 81 components + blocks, hooks and themes
Styling
Tailwind CSS 3.4, tailwindcss-animate, class-variance-authority, clsx, tailwind-merge, Poppins via Fontsource
Forms
React Hook Form 7 + remix-hook-form + Zod resolvers
Client state
Redux Toolkit + React Redux (shelf), nuqs for URL state
Tables & lists
react-virtuoso (virtualized lists), react-easy-sort, emblor (tag input)
Maps
Mapbox GL / MapLibre GL via react-map-gl
Rich text
TipTap 3 (inside the Maily email editor)
Dates
date-fns + date-fns-tz, react-day-picker
Multi-step forms
@bloom/wizard — type-safe wizards with pluggable cookie / KV / memory storage backends and automatic namespaced state
Icons
Lucide, FontAwesome Pro
Misc
Sonner, Vaul, cmdk, Embla, Motion, input-otp, react-phone-number-input, react-currency-input-field, next-themes, NProgress
Mobile
@bloom/ui-mobile — React Native primitives (@rn-primitives, NativeWind-style CVA) and an Expo tsconfig/CI workflow, prepared for a mobile client
06 · Infrastructure & DevOps
Swarm · GitLab CI · ephemeral UAT- Docker Compose + Makefile — the full local stack in one command: 3 Remix apps, worker (×3), webhooks, PostgreSQL 17 (multi-database init), Keycloak 26 with a custom theme, LocalStack S3, pgAdmin, Drizzle Studio and a React Email preview server;
make install / start / reinstall / uninstall wrap the whole lifecycle. - GitLab CI/CD — Biome CI → migration validation → multi-target image build (shelf, spaces, dashboard, worker, webhooks, commands, migrations) →
docker stack deploy → automated post-deploy image-digest validation, gated by UAT/PRD tag formats. - Per-branch ephemeral UAT environments — the pipeline parses the ticket ID from the tag, provisions a dedicated
qollabi_db_<ticket> database, rewrites every Postgres URL (app, KV, queue, notifier) to point at it, deploys an isolated Swarm stack, and tears down the stack, Keycloak realm and database on cleanup. - Docker Swarm production/UAT stacks with a single multi-stage Dockerfile producing 7 targets from shared install/build layers, plus the AWS RDS TLS bundle baked in.
- Playwright end-to-end suite with a Keycloak login setup project and a dedicated
docker-compose-test.yaml environment (make e2e / e2e-ui); GitHub Actions run alongside GitLab for code quality, backend, dashboard and Expo checks. - Biome (format + lint + CI), Husky hooks,
@manypkg/cli and dependency-version consistency checks to keep workspace versions aligned; frpc reverse tunneling for exposing local environments.
07 · Engineering highlights
Eight decisionsAn in-house framework, not a framework-shaped folder
Bloom's kernel, plugin lifecycle, DI container and CQRS bus are versioned packages with their own docs, letting six deployables share one composition model.
RLS + AsyncLocalStorage tenancy
Tenant scoping is enforced by the database inside a per-request transaction rather than by query-building convention, so a forgotten where clause cannot leak data across workspaces.
Transactional event dispatch
The event recorder buffers domain events and flushes them only on successful command completion, eliminating the “email sent for a rolled-back write” class of bug.
Custom migration tooling
Validation runs in CI, and rebase resolves the migration-ordering conflicts that plague long-lived branches on a shared Drizzle schema.
Ephemeral per-ticket environments
Full database and identity-provider isolation, provisioned and destroyed by the pipeline.
Postgres-only infrastructure
Queue, KV and pub/sub all ride the primary database, removing Redis and a broker from the operational surface while keeping jobs transactional with the data they touch.
Two-sided email system
A Maily/TipTap drag-and-drop builder for customer campaigns and React Email templates for system mail, both rendered through a shared @bloom/maily-renderer package.
Architecture conventions encoded in the repo
.cursor/rules and .prompts hold the backend and frontend scaffolding rules, so AI-assisted scaffolding conforms to the layering instead of eroding it.