rojects/workspace/history/2026/07-July/15-Tuesday/index.html

121 lines
6.0 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tuesday, 15 July 2026 — Roject</title>
<link rel="stylesheet" href="../../../../_assets_/styles.css">
<link rel="stylesheet" href="../../../../_assets_/nav.css">
</head>
<body>
<div class="page">
<header>
<p class="date">Tuesday, 15 July 2026</p>
<h1>Session History</h1>
<p class="subtitle">styles.rokojori.com built and deployed; Roject font migration; add-subdomain deployment guide.</p>
</header>
<section>
<h2>What we built</h2>
<div class="card">
<h3>styles.rokojori.com — new service</h3>
<p>
Built a new standalone asset hosting service from scratch at
<code>styles.rokojori.com</code>. Same stack as the other rokojori services:
Node.js + Express + ts-node, no external database, Web Components + raw CSS on
the frontend.
</p>
<p style="margin-top:0.75rem">Key pieces:</p>
<ul style="margin-top:0.5rem;padding-left:1.25rem;line-height:1.9;font-size:0.9rem;color:var(--muted)">
<li><strong style="color:var(--text)">GET /get-font</strong> — public CSS endpoint; three modes: all weights, specific weights (+ auto-italic), or explicit variations. Returns <code>@font-face</code> CSS; font files served statically from <code>storage/fonts/</code>.</li>
<li><strong style="color:var(--text)">POST /api/fonts/download</strong> — auth-gated; hits Google Fonts API with a browser User-Agent to get woff2 URLs, downloads each file, writes <code>meta.json</code>.</li>
<li><strong style="color:var(--text)">GET /api/fonts</strong> — auth-gated; lists all downloaded font families and their available weights/italics.</li>
<li><strong style="color:var(--text)">CORS allowlist middleware</strong> — checks <code>Origin</code> header against <code>*.rokojori.com</code> regex; echoes origin back only if matched. Public <code>*</code> header explicitly avoided.</li>
<li><strong style="color:var(--text)">Auth</strong> — shared JWT cookie from rokojori-auth; <code>requireAccess</code> middleware copied from auth workspace (role: admin, or user + product: styles / premium). HTML pages redirect to login; API routes return 401/403 JSON.</li>
<li><strong style="color:var(--text)">Pages</strong><code>/</code> detects auth state via fetch and shows hero or sections list; <code>/list-fonts</code> renders all families with live preview sentence; <code>/add-fonts</code> takes family name + optional weights, downloads, shows inline preview.</li>
</ul>
</div>
<div class="card">
<h3>Roject — font migration and page cleanup</h3>
<p>
Removed three stale pages: <code>dashboard.html</code>, <code>groups.html</code>,
<code>projects.html</code> — all superseded by the project-home redesign from the
previous session.
</p>
<p style="margin-top:0.75rem">
Migrated Barlow font loading from Google Fonts to styles.rokojori.com:
removed the three Google Fonts <code>&lt;link&gt;</code> tags from
<code>source/pages/index.html</code> and added
<code>@import url('https://styles.rokojori.com/get-font?family=barlow&amp;weights=100,400,700,900')</code>
at the top of <code>project-list-default.css</code>. The theme now self-describes
its font dependency; no Google dependency at runtime.
</p>
</div>
<div class="card">
<h3>rokojori-auth workspace — add-subdomain deployment guide</h3>
<p>
Created <code>workspace/add-subdomain.html</code> — a step-by-step deployment
checklist for adding any new rokojori subdomain service to Server A. Covers:
Gitea repo creation, .gitignore, DNS on IONOS, server clone, install/build/env,
nginx HTTP config, Let's Encrypt via certbot, nginx HTTPS verification, and
systemd service setup.
</p>
<p style="margin-top:0.75rem">
The guide has an interactive variables bar at the top (subdomain, port, service
name) — all commands throughout the page update live via JS as you type.
systemd unit file format matched to the Roject convention:
<code>/usr/bin/npx ts-node</code>, <code>Restart=on-failure</code>,
<code>StandardOutput/Error=journal</code>.
Added a step 0 explaining the CORS allowlist pattern with full code example.
</p>
</div>
</section>
<section>
<h2>Key decisions</h2>
<div class="card">
<h3>Font files are woff2-only, named numerically</h3>
<p>
Convention: <code>400.woff2</code>, <code>400-italic.woff2</code>. No "bold"
alias — numeric weights only. woff2 has near-universal browser support; no
fallback formats needed.
</p>
</div>
<div class="card">
<h3>CORS restricted to *.rokojori.com, not wildcard</h3>
<p>
<code>Access-Control-Allow-Origin: *</code> was rejected in favour of an
allowlist that echoes back the matched origin. The regex
<code>/^https?:\/\/([\w-]+\.)?rokojori\.com$/</code> covers all current and
future subdomains. Extra origins can be added as strings or regexes to the
<code>CORS_ALLOWED</code> array.
</p>
</div>
<div class="card">
<h3>styles.rokojori.com scope expanded</h3>
<p>
Initially conceived as a font host; scope widened to a general shared-asset
platform: fonts now, shared HTML components / Web Components, CSS presets, and
binary assets (images, sounds, video) planned.
</p>
</div>
</section>
<footer>
Roject &mdash; session history
</footer>
</div>
<script>var NAV_ROOT = '../../../../';</script>
<script src="../../../../_assets_/nav-data.js"></script>
<script src="../../../../_assets_/nav.js"></script>
</body>
</html>