rojects/workspace/outline/index.html

249 lines
11 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>What it is</h2>
<div class="card">
<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 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.
</p>
</div>
</section>
<section>
<h2>What exists now</h2>
<div class="card">
<h3>Auth &amp; accounts</h3>
<p>
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>.
</p>
</div>
<div class="card">
<h3>Projects &amp; storage</h3>
<p>
Projects with member management (viewer / editor / admin roles).
Each project gets a real directory on disk at <code>storage/&lt;uuid&gt;/root/</code>
with a default <code>index.html</code> on creation. All data lives as JSON files
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 &amp; 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>.
</p>
</div>
<div class="card">
<h3>Editor</h3>
<p>
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>&lt;tab-container&gt;</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.
</p>
</div>
<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>
<div class="card">
<h3>AI chat &amp; utilities</h3>
<p>
A <code>rojo-chat-panel</code> provides a streaming AI chat interface backed by
LangChain + OpenAI-compatible models. A reusable <code>&lt;confirm-dialog&gt;</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).
<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.
</p>
</div>
<div class="card">
<h3>Electron desktop app</h3>
<p>
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>.
</p>
</div>
<div class="card">
<h3>Deployment &amp; CI</h3>
<p>
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.
</p>
</div>
</section>
<section>
<h2>What's next</h2>
<div class="card">
<p>
Current tasks, known bugs, and longer-horizon features are tracked on the
<a href="../boards/index.html">Boards</a>.
</p>
</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>.
Auth is handled by <code>rokojori-auth</code>; Roject verifies the shared
<code>accessToken</code> JWT cookie using <code>jsonwebtoken</code> +
<code>cookie-parser</code>. All entity IDs are UUIDs via
<code>crypto.randomUUID()</code>. 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">jsonwebtoken</span>
<span class="tag">cookie-parser</span>
<span class="tag">UUID IDs</span>
</div>
</div>
<div class="card">
<h3>Frontend — Editor Singleton &amp; Client/Server Split</h3>
<p>
The <code>Editor</code> singleton (<code>src/editor/Editor.ts</code>) is the
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
<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/&lt;name&gt;/</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>, 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>.
</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 into
<code>build/app/library-ts/browser/</code>. The node part is included by
<code>tsconfig.ts-node.json</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 &mdash; developer documentation
</footer>
</div>
<script>var NAV_ROOT = '../';</script>
<script src="../_assets_/nav-data.js"></script>
<script src="../_assets_/nav.js"></script>
</body>
</html>