Rojects

Project Documentation

Roject

Developer reference for human and agent contributors. Keep this file up to date as the project evolves.

What it is

Roject is a self-hosted, agent-based IDE for working with files and projects. It provides specialised editors for different file types — a WYSIWYG HTML editor, a CodeMirror-backed code editor, and more to come — all within a multi-panel, tab-based workspace. Projects can be hosted on a Roject server (remote) or opened directly from the local filesystem (local), making it usable both as a lightweight self-hosted CMS and as a full desktop development environment. Designed for individual developers or small teams; no external database dependency.

What exists now

Auth & accounts

User accounts are managed by rokojori-auth at account.rokojori.com — registration, login, JWT issuance, refresh token rotation, roles, and account deletion. Roject verifies the shared accessToken JWT cookie and transparently refreshes expired tokens via account.rokojori.com/api/auth/refresh-session.

Projects & storage

Projects with member management (viewer / editor / admin roles). Each project gets a real directory on disk at storage/<uuid>/root/ with a default index.html on creation. All data lives as JSON files in build/data/db/ — no external database. Groups exist in the data layer but have been removed from the UI; they may return later via rokojori-auth.

Project home & theme system

The root / serves a new index.html entry point that loads the project-home component. Logged-out users see a full-screen dark hero; logged-in users get the active theme component dynamically imported. The default theme (project-list-default) renders a dark radial-gradient page with a Roject logo nav, per-project coloured badges (hue from UUID via 31-hash, hsl(h, 95%, 45%)), Barlow 900 Italic uppercase project names, hover-revealed delete / member buttons, and a dashed "New Project" card that opens a name dialog on click. Theme preference is persisted server-side in user_settings.json via GET / PUT /api/user/settings. A second theme (Italic Neon) is planned. /edit redirects to the existing /editor.html. Barlow is loaded via @import from styles.rokojori.com (weights 100, 400, 700, 900 including italics) — no Google Fonts dependency.

Ecosystem — tunnel.rokojori.com

A user-based local tunneling service live at tunnel.rokojori.com (source: C:\rokojori\projects\web-projects\tunnel). Exposes local services — LLMs, Stable Diffusion, language servers — to authorised rokojori users over the internet, routed through a relay server via a persistent WebSocket agent connection. Each tunnel is owned by a rokojori account and carries metadata (name, purpose tag, description, access mode, allowed users).

The Electron Tunnel Agent (electron-agent/) is a Windows system-tray app: login via account.rokojori.com, a tunnel list with Start / Stop / Delete / Create, and a green status dot when the agent WebSocket is connected. Tokens are persisted in userData/tokens.json.

The relay uses a three-message streaming protocol over the agent WebSocket: res_start (status + headers), res_data (base64 chunk), res_end — so SSE responses from local LLMs stream through the relay without buffering. Roject integrates via a Browse Tunnels button in rojo-settings-panel and forwards LLM chat through the selected tunnel. The TUNNEL_SERVER_URL env var controls the target in all environments. Phase 2 (multi-user allowed list enforcement, public access mode) is still in progress.

Ecosystem — styles.rokojori.com

A shared asset hosting service for all rokojori projects, live at styles.rokojori.com. Currently serves self-hosted fonts downloaded from Google Fonts on demand via a GET /get-font public endpoint that returns a dynamic CSS file with @font-face rules. Font files are stored as storage/fonts/<family>/<weight>.woff2 and served statically. CORS is restricted to *.rokojori.com origins. Access to the management UI (/list-fonts, /add-fonts) is gated by the shared JWT cookie via requireAccess middleware (role: admin, or role: user + product: styles / premium).

Planned: shared HTML components / Web Components, CSS presets, and binary assets (images, sounds, video) — making styles.rokojori.com the single place to manage any reusable front-end resource across the rokojori ecosystem.

Editor

A full editor page (/editor.html) with a 3-panel resizable layout (Left / Center / Right). Each panel holds one or more sections side by side; each section holds a <tab-container> with drag-and-drop tabs. The Left panel shows the file tree (create, rename, delete). A FileEditorRegistry routes files to the correct panel by extension: HTML → html-editor-panel (iframe, contenteditable, MutationObserver, undo/redo, Ctrl+S save); all other text formats → code-panel (CodeMirror 5, syntax highlighting, dark theme). An optional project-level workspace/editor/file-editors.json overrides the defaults.

Project access control

source/server/projectAccess.ts is the single point of truth for ownership and membership checks. GET /api/projects filters to projects the requesting user owns or is a member of. Every file route (tree, read, write, rename, delete) calls checkAccess() before touching the filesystem. Delete and member-management routes verify ownership. Members are currently stored by email address (Option B interim); memberMatchesUser() is the one line to change when migrating to user-ID-based lookup via rokojori-auth.

AI chat & utilities

A rojo-chat-panel provides a streaming AI chat interface backed by LangChain + OpenAI-compatible models. A reusable <confirm-dialog> component replaces browser confirm() for destructive actions. An EmailService facade (source/server/email/) provides a sendEmail() entry point backed by a swappable EmailSender interface; the default is SMTPEmailSender (Nodemailer). EmailService.reportEmail is a static field holding the admin notification address; Roject sends emails on server startup and on each verified deploy request.

Electron desktop app

Roject runs as a standalone Windows desktop application. The Express server starts in-process inside Electron's main process. A custom login window calls the auth API directly; tokens are stored in userData/tokens.json and re-used across sessions. All requests to localhost have Authorization: Bearer injected automatically via session.webRequest.onBeforeSendHeaders. Run with npm run electron:dev.

Deployment & CI

Live at https://roject.rokojori.com on Server A. nginx handles TLS and reverse-proxies to a Node.js process managed by systemd. Auto-deploy on push to main via a Gitea webhook calling POST /api/deploy (HMAC-SHA256 verified). The deploy script runs detached so it survives the systemctl restart that kills the parent process.

What's next

Current tasks, known bugs, and longer-horizon features are tracked on the Boards.

Technical Implementation

Backend

Node.js + Express, TypeScript compiled on the fly with ts-node. Auth is handled by rokojori-auth; Roject verifies the shared accessToken JWT cookie using jsonwebtoken + cookie-parser. All entity IDs are UUIDs via crypto.randomUUID(). Start the server with npm start.

Node.js Express ts-node jsonwebtoken cookie-parser UUID IDs

Frontend — Editor Singleton & Client/Server Split

The Editor singleton (src/editor/Editor.ts) is the central hub of the frontend — it owns all open document state, the FileEditorRegistry, and the five events that panels and tab containers subscribe to (onDocumentOpened, onDocumentDirty, onDocumentSaved, onFilesChanged, onFileTypeUnknown). For the full event reference and the TypeScript compilation split between client and server, see the Editor Singleton reference.

Frontend

Vanilla HTML, raw CSS (no Tailwind, no framework). Every UI component is a custom element with its own .ts and .css file in source/components/<name>/. CSS uses the element tag as root selector with display: block. TypeScript compiles to build/app/components/ via tsconfig.client.json (module: ESNext, no bundler). HTML pages live in source/pages/ and are copied to build/app/ by scripts/copy-pages.js. Build with npm run build.

Web Components raw CSS module: ESNext no bundler tsc --build

Shared Library

A personal TypeScript library lives as a git submodule at source/library-ts/. It has two parts: browser/ (DOM-capable) and node/ (Node.js only). The browser part is compiled separately via TypeScript project references into build/app/library-ts/browser/. The node part is included by tsconfig.ts-node.json.

git submodule source/library-ts/ project references composite: true