Skip to content
prod e051e98
Browse

Platform architecture

ZajLibrary is built to be forked into other libraries (verticals). A new library is not a rewrite — it is a fork-and-swap: copy the repo, change three things, deploy.

SwapWhereWhat changes
Identity + featuresapp/src/tenant.config.mjsSite name, tagline, domain, feature flags, visibility policy, MCP identity, admin allowlist.
DataDATABASE_URL (env)Point at a new database. Each library is its own deployment with its own DB — so there are no tenant-id columns and no per-row isolation to maintain.
Contentapp/src/content/Replace the documents.

Because each library is a separate deployment, “multi-tenancy” here means multi-instance: the deployment boundary is the isolation boundary. New UI reads branding and flags from tenant.config instead of hardcoding “ZajLibrary”, so a fork inherits the whole platform.

tenant.config.features toggles feedback, chat, folderView, and sideSheet. Half-built or library-specific features can ship turned off. The components check the flag before rendering.

  • Shelf view (default) — Learn / Build / Resources / Directory / System Docs.
  • Folder view (/browse) — Category › Subcategory › Topic, in reading order, with a type badge per document and a side-sheet “peek”. The header toggle remembers your choice (localStorage when anonymous, the database when signed in).
  • The default policy lives in tenant.config.visibility and can be overridden at runtime from the admin dashboard (the tenant_settings table; a null override means “use the config default”).
  • Private content is a separate collection (src/content/private/) rendered only through the gated, on-demand /private/[...slug] route. It is never built as static HTML (nothing to leak from the CDN), never enters the public search index, and a doc can also be flagged visibility: private in the regular collection to drop it from anonymous MCP results.
  • Gating is fail-closed: any error resolving the session redirects to login.

A Feedback control on every page files bugs / suggestions / missing-content / updates / questions to one database review queue (triaged in the admin dashboard, promoted to the Roadmap). Three input channels, one store: the UI form, the MCP submit_feedback tool (for agents), and the raw API.

The library is queryable over the Model Context Protocol at /api/mcp:

  • Anonymous callers get public, read-only access (search_library, get_document, list_contents) plus submit_feedback.
  • Authenticated callers (Authorization: Bearer <token>, or a logged-in browser session) can additionally read private content (read-private scope). An admin token unlocks list_feedback.
  • Every response carries the build commit (commitShaShort) so an agent can verify the index matches the live deploy in one call.

/admin (signed-in + allowlisted email) triages feedback, flips the visibility policy and feature flags, and shows which integration keys are configured — status only, never secret values. All secrets stay in environment variables.

  • app/src/tenant.config.{mjs,ts} — the fork contract.
  • app/src/lib/visibility.ts + app/src/middleware.ts — the gate.
  • app/src/mcp/search.ts + app/src/pages/api/[transport].ts — the scoped MCP.
  • app/src/lib/feedback.ts + app/src/lib/admin.ts — feedback + admin.