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.
See Tasks board for the current sprint. Local filesystem access and remote projects in Electron are the two active items.