Wednesday, 1 July 2026

Roject — Initial Build

Session summary: from blank directory to a typed, UUID-based CMS skeleton.

What we built

Node.js + Express Backend

A REST API server handling authentication, groups, and projects. Organised into route modules with a shared auth middleware that guards all non-public endpoints via express-session.

express express-session bcryptjs

User Management

Four operations: register, login, logout, and delete account. Passwords are hashed with bcrypt. Session stores the user's UUID and username for the lifetime of the browser session.

POST /api/auth/register POST /api/auth/login POST /api/auth/logout DELETE /api/auth/me

Groups & Projects

Both entities support create, delete, and member management. Members can be either a user or another group. Project members additionally carry a role (viewer, editor, admin).

/api/groups /api/projects member_type: user | group role

Web Component Frontend

Five custom elements, each with its own .ts and .css file. No framework, no build tool beyond plain tsc, no Tailwind. CSS uses the element tag as the root selector with display: block.

<login-form> <register-form> <app-nav> <group-editor> <project-editor>

Key Decisions

JSON file store instead of SQLite

better-sqlite3 requires native compilation and failed on Node 24 without build tools. Replaced with plain fs.readFileSync / fs.writeFileSync on per-table JSON files. Zero dependencies, good enough for MVP scale.

TypeScript via plain tsc — no bundler

Server runs with ts-node. Frontend TypeScript lives in src/components/ and compiles to public/components/ via a separate tsconfig.client.json with module: none, keeping each component as a standalone global script.

UUIDs for all IDs

Integer IDs would collide across parallel server instances. Switching to crypto.randomUUID() (built-in, no extra dependency) means any server can generate IDs independently, making future data merging or multi-node deployments straightforward.

Scripts at bottom of body

Custom elements are registered after the browser has parsed the HTML, so connectedCallback fires on an already-present element. Equivalent to defer in head, but explicit by position.

Project Structure

server/ — TypeScript backend source
src/components/ — TypeScript frontend source
public/ — compiled JS, CSS, and HTML pages served statically
data/ — auto-created JSON data files
history/ — session logs (this file)
CLAUDE.md — project conventions loaded by Claude Code automatically

What is missing

The HTML document editor itself — creating and editing actual content — is not yet built. The session covers only the scaffolding: auth, group management, project management, and the TypeScript + component infrastructure to build on.