337 lines
16 KiB
HTML
337 lines
16 KiB
HTML
<!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">
|
|
|
|
<div style="width:100%;height:400px;overflow:hidden;background:#000;margin-bottom:2rem;border-radius:8px;">
|
|
<img src="../_assets_/roject.svg" alt="Rojects"
|
|
style="width:100%;height:100%;object-fit:cover;object-position:center;">
|
|
</div>
|
|
|
|
<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>
|
|
<h2>Project Outline</h2>
|
|
|
|
<div class="card">
|
|
<h3>What it is</h3>
|
|
<p>
|
|
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 editors to come — all within a
|
|
multi-panel, tab-based workspace. Projects can be hosted on the 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.
|
|
It is designed for individual developers or small teams and has no external database
|
|
dependency.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>What exists now</h3>
|
|
<p>
|
|
User accounts with registration, login, logout, and account deletion.
|
|
Groups and projects with member management (viewer / editor / admin roles).
|
|
Each project gets a real directory on disk at <code>storage/<uuid>/root/</code>
|
|
with a default <code>index.html</code> on creation.
|
|
</p>
|
|
<p style="margin-top:0.75rem">
|
|
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>. Tabs are draggable
|
|
between containers. The Left panel shows the file tree with create, rename,
|
|
and delete for files and folders. The Center panel holds the WYSIWYG HTML
|
|
editor (iframe, <code>contenteditable</code>, MutationObserver, undo/redo,
|
|
Ctrl+S save). The Right panel is empty by default and receives dropped tabs.
|
|
</p>
|
|
<p style="margin-top:0.75rem">
|
|
A <code>FileEditorRegistry</code> routes files to the correct panel by suffix.
|
|
HTML files open in <code>html-editor-panel</code>; all other known text formats
|
|
open in <code>code-panel</code> (CodeMirror 5, syntax highlighting, dark theme,
|
|
Pin/Undo/Redo/Save toolbar). The registry checks an optional project-level
|
|
<code>workspace/editor/file-editors.json</code> first, then falls back to
|
|
in-memory defaults. Unknown extensions show an error in the file tree instead
|
|
of attempting to open.
|
|
</p>
|
|
<p style="margin-top:0.75rem">
|
|
A <code>rojo-chat-panel</code> provides a streaming AI chat interface backed
|
|
by a LangChain + OpenAI-compatible model. Each panel instance holds its own
|
|
conversation session in memory.
|
|
A reusable <code><confirm-dialog></code> component replaces browser
|
|
<code>confirm()</code> for destructive actions (currently project deletion).
|
|
</p>
|
|
<p style="margin-top:0.75rem">
|
|
The app is deployed and publicly accessible at
|
|
<code>https://roject.rokojori.com</code> on Server A. nginx handles TLS
|
|
termination and reverse-proxies to the Node.js process managed by a
|
|
systemd service. Deployment is currently manual
|
|
(<code>git pull && npm run build && systemctl restart roject</code>);
|
|
CI automation is the remaining open item.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>What still needs work</h3>
|
|
<p>Items below are ordered by priority. Major planned features first, then smaller open improvements.</p>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>1 — CI pipeline (server is live)</h3>
|
|
<p>
|
|
The server is deployed and running at <code>https://roject.rokojori.com</code>
|
|
(nginx + systemd + Let's Encrypt on Server A). What remains is automating the
|
|
deploy on push: a Gitea Actions runner installed on Server A registers with the
|
|
repo on <code>community.rokojori.com</code> and runs a workflow that pulls,
|
|
builds, and restarts the service on every push to main. This is the last piece
|
|
that turns the manual deploy into a proper CI/CD pipeline.
|
|
</p>
|
|
<div class="tags">
|
|
<span class="tag">Gitea Actions runner</span>
|
|
<span class="tag">act_runner</span>
|
|
<span class="tag">auto-deploy on push</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>2 — Electron desktop app + local filesystem access</h3>
|
|
<p>
|
|
Package Roject as a standalone desktop application using Electron. Since the
|
|
frontend is already plain HTML/JS/CSS, the Electron integration is mostly
|
|
structural: the Express server runs as a child process inside Electron's main
|
|
process, and the BrowserWindow is pointed at it. No frontend changes are needed
|
|
to make the existing UI run inside Electron.
|
|
</p>
|
|
<p style="margin-top:0.75rem">
|
|
Local filesystem access follows from this almost for free: the file tree is
|
|
extended to browse arbitrary directories on the host machine using Node.js
|
|
<code>fs</code> directly, rather than being restricted to the
|
|
<code>storage/<uuid>/root/</code> paths managed by the server. This is
|
|
what turns Roject from a hosted CMS into something closer to VS Code — the
|
|
user can open any folder on their machine as a project.
|
|
</p>
|
|
<p style="margin-top:0.75rem">
|
|
These two features are treated as a single unit of work: there is no point
|
|
shipping Electron without local filesystem access, and local filesystem access
|
|
in the browser would require the File System Access API with significant UX
|
|
friction. Electron is the cleaner path.
|
|
</p>
|
|
<div class="tags">
|
|
<span class="tag">Electron</span>
|
|
<span class="tag">child_process</span>
|
|
<span class="tag">Node.js fs</span>
|
|
<span class="tag">BrowserWindow</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>3 — Local git repository integration</h3>
|
|
<p>
|
|
Git integration inside the editor: file status indicators in the tree, staging,
|
|
commit, push and pull, and eventually diffs and history. This depends on local
|
|
filesystem access (feature 2) and follows naturally from it — once Roject can
|
|
open an arbitrary local directory, the git repo that directory belongs to is
|
|
already there.
|
|
</p>
|
|
<p style="margin-top:0.75rem">
|
|
The implementation uses <code>simple-git</code>, a thin Node.js wrapper around
|
|
the git CLI, which keeps the dependency surface small and relies on the user's
|
|
existing git installation. An alternative is <code>isomorphic-git</code> (pure
|
|
JS, works in the browser too), but the CLI wrapper is simpler for a first
|
|
iteration. A new panel in the editor displays repo status and exposes the
|
|
common operations.
|
|
</p>
|
|
<div class="tags">
|
|
<span class="tag">simple-git</span>
|
|
<span class="tag">git CLI</span>
|
|
<span class="tag">new panel</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>4 — Internet tunnel / port pass-through relay</h3>
|
|
<p>
|
|
A tunneling feature that allows local devices — a main workstation running
|
|
Stable Diffusion, a local LLM, a GDScript language server, or any other
|
|
service — to be accessible to authorised Roject users over the internet,
|
|
routed through the Roject server.
|
|
</p>
|
|
<p style="margin-top:0.75rem">
|
|
The architecture: a small local agent (a Node.js script, or a built-in Roject
|
|
feature) connects to the Roject server via a persistent WebSocket, identifying
|
|
itself with a secret key. The server maps that key to a Roject user and
|
|
permission record. When an authorised Roject user (e.g. on their phone) makes
|
|
a request to the relay endpoint, the server forwards it through the WebSocket
|
|
to the local agent, which proxies it to the configured local port, and returns
|
|
the response the same way.
|
|
</p>
|
|
<p style="margin-top:0.75rem">
|
|
The primary use case is mobile-to-desktop: use a phone as a thin client while
|
|
the main machine handles all heavy processing (image generation, inference,
|
|
language server completions). The secret key is the only credential needed —
|
|
it is registered once in Roject's user system and then shared with the local
|
|
agent. A single pass-through maps one local port to one authorised user.
|
|
</p>
|
|
<p style="margin-top:0.75rem">
|
|
This feature is architecturally independent of Electron and mobile and lives
|
|
entirely on the server, so it can be developed in parallel with the desktop
|
|
work. It is placed here because its primary value is unlocked only once mobile
|
|
access (feature 5) also exists.
|
|
</p>
|
|
<div class="tags">
|
|
<span class="tag">WebSocket relay</span>
|
|
<span class="tag">HTTP proxy</span>
|
|
<span class="tag">secret key / auth</span>
|
|
<span class="tag">local agent</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>5 — Mobile app (PWA first, native shell later)</h3>
|
|
<p>
|
|
Make Roject usable on a phone or tablet. The quickest path given the existing
|
|
web frontend is a Progressive Web App (PWA) — a manifest file and a service
|
|
worker. This costs almost nothing to add, works in Safari and Chrome on both
|
|
Android and iOS without an app store, and covers the core use case of reaching
|
|
the editor and the tunnel relay from a mobile browser.
|
|
</p>
|
|
<p style="margin-top:0.75rem">
|
|
If native capabilities are later needed (background processing, push
|
|
notifications, deeper OS integration), Capacitor can wrap the same web app
|
|
in a native shell without requiring a framework rewrite. A full React Native
|
|
or Flutter rewrite would be a significant departure from the existing Web
|
|
Components architecture and is not planned.
|
|
</p>
|
|
<p style="margin-top:0.75rem">
|
|
The main challenge of a mobile editing experience is the code editor — CodeMirror
|
|
on a touchscreen is not great for authoring. The realistic mobile workflow is
|
|
lighter interaction: browsing files, reading output, triggering generation
|
|
requests through the tunnel relay, and simple edits rather than heavy coding.
|
|
</p>
|
|
<div class="tags">
|
|
<span class="tag">PWA</span>
|
|
<span class="tag">manifest + service worker</span>
|
|
<span class="tag">Capacitor (later)</span>
|
|
<span class="tag">no React Native</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>Smaller open improvements</h3>
|
|
<ul style="line-height:1.9">
|
|
<li>The Right panel has no default content and relies on manual tab dragging to populate.</li>
|
|
<li>Portrait mode's secondary section switcher (when a panel has multiple side-by-side sections) is not yet wired up.</li>
|
|
<li>The member list UI shows raw UUIDs instead of usernames.</li>
|
|
<li>The group editor and account delete button still use the browser <code>confirm()</code> instead of the custom <code><confirm-dialog></code>.</li>
|
|
<li>Non-text files (images, PDFs) are visible in the tree but not openable — a <code>MediaViewerPanel</code> is planned.</li>
|
|
<li>No real-time multi-user collaboration yet.</li>
|
|
</ul>
|
|
</div>
|
|
|
|
</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>.
|
|
No database — all data lives as JSON files in <code>data/</code>
|
|
(auto-created on first run). Auth uses <code>express-session</code> +
|
|
<code>bcryptjs</code>. All entity IDs are UUIDs via
|
|
<code>crypto.randomUUID()</code> — no central counter, safe for parallel
|
|
instances. Start the server with <code>npm start</code>.
|
|
</p>
|
|
<div class="tags">
|
|
<span class="tag">Node.js</span>
|
|
<span class="tag">Express</span>
|
|
<span class="tag">ts-node</span>
|
|
<span class="tag">express-session</span>
|
|
<span class="tag">bcryptjs</span>
|
|
<span class="tag">UUID IDs</span>
|
|
</div>
|
|
</div>
|
|
|
|
<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
|
|
central hub of the frontend editor — it owns all open document state, the
|
|
<code>FileEditorRegistry</code>, and the five events that panels and the tab
|
|
container 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
|
|
<a href="../reference/editor-singleton/index.html">Editor Singleton reference</a>.
|
|
</p>
|
|
</div>
|
|
|
|
<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
|
|
<code>source/components/<name>/</code>. CSS uses the element tag as root
|
|
selector with <code>display: block</code>. TypeScript compiles to
|
|
<code>build/app/components/</code> via <code>tsconfig.client.json</code>
|
|
(<code>module: ESNext</code>, <code>moduleResolution: bundler</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> as part of the
|
|
build. HTML pages load components with
|
|
<code><script type="module"></code>. Shared state uses a module-level
|
|
singleton (<code>editor-state.ts</code>) rather than globals.
|
|
Build with <code>npm run build</code>.
|
|
</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
|
|
<code>source/library-ts/</code>. It has two parts: <code>browser/</code>
|
|
(DOM-capable) and <code>node/</code> (Node.js only). The browser part is
|
|
compiled separately via TypeScript project references
|
|
(<code>source/library-ts/browser/tsconfig.roject.json</code>, <code>strict: false</code>)
|
|
into <code>build/app/library-ts/browser/</code>. The node part is included by
|
|
<code>tsconfig.ts-node.json</code> (extends server config, <code>strictNullChecks: false</code>).
|
|
</p>
|
|
<div class="tags">
|
|
<span class="tag">git submodule</span>
|
|
<span class="tag">source/library-ts/</span>
|
|
<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>
|