2026-07-06 17:28:59 +00:00
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html lang="en">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
<title>Roject — Developer Documentation</title>
|
|
|
|
|
<link rel="stylesheet" href="../_assets_/styles.css">
|
|
|
|
|
<link rel="stylesheet" href="../_assets_/nav.css">
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div class="page">
|
|
|
|
|
|
2026-07-12 14:14:58 +00:00
|
|
|
<div style="width:100%;height:400px;overflow:hidden;background:#000;margin-bottom:2rem;border-radius:8px;">
|
|
|
|
|
<img src="../_assets_/roject.svg" alt="Rojects"
|
2026-07-11 12:06:55 +00:00
|
|
|
style="width:100%;height:100%;object-fit:cover;object-position:center;">
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-07-06 17:28:59 +00:00
|
|
|
<header>
|
|
|
|
|
<p class="date">Project Documentation</p>
|
|
|
|
|
<h1 style="font-size: 300%;">Roject</h1>
|
|
|
|
|
<p class="subtitle">Developer reference for human and agent contributors. Keep this file up to date as the project evolves.</p>
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
<section>
|
2026-07-14 12:34:47 +00:00
|
|
|
<h2>What it is</h2>
|
2026-07-06 17:28:59 +00:00
|
|
|
|
|
|
|
|
<div class="card">
|
|
|
|
|
<p>
|
2026-07-11 12:06:55 +00:00
|
|
|
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,
|
2026-07-14 12:34:47 +00:00
|
|
|
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.
|
2026-07-06 17:28:59 +00:00
|
|
|
</p>
|
|
|
|
|
</div>
|
2026-07-14 12:34:47 +00:00
|
|
|
</section>
|
2026-07-06 17:28:59 +00:00
|
|
|
|
2026-07-14 12:34:47 +00:00
|
|
|
<section>
|
|
|
|
|
<h2>What exists now</h2>
|
2026-07-14 11:31:11 +00:00
|
|
|
|
|
|
|
|
<div class="card">
|
2026-07-14 12:34:47 +00:00
|
|
|
<h3>Auth & accounts</h3>
|
2026-07-14 11:31:11 +00:00
|
|
|
<p>
|
2026-07-14 12:34:47 +00:00
|
|
|
User accounts are managed by <strong>rokojori-auth</strong> at
|
|
|
|
|
<code>account.rokojori.com</code> — registration, login, JWT issuance, refresh
|
|
|
|
|
token rotation, roles, and account deletion. Roject verifies the shared
|
|
|
|
|
<code>accessToken</code> JWT cookie and transparently refreshes expired tokens
|
|
|
|
|
via <code>account.rokojori.com/api/auth/refresh-session</code>.
|
2026-07-14 11:31:11 +00:00
|
|
|
</p>
|
2026-07-11 12:06:55 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="card">
|
2026-07-14 20:27:03 +00:00
|
|
|
<h3>Projects & storage</h3>
|
2026-07-11 12:06:55 +00:00
|
|
|
<p>
|
2026-07-14 20:27:03 +00:00
|
|
|
Projects with member management (viewer / editor / admin roles).
|
2026-07-14 12:34:47 +00:00
|
|
|
Each project gets a real directory on disk at <code>storage/<uuid>/root/</code>
|
|
|
|
|
with a default <code>index.html</code> on creation. All data lives as JSON files
|
2026-07-14 20:27:03 +00:00
|
|
|
in <code>build/data/db/</code> — no external database. Groups exist in the data
|
|
|
|
|
layer but have been removed from the UI; they may return later via rokojori-auth.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="card">
|
|
|
|
|
<h3>Project home & theme system</h3>
|
|
|
|
|
<p>
|
|
|
|
|
The root <code>/</code> serves a new <code>index.html</code> entry point that
|
|
|
|
|
loads the <code>project-home</code> component. Logged-out users see a full-screen
|
|
|
|
|
dark hero; logged-in users get the active theme component dynamically imported.
|
|
|
|
|
The default theme (<code>project-list-default</code>) renders a dark
|
|
|
|
|
radial-gradient page with a Roject logo nav, per-project coloured badges (hue
|
|
|
|
|
from UUID via 31-hash, <code>hsl(h, 95%, 45%)</code>), 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 <code>user_settings.json</code> via
|
|
|
|
|
<code>GET / PUT /api/user/settings</code>. A second theme (Italic Neon) is
|
|
|
|
|
planned. <code>/edit</code> redirects to the existing <code>/editor.html</code>.
|
2026-07-11 12:06:55 +00:00
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="card">
|
2026-07-14 12:34:47 +00:00
|
|
|
<h3>Editor</h3>
|
2026-07-11 12:06:55 +00:00
|
|
|
<p>
|
2026-07-14 12:34:47 +00:00
|
|
|
A full editor page (<code>/editor.html</code>) with a 3-panel resizable layout
|
|
|
|
|
(Left / Center / Right). Each panel holds one or more sections side by side;
|
|
|
|
|
each section holds a <code><tab-container></code> with drag-and-drop tabs.
|
|
|
|
|
The Left panel shows the file tree (create, rename, delete).
|
|
|
|
|
A <code>FileEditorRegistry</code> routes files to the correct panel by extension:
|
|
|
|
|
HTML → <code>html-editor-panel</code> (iframe, contenteditable, MutationObserver,
|
|
|
|
|
undo/redo, Ctrl+S save); all other text formats → <code>code-panel</code>
|
|
|
|
|
(CodeMirror 5, syntax highlighting, dark theme). An optional project-level
|
|
|
|
|
<code>workspace/editor/file-editors.json</code> overrides the defaults.
|
2026-07-11 12:06:55 +00:00
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-07-14 20:27:03 +00:00
|
|
|
<div class="card">
|
|
|
|
|
<h3>Project access control</h3>
|
|
|
|
|
<p>
|
|
|
|
|
<code>source/server/projectAccess.ts</code> is the single point of truth for
|
|
|
|
|
ownership and membership checks. <code>GET /api/projects</code> filters to
|
|
|
|
|
projects the requesting user owns or is a member of. Every file route
|
|
|
|
|
(tree, read, write, rename, delete) calls <code>checkAccess()</code> before
|
|
|
|
|
touching the filesystem. Delete and member-management routes verify ownership.
|
|
|
|
|
Members are currently stored by email address (Option B interim);
|
|
|
|
|
<code>memberMatchesUser()</code> is the one line to change when migrating to
|
|
|
|
|
user-ID-based lookup via rokojori-auth.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-07-11 12:06:55 +00:00
|
|
|
<div class="card">
|
2026-07-14 12:34:47 +00:00
|
|
|
<h3>AI chat & utilities</h3>
|
2026-07-06 17:28:59 +00:00
|
|
|
<p>
|
2026-07-14 12:34:47 +00:00
|
|
|
A <code>rojo-chat-panel</code> provides a streaming AI chat interface backed by
|
|
|
|
|
LangChain + OpenAI-compatible models. A reusable <code><confirm-dialog></code>
|
|
|
|
|
component replaces browser <code>confirm()</code> for destructive actions.
|
|
|
|
|
An <code>EmailService</code> facade (<code>source/server/email/</code>) provides
|
|
|
|
|
a <code>sendEmail()</code> entry point backed by a swappable <code>EmailSender</code>
|
|
|
|
|
interface; the default is <code>SMTPEmailSender</code> (Nodemailer).
|
2026-07-14 20:27:03 +00:00
|
|
|
<code>EmailService.reportEmail</code> is a static field holding the admin
|
|
|
|
|
notification address; Roject sends emails on server startup and on each
|
|
|
|
|
verified deploy request.
|
2026-07-11 12:06:55 +00:00
|
|
|
</p>
|
2026-07-06 17:28:59 +00:00
|
|
|
</div>
|
2026-07-11 12:06:55 +00:00
|
|
|
|
2026-07-14 11:31:11 +00:00
|
|
|
<div class="card">
|
2026-07-14 12:34:47 +00:00
|
|
|
<h3>Electron desktop app</h3>
|
2026-07-14 11:31:11 +00:00
|
|
|
<p>
|
2026-07-14 12:34:47 +00:00
|
|
|
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 <code>userData/tokens.json</code> and re-used
|
|
|
|
|
across sessions. All requests to <code>localhost</code> have
|
|
|
|
|
<code>Authorization: Bearer</code> injected automatically via
|
|
|
|
|
<code>session.webRequest.onBeforeSendHeaders</code>. Run with
|
|
|
|
|
<code>npm run electron:dev</code>.
|
2026-07-14 11:31:11 +00:00
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-07-13 19:56:25 +00:00
|
|
|
<div class="card">
|
2026-07-14 12:34:47 +00:00
|
|
|
<h3>Deployment & CI</h3>
|
2026-07-13 19:56:25 +00:00
|
|
|
<p>
|
2026-07-14 12:34:47 +00:00
|
|
|
Live at <code>https://roject.rokojori.com</code> on Server A. nginx handles TLS
|
|
|
|
|
and reverse-proxies to a Node.js process managed by systemd. Auto-deploy on push
|
|
|
|
|
to <code>main</code> via a Gitea webhook calling <code>POST /api/deploy</code>
|
|
|
|
|
(HMAC-SHA256 verified). The deploy script runs detached so it survives the
|
|
|
|
|
<code>systemctl restart</code> that kills the parent process.
|
2026-07-13 19:56:25 +00:00
|
|
|
</p>
|
|
|
|
|
</div>
|
2026-07-14 12:34:47 +00:00
|
|
|
</section>
|
2026-07-13 19:56:25 +00:00
|
|
|
|
2026-07-14 12:34:47 +00:00
|
|
|
<section>
|
|
|
|
|
<h2>What's next</h2>
|
2026-07-12 18:59:23 +00:00
|
|
|
|
2026-07-13 11:54:11 +00:00
|
|
|
<div class="card">
|
|
|
|
|
<p>
|
2026-07-14 12:34:47 +00:00
|
|
|
Current tasks, known bugs, and longer-horizon features are tracked on the
|
|
|
|
|
<a href="../boards/index.html">Boards</a>.
|
2026-07-13 11:54:11 +00:00
|
|
|
</p>
|
|
|
|
|
</div>
|
2026-07-06 17:28:59 +00:00
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section>
|
|
|
|
|
<h2>Technical Implementation</h2>
|
|
|
|
|
|
|
|
|
|
<div class="card">
|
|
|
|
|
<h3>Backend</h3>
|
|
|
|
|
<p>
|
|
|
|
|
Node.js + Express, TypeScript compiled on the fly with <code>ts-node</code>.
|
2026-07-14 12:34:47 +00:00
|
|
|
Auth is handled by <code>rokojori-auth</code>; Roject verifies the shared
|
2026-07-13 13:37:19 +00:00
|
|
|
<code>accessToken</code> JWT cookie using <code>jsonwebtoken</code> +
|
|
|
|
|
<code>cookie-parser</code>. All entity IDs are UUIDs via
|
2026-07-14 12:34:47 +00:00
|
|
|
<code>crypto.randomUUID()</code>. Start the server with <code>npm start</code>.
|
2026-07-06 17:28:59 +00:00
|
|
|
</p>
|
|
|
|
|
<div class="tags">
|
|
|
|
|
<span class="tag">Node.js</span>
|
|
|
|
|
<span class="tag">Express</span>
|
|
|
|
|
<span class="tag">ts-node</span>
|
2026-07-13 13:37:19 +00:00
|
|
|
<span class="tag">jsonwebtoken</span>
|
|
|
|
|
<span class="tag">cookie-parser</span>
|
2026-07-06 17:28:59 +00:00
|
|
|
<span class="tag">UUID IDs</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-07-11 12:24:17 +00:00
|
|
|
<div class="card">
|
|
|
|
|
<h3>Frontend — Editor Singleton & Client/Server Split</h3>
|
|
|
|
|
<p>
|
|
|
|
|
The <code>Editor</code> singleton (<code>src/editor/Editor.ts</code>) is the
|
2026-07-14 12:34:47 +00:00
|
|
|
central hub of the frontend — it owns all open document state, the
|
|
|
|
|
<code>FileEditorRegistry</code>, and the five events that panels and tab containers
|
|
|
|
|
subscribe to (<code>onDocumentOpened</code>, <code>onDocumentDirty</code>,
|
|
|
|
|
<code>onDocumentSaved</code>, <code>onFilesChanged</code>,
|
|
|
|
|
<code>onFileTypeUnknown</code>). For the full event reference and the TypeScript
|
|
|
|
|
compilation split between client and server, see the
|
2026-07-11 12:24:17 +00:00
|
|
|
<a href="../reference/editor-singleton/index.html">Editor Singleton reference</a>.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
2026-07-06 17:28:59 +00:00
|
|
|
<div class="card">
|
|
|
|
|
<h3>Frontend</h3>
|
|
|
|
|
<p>
|
|
|
|
|
Vanilla HTML, raw CSS (no Tailwind, no framework). Every UI component is a
|
|
|
|
|
custom element with its own <code>.ts</code> and <code>.css</code> file in
|
2026-07-12 12:01:01 +00:00
|
|
|
<code>source/components/<name>/</code>. CSS uses the element tag as root
|
2026-07-06 17:28:59 +00:00
|
|
|
selector with <code>display: block</code>. TypeScript compiles to
|
2026-07-12 12:01:01 +00:00
|
|
|
<code>build/app/components/</code> via <code>tsconfig.client.json</code>
|
2026-07-14 12:34:47 +00:00
|
|
|
(<code>module: ESNext</code>, no bundler). HTML pages live in
|
|
|
|
|
<code>source/pages/</code> and are copied to <code>build/app/</code> by
|
|
|
|
|
<code>scripts/copy-pages.js</code>. Build with <code>npm run build</code>.
|
2026-07-06 17:28:59 +00:00
|
|
|
</p>
|
|
|
|
|
<div class="tags">
|
|
|
|
|
<span class="tag">Web Components</span>
|
|
|
|
|
<span class="tag">raw CSS</span>
|
|
|
|
|
<span class="tag">module: ESNext</span>
|
|
|
|
|
<span class="tag">no bundler</span>
|
|
|
|
|
<span class="tag">tsc --build</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="card">
|
|
|
|
|
<h3>Shared Library</h3>
|
|
|
|
|
<p>
|
|
|
|
|
A personal TypeScript library lives as a git submodule at
|
2026-07-12 12:01:01 +00:00
|
|
|
<code>source/library-ts/</code>. It has two parts: <code>browser/</code>
|
2026-07-06 17:28:59 +00:00
|
|
|
(DOM-capable) and <code>node/</code> (Node.js only). The browser part is
|
2026-07-14 12:34:47 +00:00
|
|
|
compiled separately via TypeScript project references into
|
|
|
|
|
<code>build/app/library-ts/browser/</code>. The node part is included by
|
|
|
|
|
<code>tsconfig.ts-node.json</code>.
|
2026-07-06 17:28:59 +00:00
|
|
|
</p>
|
|
|
|
|
<div class="tags">
|
|
|
|
|
<span class="tag">git submodule</span>
|
2026-07-12 12:01:01 +00:00
|
|
|
<span class="tag">source/library-ts/</span>
|
2026-07-06 17:28:59 +00:00
|
|
|
<span class="tag">project references</span>
|
|
|
|
|
<span class="tag">composite: true</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<footer>
|
|
|
|
|
Roject — developer documentation
|
|
|
|
|
</footer>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
<script>var NAV_ROOT = '../';</script>
|
|
|
|
|
<script src="../_assets_/nav-data.js"></script>
|
|
|
|
|
<script src="../_assets_/nav.js"></script>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|