Monday, 14 July 2026
Roject packaged as a standalone Windows desktop app with JWT-based auth, token persistence, Authorization header injection, and a local Express server running in-process.
electron/main.ts)
The Express server starts in-process inside Electron's main process via a
compiled startServer(port) export. A BrowserWindow
points at http://localhost:3000. The server's static file,
data, and locale paths all previously relied on __dirname
relative to the TypeScript source; a new source/server/rootDir.ts
module resolves these using process.env.ROJECT_ROOT (set by
Electron before starting the server) with a fallback that preserves the
existing ts-node behaviour.
A minimal electron/login.html form collects email and password.
Credentials are sent to the main process via IPC (contextBridge +
ipcRenderer.invoke). The main process calls
POST https://account.rokojori.com/api/auth/login directly using
Node.js https — no browser redirect, no CORS, no cookie.
Tokens are written to userData/tokens.json and reloaded on
the next app start.
session.defaultSession.webRequest.onBeforeSendHeaders intercepts
every request from the BrowserWindow to http://localhost:3000/*
and adds Authorization: Bearer <accessToken>. The
existing extractToken middleware already checked this header
(designed for Electron from the start), so the frontend required zero changes.
Server-side 302 redirects to
/api/auth/refresh-session are intercepted by
will-redirect — the main process calls
POST /api/auth/refresh with the refresh token, updates the
stored tokens, and reloads the original URL. A will-navigate
guard prevents the BrowserWindow from ever leaving localhost:
any external navigation (e.g. the app's login link pointing to
account.rokojori.com) is intercepted and replaced with the
Electron login window.
Three new tsconfigs: tsconfig.electron.json (compiles
electron/ → build/electron/),
tsconfig.electron-server.json (compiles
source/server/ → build/server/ for Electron's
in-process require). New npm scripts: electron:build,
electron:dev, electron:dist.
scripts/copy-electron-assets.js copies login.html
into build/electron/.
scripts/launch-electron.js spawns the Electron binary with
ELECTRON_RUN_AS_NODE deleted from the environment (VS Code /
Claude Code set this variable, which otherwise makes Electron behave as
plain Node.js with no GUI or API).
The outline originally described the server as a child process. Running it
in-process is simpler, removes IPC overhead, and is equivalent for the first
iteration. The compiled server JS is required at runtime via a dynamic
require(serverPath) call.
When this env var is set, the Electron binary runs as plain Node.js: no GUI,
no Electron API, require('electron') returns the binary path
string. The launcher script deletes it before spawning so the binary
initialises as a real Electron app. This was discovered by writing debug
output to a log file from inside the Electron process.
Six server files used path.join(__dirname, '..', '..', ...)
relative to the TypeScript source depth. Compiled output is one level deeper
(build/server/server/), breaking all paths. A single
rootDir.ts module exposes ROOT that all files
import, using ROJECT_ROOT when set (Electron) or the
__dirname fallback (ts-node).
The Express server reads JWT_SECRET from the environment.
When started via npm start this is provided by the shell; when
started from Electron there is no shell. A small inline loadEnv()
function in electron/main.ts parses the project-root
.env file and sets missing variables before startServer
is called.
workspace/boards/)
A new Boards section added to the workspace with three boards:
Tasks (current sprint, To Do / In Progress / Done),
Bugs (Critical and Visual/UI/UX lanes),
Backlog (MVP / Nice To Have / To The Moon).
Each board uses custom HTML elements — <task-item>,
<task-title>, <task-content> — styled
to match the workspace visual language (CSS variables, same spacing rhythm,
lane headers matching section h2). Clicking a title toggles
the content open/closed via hide-content class.
Shared styles extracted to workspace/_assets_/boards.css.
workspace/outline/index.html was rewritten to remove the long
numbered to-do list and the "Smaller open improvements" bullet list.
Those items were distributed across the three boards.
The outline now covers only: what Roject is, what exists now (condensed into
named cards), a one-card pointer to the boards, and the technical implementation
reference. About half the original length.
workspace/index.html gained a Boards card and a
"Quick orientation" section with separate guidance for humans and agents:
read Outline → Guides → Reference before making changes; check Boards and
the most recent History entry for current context.
Added UserSetting interface and userSettings CRUD module
to source/server/db.ts (persisted in user_settings.json).
Created source/server/routes/userSettings.ts with
GET / PUT /api/user/settings (requires auth).
Cleaned up source/server/index.ts: removed the groups router and
explicit / redirect; added /edit → /editor.html
redirect and wired the new userSettings route.
New source/pages/index.html entry point loads Barlow 900 Italic
from Google Fonts and the project-home component.
project-home checks auth: logged-out → full-screen dark hero with
brand text and login link; logged-in → fetches user settings, reads
settings.theme, and dynamically imports the matching theme component
(project-list-default by default; project-list-italic-neon
planned).
Full default theme: dark radial-gradient background, fixed nav with Roject logo
(webp, inner area positioned at 70% scale) and a user-group element where hover
slides in "Log out" beneath the email — clicking anywhere triggers logout.
Each project row: 7em×7em rounded badge with project colour (hue from UUID via
31-hash), radial-gradient fill (centre at 51% alpha), Barlow 900 Italic skewed
name in project colour. Hover reveals delete (×) and members buttons over the
badge corners. A "New Project…" dashed-outline card sits first in the list and
opens a name dialog on click. Rows animate in staggered on load.
Back arrow in the editor updated to /.
The redesign spec removed groups entirely from the frontend and server routes.
The data layer (groups / groupMembers in db.ts) is
retained in case groups return later via rokojori-auth; only the router and all
UI references were deleted.
JWT settings from rokojori-auth are read-only. A local
user_settings.json DB file with a generic
Record<string, unknown> value map provides per-user persistence
for any app setting (starting with theme) without requiring changes
to the auth service.
Italic Neon theme (batch 2): skewed cards, warm→cold gradient, hand-crafted SVG pattern icons (13 files already drawn), daily auto-rotation + user toggle. See Tasks board for the full sprint.