logicspike/docs

Blog Engine

Blog System — Developer Guide

Last Updated: 2026-06-28 Status: Active

The complete internal reference for the Vlozi blog system. Everything a developer needs — architecture, schema, deployment, editor internals, SDK — lives here or is one link away.


1. What Is This System?

The Vlozi blog system is a multi-tenant headless blog engine built across three codebases:

Codebase Location Role
blog-service apps/blog-service Cloudflare Worker — owns all blog data, enforces permissions, serves the API
seller-dashboard apps/seller-dashboard/src/modules/blog Next.js dashboard — where tenants write and manage posts
blog-sdk packages/blog-sdk Published as @vlozi/blog — what customers embed on their websites

Two doors in, one data store:

Seller Dashboard ──JWT──► Gateway ──service binding──► blog-service ──► Neon PostgreSQL
Customer Website ──API Key──► Gateway ──────────────────────────────────────────────────►
  • Admin door (/blog/admin/*): JWT-authenticated. Full CRUD for posts, categories, and tags.
  • Public door (/blog/public/*): API key-authenticated. Read-only, published posts only.

2. Start Here By Role

Role Reading Path
New to the project This doc → glossary.mdarchitecture.mduser-journey.md
Backend / blog-service work architecture.mddatabase.mdblog-service.mdpermissions.mddeployment.md
Frontend / dashboard work architecture.mdfrontend-spec.mdeditor.mdmarkdown-import.md
SDK integrator sdk-reference.mdsdk-security-model.mdai-integration-prompt.md
Need a curl example fast cookbook.md
Setting up locally or deploying deployment.md
Debugging a failing request blog-workflow.md

3. Doc Index

Core Reference

Doc What It Covers
glossary.md Every term used across these docs — tenant, JWT, slug, content_json, hydration, etc.
architecture.md System diagram, all services, request flows, header protocol, permission model, multi-tenant isolation
database.md All 5 tables — column reference, constraints, indexes with rationale, migrations
billing.md Credit billing — publish cost, creditGuard middleware, 30-min grace window, MCP differences
permissions.md Every permission string, what route it gates, role bundles, how to add a new scope
deployment.md Local dev setup, env vars for all 3 services, production deploy, health checks
blog-service.md Full API reference — every endpoint, request/response schemas, middleware pipeline
cookbook.md Runnable curl + fetch recipes for common admin and public operations
blog-workflow.md Step-by-step request traces, common failure modes and fixes, debug checklist
editor.md TipTap extension inventory, custom node views, slash commands, how to add extensions
markdown-import.md The 5-stage .md → draft pipeline: parse → resolve → convert → mirror images → create
frontend-spec.md Dashboard UI — pages, components, API hooks, Redux state, permission-gating
sdk-reference.md Complete @vlozi/blog API — all exports, hooks, components, types, defaults
sdk-security-model.md HTML sanitization, iframe allowlist, XSS prevention, CSP guidance
testing.md Test inventory, how to run, test patterns, coverage gaps

Context & Process

Doc What It Covers
user-journey.md 9 end-to-end user journeys for admin authoring and SDK consumption
backlog.md Bugs, gaps, and improvement scope for blog-service — prioritized, with fix guidance
sdk-backlog.md Active bug/improvement queue for @vlozi/blog
ai-integration-prompt.md Paste-ready AI prompt for SDK integration tasks

Vision (Forward-Looking)

These describe where the product is going — not the current implementation.

Doc What It Covers
vision/blog-engine-vision.md Product north star — full editor, management, and integration vision
vision/layouts-vision.md Pre-built blog layout presets
vision/hosted-blog-vision.md Hosted blog pages (no SDK needed)
vision/integration-friction-vision.md Reducing SDK integration friction
vision/books-vision.md Blog → series → book publishing ladder

4. Codebase Quick Map

apps/
├── blog-service/                     Cloudflare Worker · port 8791 (local)
│   ├── src/index.ts                  Entry point — middleware pipeline + route registration
│   ├── src/db/schema.ts              5 tables: blog_posts, blog_categories, blog_tags, blog_post_tags, blog_overview_snapshots
│   ├── src/routes/admin/             posts.ts · categories.ts · tags.ts
│   ├── src/routes/public/            posts.ts · categories.ts · tags.ts
│   ├── src/middleware/               auth.middleware.ts · db.middleware.ts
│   └── src/utils/tiptap-renderer.ts  TipTap JSON → sanitized HTML

├── gateway/                          Cloudflare Worker · port 8788 (local)
│   └── src/routes/blog.proxy.ts      Admin + Public proxy handlers

└── seller-dashboard/                 Next.js · port 3000 (local)
    └── src/modules/blog/             ~54 files across pages, editor, components, store, import
 
packages/
└── blog-sdk/                         Published as @vlozi/blog@2.1.6
    └── src/                          client · react/ · server/ · next/

5. Three Things Every Dev Must Know

1. The gateway is the only trust boundary. blog-service validates x-gateway-key on every request. Requests missing or bearing an invalid key are rejected 403. There is no direct public access to blog-service. When something is 403 but shouldn't be, check that GATEWAY_SECRET matches in both services.

2. Content is TipTap JSON in the database, HTML on the public API. All content is stored as JSONB (content_json). The admin API returns raw TipTap JSON for the editor. The public API (/public/posts/:slug) runs it through tiptap-renderer.ts before responding — HTML is generated server-side per request, never persisted.

3. All database queries are scoped by tenant_id. There is one blog-service serving every tenant. Isolation is enforced at the query level, not by routing or separate databases. Every SELECT, INSERT, UPDATE, and DELETE includes a WHERE tenant_id = ? clause. The requireTenant middleware rejects any request where x-tenant-id is absent.

4. Publishing costs 1 credit — and is the only billed operation. The creditGuard middleware charges 1 credit from CORE_DATABASE_URL before the publish handler runs. If the handler fails or the post was already published, the credit is automatically refunded. Unpublishing within 30 minutes also refunds the credit. See billing.md.

Blog Engine