Last Updated: 2026-05-14 Status: Active Service:
apps/gatewayLive URL:https://api.vlozi.appDev URL:http://localhost:8788
The Gateway is the single public entry point for every Vlozi API call. No downstream Worker (blog, brain, media, etc.) is reachable from the internet — all traffic must pass through the Gateway first.
1. What the Gateway Does
| Responsibility | How |
|---|---|
| Rate limiting | Fixed-window counter per IP, KV-backed in production |
| CORS enforcement | Strict origin whitelist for dashboard; open * for public SDK routes |
| JWT authentication | Verifies RS256 access tokens via @repo/core-auth |
| API-key authentication | SHA-256 hash lookup with 3-tier cache (memory → KV → DB) |
| PBAC service-access check | assertServiceAccess from @repo/core-access |
| Subscription gate | Blocks paid features when tenant is canceled, past_due, or trialing+expired |
| Request forwarding | Cloudflare Service Bindings — zero public-internet hop |
| Identity injection | Appends x-tenant-id, x-user-id, x-user-permissions, x-user-services |
| Trace correlation | Generates x-request-id UUID per authenticated request |
2. Technology Stack
| Layer | Technology |
|---|---|
| Runtime | Cloudflare Workers (edge, V8 isolate) |
| Framework | Hono v4 |
| Service routing | Cloudflare Service Bindings (internal, no network overhead) |
| Persistent state | Cloudflare KV (RATE_LIMIT_KV) |
| Database | Neon Postgres via @neondatabase/serverless + Drizzle ORM |
| Build / deploy | Wrangler v4 |
| Type safety | TypeScript — @cloudflare/workers-types |
3. System Topology
Full infrastructure map — every client type, every middleware layer with its data sources, every downstream service.
4. Full Request Processing Pipeline
Every decision the Gateway makes, in order. Every diamond is a conditional branch; red terminals are rejections.
4.1 Phase 1 — Rate Limit + CORS
4.2 Phase 2 — Authentication
4.3 Phase 3 — PBAC, Subscription Guard, and Proxy
5. Project File Structure
apps/gateway/
├── wrangler.toml # Worker config: name, bindings, KV, routes
├── package.json
├── tsconfig.json
├── .env # Local dev vars (gitignored)
└── src/
├── index.ts # App root: middleware order, route mounting, /health
├── context.ts # Hono ContextVariableMap augmentation
├── types.ts # GatewayBindings type (all env bindings)
├── db/
│ └── client.ts # createCoreDb() — neon-http Drizzle handle
├── middleware/
│ ├── rate-limit.middleware.ts # Fixed-window rate limiter (KV + memory)
│ ├── auth.middleware.ts # JWT RS256 verification
│ ├── api-key.middleware.ts # API-key lookup with 3-tier cache
│ ├── access.middleware.ts # PBAC service-entitlement check
│ └── subscription.middleware.ts # Billing-state gate
├── routes/
│ ├── blog.proxy.ts # /blog/admin/* (JWT) + /blog/public/* (API key)
│ ├── media.proxy.ts # /media/upload/* + /media/files/* (JWT)
│ ├── manager.proxy.ts # /manager/* (JWT, with public-path exceptions)
│ ├── content.proxy.ts # /content/* (JWT + subscription)
│ ├── brain.proxy.ts # /brain/* (JWT + subscription)
│ ├── contacts.proxy.ts # /contacts-intel/* (JWT + subscription)
│ ├── newsletter.proxy.ts # /newsletter/* (JWT) + /newsletter/public/* (API key / open)
│ ├── comms.proxy.ts # /comms/* (JWT + subscription)
│ └── chatbot.proxy.ts # /chatbot/* (JWT + subscription)
└── utils/
├── proxy.utils.ts # proxyFetch, proxyResponseArgs, buildDownstreamHeaders
└── logger.ts # logSystem / logError / logInfo (structured JSON)6. Environment Bindings Reference
6.1 Service Bindings (Worker-to-Worker, zero-latency)
| Binding | Downstream Worker |
|---|---|
BLOG_SERVICE |
logicspike-blog-service |
MEDIA_SERVICE |
logicspike-media |
MANAGER_SERVICE |
logicspike-manager |
CONTENT_ENGINE_SERVICE |
logicspike-content-engine |
BRAIN_SERVICE |
logicspike-brain-service |
CI_SERVICE |
logicspike-contact-intelligence |
NL_SERVICE |
logicspike-newsletter |
COMMS_SERVICE |
logicspike-communication |
CE_SERVICE |
logicspike-chat-engine |
6.2 KV Namespaces
| Binding | KV Key Prefix | Purpose |
|---|---|---|
RATE_LIMIT_KV |
rl:{ip} |
Rate-limit counters per IP |
RATE_LIMIT_KV |
ak:{sha256(key)} |
API-key lookup cache |
Both use the same KV namespace. The rl: and ak: prefixes prevent key collisions.
6.3 Secrets
Set via wrangler secret put (production) or .dev.vars (local — never commit).
| Variable | Type | Purpose |
|---|---|---|
JWT_PUBLIC_KEY |
RS256 PEM string | Verifies access tokens issued by manager |
GATEWAY_SECRET |
Random string | Shared secret forwarded as x-gateway-key to downstream workers |
DATABASE_URL |
Neon connection string | API-key lookups + subscription checks |
DEBUG |
"true" / unset |
Enables trace logging and debug endpoints |
7. CORS Policy
Two tiers of CORS are applied in order in src/index.ts:
7.1 Public SDK Routes (open *)
| Route | Allowed methods |
|---|---|
/blog/public/* |
GET, OPTIONS |
/newsletter/public/* |
POST, OPTIONS |
7.2 All Other Routes (strict whitelist)
https://go.vlozi.app (seller dashboard)
https://vlozi.app (marketing site)
https://www.vlozi.app
https://docs.vlozi.app
https://logicspike-office.vercel.app (legacy — remove after DNS cutover)
https://logicspike.com (legacy)
https://app.logicspike.com (legacy)
http://localhost:3000
http://localhost:3001
http://localhost:30028. Health Check
GET /healthReturns 200 OK with a JSON object indicating whether every binding is present. No auth required.
{
"status": "ok",
"env": {
"BLOG_SERVICE": true,
"MANAGER_SERVICE": true,
"JWT_PUBLIC_KEY": true,
"RATE_LIMIT_KV": true
}
}9. Related Documents
- Middleware Reference — deep dive into each middleware
- Route Reference — per-route auth matrix and proxy behavior
- Developer Guide — adding new services, local setup, deployment
- Auth Architecture — JWT / PBAC design
- System Architecture — full platform service map