Skip to Content
πŸ–₯️ Self-HostingArchitecture & Tech Stack

Architecture & Tech Stack

Sitepins is architected as an open-source, modular, Git-based headless CMS. Rather than replacing your Git workflow or managing a proprietary database for content, Sitepins acts as a visual editing interface over files stored directly in your repositories.

Runtime Topology

A self-hosted deployment consists of three long-lived processes, an S3-compatible object storage bucket, and external Git providers:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” HTTPS (Session Cookie) β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Next.js 16 Web App β”‚ ──────────────────────────▢│ Express 5 API Server β”‚ β”‚ (port 3000) β”‚ β”‚ (port 4000) β”‚ β”‚ β”‚ ws://.../collab β”‚ β€’ REST Endpoints (/api/v1) β”‚ β”‚ β€’ Visual Plate Editor β”‚ ──────────────────────────▢│ β€’ Hocuspocus Yjs Server β”‚ β”‚ β€’ Monaco Code Editor β”‚ /socket.io β”‚ β€’ Socket.IO Gateways β”‚ β”‚ β€’ Direct Git Client β”‚ ──────────────────────────▢│ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ Octokit / GitLab REST β”‚ Mongoose ODM β–Ό β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Git Providers β”‚ β”‚ MongoDB Database β”‚ β”‚ (GitHub & GitLab) β”‚ β”‚ (port 27017) β”‚ β”‚ [All Website Content] β”‚ β”‚ [Users, Orgs, Projects, Logs]β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–² β”‚ Direct Client Upload β”‚ Multipart Upload β–Ό β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ S3-Compatible Object Storage (AWS S3, Cloudflare R2, MinIO, DO Spaces) β”‚ β”‚ [Application UI Assets: Avatars, Org Thumbnails, Project Covers] β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Processes & Port Allocations

ProcessSubsystemDefault PortPrimary Responsibilities
Webapp/ (Next.js 16)3000Browser UI, Plate rich text editor, Monaco code editor, i18n, direct Git commits.
APIapi/ (Express 5)4000Better Auth sessions, MongoDB persistence, Hocuspocus CRDT sync, Socket.IO presence.
DatabaseMongoDB27017Persistent document storage for accounts, organizations, projects, and access control.

API Process Architecture (Three-in-One Listener)

The backend API server initializes three discrete server engines on a single HTTP port (4000):

  1. Express REST Engine (/api/v1): Serves RESTful CRUD routes for users, organizations, projects, media upload signatures, and health checks (GET /healthz).
  2. Socket.IO Engine (/socket.io): Manages real-time presence rooms (presence:<orgId>:<projectId>:<filePath>) and broadcasts Git commit events across collaborators. Authenticated on connection via socketAuth.ts.
  3. Hocuspocus WebSocket Engine (/api/v1/editor/collab): Yjs-backed collaborative CRDT server. Incoming HTTP upgrade requests on this path are intercepted and delegated directly to Hocuspocus with document-level tenant authorization.
// Conceptual upgrade routing in api/src/server.ts httpServer.on("upgrade", (request, socket, head) => { if ((request.url ?? "").startsWith("/api/v1/editor/collab")) { hocuspocusWss.handleUpgrade(request, socket, head, (ws) => { hocuspocusWss.emit("connection", ws, request); }); } });

Because Socket.IO and Hocuspocus share port 4000 via custom HTTP upgrade delegation, reverse proxies (like Nginx and Caddy) only need to proxy to a single upstream port.

Frontend Stack (app/)

  • Framework: Next.js 16 (App Router, Turbopack, React 19, TypeScript strict).
  • Styling: Tailwind CSS v4 CSS-first configuration (@theme definitions in src/styles/variables.css, no legacy tailwind.config.js).
  • State Management: Redux Toolkit (RTK Query) with domain-specific slices (auth, config, organization, project, editor).
  • Rich Text Editor: Platejs 53 (platejs with modular plugins for tables, media, code blocks, callouts, and Mermaid diagrams).
  • Code Editor: Monaco Editor (@monaco-editor/react) with syntax highlighting via Shiki.
  • Real-Time Collaboration: @platejs/yjs, @slate-yjs/react, @hocuspocus/provider, and yjs.
  • Git Integrations: Octokit (octokit, @octokit/auth-app, @octokit/rest) for GitHub App authentication; GitLab OAuth via REST.
  • Internationalization (i18n): next-intl supporting 12 global locales (en, zh, ja, de, fr, es, pt, ru, ko, id, vi, bn).
  • Content Serializers: Lossless Markdown/MDX parsing and comment-preserving YAML/TOML/JSON serialisation (gray-matter, unified, yaml, @ltd/j-toml).

Backend Stack (api/)

  • Framework: Express 5 with Helmet security headers and CORS protection.
  • Database & ODM: MongoDB with Mongoose 9 persistence (api/src/lib/dbConnect.ts).
  • Authentication: better-auth handling email/password sign-in, session cookies, password resets, and OAuth sign-in (GitHub, Google).
  • Real-Time Engines: @hocuspocus/server for Yjs CRDT synchronization + socket.io for presence rosters.
  • Media Uploads: S3-compatible client (@aws-sdk/client-s3, multer, multer-s3).
  • Email Delivery: Provider-agnostic mailer (nodemailer for SMTP, with zero-config console fallback in dev).
  • Testing: Vitest for unit and integration test coverage.

Security Posture & Isolation

1. Git Provider Credential Isolation

Sitepins commits to repositories on your behalf. To maximize security, Git provider credentials and private keys belong strictly to the web app, never to the API server:

  • The API stores OAuth access and refresh tokens, encrypted at rest.
  • The web app reads tokens securely during authenticated sessions to interact directly with GitHub and GitLab.
  • The API never touches or stores your GitHub App private key (.pem).

2. Multi-Tenant Authorization

All resource requests are validated through layered middleware:

  • verifyAuth: Validates session cookie or internal bearer token.
  • orgMiddleware(PERM): Verifies that the authenticated user is a valid member of the target organization and possesses the requisite permission (e.g. VIEW_PROJECTS, MANAGE_MEMBERS, DELETE_ORG).
  • projectMiddleware(roles): Verifies project-level access (owner, admin, editor).
  • Realtime Document Check: When opening a file over WebSockets, Hocuspocus extracts the organization ID from the document name (/org-<orgId>/<projectId>/<filePath>) and verifies org membership via isOrgMember(userId, orgId). Unauthorized sockets are immediately terminated.

3. Encryption at Rest

  • Sandbox Tokens: Third-party credentials (such as Vercel preview tokens) are encrypted at rest using AES-256-GCM via SANDBOX_ENCRYPTION_KEY.
  • User Passwords: Hashed using bcrypt with configurable salt work factor (SALT, default 10).

4. Server-to-Server Internal Security

Internal route invocations between the Next.js frontend and Express backend are authenticated using INTERNAL_API_SECRET passed in the x-internal-secret header. This shared secret must match identically between app/.env and api/.env.

Last updated on