CustomBlock: ERP & Headless CMS

Framework-as-a-service with Server-Driven UI

What is this project?

CustomBlock is a modular, multi-tenant B2B backend operating on a 'framework-as-a-service' model. A shared core handles authentication, audit logging, and UI generation, while individual tenant modules (like this portfolio's Headless CMS or an inventory ERP) plug into the framework by providing only their data models — eliminating all boilerplate code.

The Challenge

The goal was to build a multi-tenant architecture with strict separation between the core framework and customer code, enabling zero-downtime framework upgrades via versioned Docker images. I also wanted to eliminate manual HTML authoring by engineering a Server-Driven UI capable of generating forms, data grids, and APIs dynamically by reading database metadata.

Security Architecture

JWT (HttpOnly)

HS256 tokens in HttpOnly, SameSite=Lax cookies. Dual-mode login: browser clients receive a Set-Cookie redirect; API clients receive {"access_token": ...} JSON — both from the same endpoint.

RBAC

Factory function returning FastAPI-injectable dependency functions. Pre-built guards: allow_admin, allow_authenticated. Navigation items are filtered server-side per role — no empty dropdowns for restricted users.

Automated Audit Log

SQLAlchemy event hooks (after_insert, before_update, before_delete) silently capture every data change using ContextVars. Entries are written in the same DB transaction as the change — no phantom logs on rollback.

GDPR Anonymization

5-step Article 17 engine: scramble PII fields, scrub the record's audit history, anonymize historical actions by the user, and scan all audit logs for the subject's email. Triggered via a modal-confirmed button on the edit form.

Active Tenants

demo
Inventory & ERP

Eight interconnected models: Products, Categories, Warehouses, Suppliers, Purchase Orders, Customers, Sales Orders. Three navigation dropdowns. The entire admin interface is registered in approximately 10 lines of Python.

portfolio
Headless Portfolio CMS

Eight multilingual (IT/EN) models. Public API with server-side language flattening, draft filtering, absolute URL resolution, and a dedicated cross-origin CV download endpoint. Powers this portfolio site.

Docker Architecture

The Dockerfile copies only core/ — customer directories are deliberately excluded. The result is a versioned, immutable cb-core:<version> image. Each customer's .env pins its own CORE_VERSION, allowing staged rollouts. Two customers running simultaneously share nothing: separate networks, separate volumes, separate databases.

Live Development Mode — A docker-compose override mounts ./core as a bind-mount and enables Uvicorn --reload, giving instant hot-reload of framework code inside the properly isolated Docker environment.

cbenv.sh — Developer CLI

Sourced into the shell (source cbenv.sh), it exposes the cbdev command. A pre-flight check validates that the required cb-core image exists locally before any stack starts — no silent pulls or mid-startup failures.

  • cbdev build <version> — Build a versioned cb-core image from the local Dockerfile
  • cbdev <customer> start — Render Compose template and start the tenant stack
  • cbdev <customer> migrate — Run alembic upgrade head inside the container
  • cbdev <customer> bash — Open a shell inside the running app container
  • cbdev <customer> remove — Stop the stack and delete its volumes (destructive)