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
| Process | Subsystem | Default Port | Primary Responsibilities |
|---|---|---|---|
| Web | app/ (Next.js 16) | 3000 | Browser UI, Plate rich text editor, Monaco code editor, i18n, direct Git commits. |
| API | api/ (Express 5) | 4000 | Better Auth sessions, MongoDB persistence, Hocuspocus CRDT sync, Socket.IO presence. |
| Database | MongoDB | 27017 | Persistent 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):
- Express REST Engine (
/api/v1): Serves RESTful CRUD routes for users, organizations, projects, media upload signatures, and health checks (GET /healthz). - Socket.IO Engine (
/socket.io): Manages real-time presence rooms (presence:<orgId>:<projectId>:<filePath>) and broadcasts Git commit events across collaborators. Authenticated on connection viasocketAuth.ts. - 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 (
@themedefinitions insrc/styles/variables.css, no legacytailwind.config.js). - State Management: Redux Toolkit (RTK Query) with domain-specific slices (
auth,config,organization,project,editor). - Rich Text Editor: Platejs 53 (
platejswith 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, andyjs. - Git Integrations: Octokit (
octokit,@octokit/auth-app,@octokit/rest) for GitHub App authentication; GitLab OAuth via REST. - Internationalization (i18n):
next-intlsupporting 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-authhandling email/password sign-in, session cookies, password resets, and OAuth sign-in (GitHub, Google). - Real-Time Engines:
@hocuspocus/serverfor Yjs CRDT synchronization +socket.iofor presence rosters. - Media Uploads: S3-compatible client (
@aws-sdk/client-s3,multer,multer-s3). - Email Delivery: Provider-agnostic mailer (
nodemailerfor SMTP, with zero-configconsolefallback 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 viaisOrgMember(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
bcryptwith 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.