2026-07-12 12:01:01 +00:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< title > Session Summary — 12 July 2026< / title >
< link rel = "stylesheet" href = "../../../../_assets_/styles.css" >
< link rel = "stylesheet" href = "../../../../_assets_/nav.css" >
< / head >
< body >
< div class = "page" >
< header >
< p class = "date" > Sunday, 12 July 2026< / p >
< h1 > Roject — Session Summary< / h1 >
< p class = "subtitle" >
2026-07-12 14:14:58 +00:00
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.
2026-07-12 12:01:01 +00:00
< / p >
< / header >
< section >
< h2 > What we built< / h2 >
< div class = "card" >
< h3 > Directory restructure< / h3 >
< p >
The project root was reorganised into two top-level directories that
cleanly separate source from build artefacts and runtime data:
< / p >
< ul style = "line-height:1.9;margin-top:0.75rem" >
< li > < code > source/< / code > — all TypeScript source (components, editor, server, rojos, locales, library-ts submodule) plus locale data and HTML pages< / li >
< li > < code > build/app/< / code > — compiled frontend output (was < code > public/< / code > )< / li >
< li > < code > build/data/db/< / code > — JSON user/project data (was < code > data/< / code > )< / li >
< li > < code > build/data/storage/< / code > — project files, sessions, layouts (was < code > storage/< / code > )< / li >
< / ul >
< p style = "margin-top:0.75rem" >
The git submodule (< code > library-ts< / code > ) was moved with < code > git mv< / code >
so < code > .gitmodules< / code > stayed in sync automatically. The entire
< code > build/< / code > tree is gitignored; < code > source/< / code > is fully tracked.
< / p >
< div class = "tags" >
< span class = "tag" > source/< / span >
< span class = "tag" > build/app/< / span >
< span class = "tag" > build/data/< / span >
< span class = "tag" > git mv< / span >
< / div >
< / div >
< div class = "card" >
< h3 > source/pages/ + copy-pages build step< / h3 >
< p >
HTML pages (< code > editor.html< / code > , < code > dashboard.html< / code > , etc.)
moved from < code > build/app/< / code > into < code > source/pages/< / code > so they
are tracked in git as source files. A new < code > scripts/copy-pages.js< / code >
(plain Node.js, no extra dependencies) copies them to < code > build/app/< / code >
as the second step of < code > npm run build< / code > :
< / p >
< pre style = "margin-top:0.75rem" > < code > tsc --build tsconfig.client.json & & node scripts/copy-pages.js< / code > < / pre >
< div class = "tags" >
< span class = "tag" > source/pages/< / span >
< span class = "tag" > scripts/copy-pages.js< / span >
< span class = "tag" > npm run build< / span >
< / div >
< / div >
2026-07-12 14:14:58 +00:00
< div class = "card" >
< h3 > First production deployment — roject.rokojori.com< / h3 >
< p >
Roject deployed to Server A and served publicly at
< code > https://roject.rokojori.com< / code > . Stack: Node.js 20,
< code > ts-node< / code > running < code > source/server/index.ts< / code > 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.
< / p >
< p style = "margin-top:0.75rem" >
Several build gaps were discovered and fixed during the deploy:
component CSS files were never in source control (moved to
< code > source/components/< / code > ); vendor libraries were in the gitignored
< code > build/app/vendor/< / code > (moved to < code > source/vendor/< / code > );
< code > mkdirSync< / code > calls in the server lacked < code > { recursive: true }< / code >
causing a crash on a fresh clone; and the library-ts browser
< code > tsconfig.roject.json< / code > still referenced the old
< code > public/< / code > outDir instead of < code > build/app/< / code > .
The copy script was also expanded to copy all non-TS static assets
(CSS, SVG, etc.) from all frontend source directories.
< / p >
< div class = "tags" >
< span class = "tag" > roject.rokojori.com< / span >
< span class = "tag" > systemd< / span >
< span class = "tag" > nginx< / span >
< span class = "tag" > Let's Encrypt< / span >
< span class = "tag" > Node.js 20< / span >
< / div >
< / div >
2026-07-12 16:50:04 +00:00
< div class = "card" >
< h3 > EmailService — SMTP email sending< / h3 >
< p >
Added a thin email layer to the backend under
< code > source/server/email/< / code > : an < code > EmailSender< / code > interface,
an < code > SMTPEmailSender< / code > implementation using Nodemailer, and an
< code > EmailService< / code > static facade that instantiates the sender from
environment variables (< code > SMTP_HOST< / code > , < code > SMTP_PORT< / code > ,
< code > SMTP_SECURE< / code > , < code > SMTP_USER< / code > , < code > SMTP_PASS< / code > ,
< code > SMTP_FROM< / code > ). Swapping the implementation requires changing one
line in < code > EmailService.ts< / code > .
< / p >
< div class = "tags" >
< span class = "tag" > Nodemailer< / span >
< span class = "tag" > EmailSender interface< / span >
< span class = "tag" > static facade< / span >
< span class = "tag" > env vars< / span >
< / div >
< / div >
2026-07-12 12:01:01 +00:00
< / section >
< section >
< h2 > Key Decisions< / h2 >
< div class = "decision" >
< strong > Two locale directories: source/locales/ vs source/locale-data/< / strong >
< p >
< code > src/locales/< / code > (TypeScript locale management code) moved to
< code > source/locales/< / code > . The root < code > locales/< / code > (raw locale
data files — < code > en/< / code > ) moved to < code > source/locale-data/< / code > .
Merging them into one directory would have mixed TypeScript source with data
files; keeping them separate makes each directory's purpose unambiguous.
< / p >
< / div >
< div class = "decision" >
< strong > build/ fully gitignored, source/pages/ tracked< / strong >
< p >
The old setup had < code > public/< / code > gitignored with a < code > !public/*.html< / code >
exception that never actually tracked the files. The new setup is cleaner:
all hand-written HTML pages live in < code > source/pages/< / code > (tracked),
< code > build/< / code > is entirely ignored, and the copy step bridges the two
at build time.
< / p >
< / div >
2026-07-12 14:14:58 +00:00
< div class = "decision" >
< strong > systemd over PM2< / strong >
< p >
systemd is already present on every Linux server and integrates with
< code > journalctl< / code > 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.
< / p >
< / div >
< div class = "decision" >
< strong > Static assets belong in source/, not build/< / strong >
< p >
CSS files, vendor libraries, and SVGs were historically placed directly
in < code > public/< / code > (gitignored) and never tracked. A fresh server
clone exposes this immediately — nothing in < code > build/< / code > exists
until the build runs, and the build can only copy what it finds in
< code > source/< / code > . Moving all static assets to < code > source/< / code >
makes them first-class source files and ensures a clean deploy from any
fresh clone.
< / p >
< / div >
2026-07-12 12:01:01 +00:00
< div class = "decision" >
< strong > Plain Node.js copy script, no npm dependency< / strong >
< p >
< code > scripts/copy-pages.js< / code > uses only < code > fs< / code > and
< code > path< / code > from the Node.js standard library. Adding a package like
< code > copyfiles< / code > or < code > cpx< / code > for a four-line operation would
be unnecessary complexity.
< / p >
< / div >
< / section >
< section >
< h2 > Structural Changes< / h2 >
< div class = "card" >
< p >
< code > src/< / code > → < code > source/< / code > (git mv, including library-ts submodule)< br >
< code > server/< / code > → < code > source/server/< / code > (git mv)< br >
< code > locales/< / code > → < code > source/locale-data/< / code > (git mv)< br >
< code > public/< / code > → < code > build/app/< / code > (filesystem move, gitignored)< br >
< code > data/< / code > → < code > build/data/db/< / code > (filesystem move, gitignored)< br >
< code > storage/< / code > → < code > build/data/storage/< / code > (filesystem move, gitignored)< br >
< code > source/pages/< / code > — new: hand-written HTML pages (tracked)< br >
< code > scripts/copy-pages.js< / code > — new: copies pages to build/app/ on build< br >
< code > tsconfig.client.json< / code > — rootDir, outDir, include, exclude, references updated< br >
< code > tsconfig.json< / code > — include updated< br >
< code > tsconfig.ts-node.json< / code > — include updated< br >
< code > source/library-ts/browser/tsconfig.roject.json< / code > — outDir updated< br >
< code > package.json< / code > — main and build script updated< br >
< code > .gitignore< / code > — replaced data/, storage/, public/ with build/< br >
2026-07-12 14:14:58 +00:00
< code > source/server/< / code > — all __dirname paths and library-ts imports updated< br >
< code > source/components/*.css< / code > — moved from build/app/ into source control< br >
< code > source/vendor/< / code > — vendor libs moved from build/app/ into source control< br >
< code > source/library-ts/browser/tsconfig.roject.json< / code > — outDir fixed in submodule, committed and pushed< br >
< code > scripts/copy-pages.js< / code > — expanded to copy all non-TS static assets from all frontend source dirs< br >
< code > source/server/db.ts< / code > , < code > storage.ts< / code > — mkdirSync updated to use < code > { recursive: true }< / code > < br >
< code > /etc/systemd/system/roject.service< / code > — new on Server A< br >
< code > /etc/nginx/sites-available/roject< / code > — new on Server A
2026-07-12 12:01:01 +00:00
< / p >
< / div >
< / section >
< footer >
Roject — session log — 12 July 2026
< / footer >
< / div >
< script > var NAV _ROOT = '../../../../' ; < / script >
< script src = "../../../../_assets_/nav-data.js" > < / script >
< script src = "../../../../_assets_/nav.js" > < / script >
< / body >
< / html >