Sunday, 12 July 2026
Full project directory restructure and first production deployment — source/, build/app/, build/data/, source/pages/; Roject live at roject.rokojori.com via nginx + systemd on Server A.
The project root was reorganised into two top-level directories that cleanly separate source from build artefacts and runtime data:
source/ — all TypeScript source (components, editor, server, rojos, locales, library-ts submodule) plus locale data and HTML pagesbuild/app/ — compiled frontend output (was public/)build/data/db/ — JSON user/project data (was data/)build/data/storage/ — project files, sessions, layouts (was storage/)
The git submodule (library-ts) was moved with git mv
so .gitmodules stayed in sync automatically. The entire
build/ tree is gitignored; source/ is fully tracked.
HTML pages (editor.html, dashboard.html, etc.)
moved from build/app/ into source/pages/ so they
are tracked in git as source files. A new scripts/copy-pages.js
(plain Node.js, no extra dependencies) copies them to build/app/
as the second step of npm run build:
tsc --build tsconfig.client.json && node scripts/copy-pages.js
Roject deployed to Server A and served publicly at
https://roject.rokojori.com. Stack: Node.js 20,
ts-node running source/server/index.ts managed
by a systemd service, nginx as TLS-terminating reverse proxy with a
Let's Encrypt certificate, port 3000 kept closed at the IONOS firewall.
Several build gaps were discovered and fixed during the deploy:
component CSS files were never in source control (moved to
source/components/); vendor libraries were in the gitignored
build/app/vendor/ (moved to source/vendor/);
mkdirSync calls in the server lacked { recursive: true }
causing a crash on a fresh clone; and the library-ts browser
tsconfig.roject.json still referenced the old
public/ outDir instead of build/app/.
The copy script was also expanded to copy all non-TS static assets
(CSS, SVG, etc.) from all frontend source directories.
Added a thin email layer to the backend under
source/server/email/: an EmailSender interface,
an SMTPEmailSender implementation using Nodemailer, and an
EmailService static facade that instantiates the sender from
environment variables (SMTP_HOST, SMTP_PORT,
SMTP_SECURE, SMTP_USER, SMTP_PASS,
SMTP_FROM). Swapping the implementation requires changing one
line in EmailService.ts.
src/locales/ (TypeScript locale management code) moved to
source/locales/. The root locales/ (raw locale
data files — en/) moved to source/locale-data/.
Merging them into one directory would have mixed TypeScript source with data
files; keeping them separate makes each directory's purpose unambiguous.
The old setup had public/ gitignored with a !public/*.html
exception that never actually tracked the files. The new setup is cleaner:
all hand-written HTML pages live in source/pages/ (tracked),
build/ is entirely ignored, and the copy step bridges the two
at build time.
systemd is already present on every Linux server and integrates with
journalctl for log management. PM2 is easier for day-to-day
Node.js process management but adds an extra global dependency. For a
single-service deployment systemd is sufficient and keeps the server
dependency surface minimal.
CSS files, vendor libraries, and SVGs were historically placed directly
in public/ (gitignored) and never tracked. A fresh server
clone exposes this immediately — nothing in build/ exists
until the build runs, and the build can only copy what it finds in
source/. Moving all static assets to source/
makes them first-class source files and ensures a clean deploy from any
fresh clone.
scripts/copy-pages.js uses only fs and
path from the Node.js standard library. Adding a package like
copyfiles or cpx for a four-line operation would
be unnecessary complexity.
src/ → source/ (git mv, including library-ts submodule)
server/ → source/server/ (git mv)
locales/ → source/locale-data/ (git mv)
public/ → build/app/ (filesystem move, gitignored)
data/ → build/data/db/ (filesystem move, gitignored)
storage/ → build/data/storage/ (filesystem move, gitignored)
source/pages/ — new: hand-written HTML pages (tracked)
scripts/copy-pages.js — new: copies pages to build/app/ on build
tsconfig.client.json — rootDir, outDir, include, exclude, references updated
tsconfig.json — include updated
tsconfig.ts-node.json — include updated
source/library-ts/browser/tsconfig.roject.json — outDir updated
package.json — main and build script updated
.gitignore — replaced data/, storage/, public/ with build/
source/server/ — all __dirname paths and library-ts imports updated
source/components/*.css — moved from build/app/ into source control
source/vendor/ — vendor libs moved from build/app/ into source control
source/library-ts/browser/tsconfig.roject.json — outDir fixed in submodule, committed and pushed
scripts/copy-pages.js — expanded to copy all non-TS static assets from all frontend source dirs
source/server/db.ts, storage.ts — mkdirSync updated to use { recursive: true }
/etc/systemd/system/roject.service — new on Server A
/etc/nginx/sites-available/roject — new on Server A