← back to build-pages
ui: /privacy + /terms boilerplate (no-tracking + as-is) — sitemap + footer + 6 smoke
3af9a4459860c0b8551489864d3909b3478acf25 · 2026-05-13 19:33:07 -0700 · SteveStudio2
Files touched
M server.jsM test/smoke.js
Diff
commit 3af9a4459860c0b8551489864d3909b3478acf25
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Wed May 13 19:33:07 2026 -0700
ui: /privacy + /terms boilerplate (no-tracking + as-is) — sitemap + footer + 6 smoke
---
server.js | 44 ++++++++++++++++++++++++++++++++++++++++++++
test/smoke.js | 8 +++++++-
2 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/server.js b/server.js
index 76b1477..671eac9 100644
--- a/server.js
+++ b/server.js
@@ -213,6 +213,10 @@ function shell(title, body, headExtra = '', meta = {}) {
<span class="bp-ftr-sep">·</span>
<a href="/about">about</a>
<span class="bp-ftr-sep">·</span>
+ <a href="/privacy">privacy</a>
+ <span class="bp-ftr-sep">·</span>
+ <a href="/terms">terms</a>
+ <span class="bp-ftr-sep">·</span>
<a href="/api">JSON API</a>
<span class="bp-ftr-sep">·</span>
<a href="/sitemap.xml">sitemap</a>
@@ -269,6 +273,8 @@ app.get('/sitemap.xml', async (_req, res, next) => {
const urls = [
`<url><loc>${base}/</loc><lastmod>${today}</lastmod><changefreq>daily</changefreq><priority>1.0</priority></url>`,
`<url><loc>${base}/about</loc><lastmod>${today}</lastmod><changefreq>monthly</changefreq><priority>0.6</priority></url>`,
+ `<url><loc>${base}/privacy</loc><lastmod>${today}</lastmod><changefreq>yearly</changefreq><priority>0.3</priority></url>`,
+ `<url><loc>${base}/terms</loc><lastmod>${today}</lastmod><changefreq>yearly</changefreq><priority>0.3</priority></url>`,
];
for (const slug of Object.keys(PROJECTS)) {
const bundle = await getProjectBundle(slug, PROJECTS[slug]).catch(() => null);
@@ -1203,6 +1209,44 @@ app.get('/api/projects/:slug', async (req, res, next) => {
} catch (e) { next(e); }
});
+// /privacy — what data this site collects. The honest answer: very little.
+app.get('/privacy', (_req, res) => {
+ res.send(shell('Privacy — build-pages', `
+ <h1>Privacy</h1>
+ <p class="bp-lede">build-pages is a static read-out of public git history. It collects nothing about you.</p>
+ <h2>What we don't collect</h2>
+ <ul>
+ <li>No accounts. No login. No cookies.</li>
+ <li>No analytics scripts. No tracking pixels.</li>
+ <li>No form submissions. The only inputs are search filters that stay in your browser URL.</li>
+ </ul>
+ <h2>What the server logs</h2>
+ <p>Standard nginx + Node access logs (IP, path, user-agent, response code, timing) for ops debugging.
+ Retained 30 days, not shared.</p>
+ <h2>What's public by design</h2>
+ <p>Every commit subject, body, author name + email as recorded in the git repo, file paths, and diffs.
+ Authors who don't want their email surfaced should set a private one via
+ <code>git config user.email</code> before committing. We don't redact retrospectively.</p>
+ <p class="bp-meta"><a href="/">← back to all projects</a></p>
+ `, '', { canonical: 'https://projects.agentabrams.com/privacy', desc: 'build-pages privacy — no tracking, no accounts, no cookies; standard server logs only.' }));
+});
+
+// /terms — minimal use-of-site terms.
+app.get('/terms', (_req, res) => {
+ res.send(shell('Terms — build-pages', `
+ <h1>Terms of use</h1>
+ <p class="bp-lede">build-pages is published as-is for transparency about how Steve's projects get built.</p>
+ <ul>
+ <li>All content is rendered from public git repos. No warranty of accuracy or completeness.</li>
+ <li>Don't scrape aggressively. Cache-Control headers tell you when to refetch.</li>
+ <li>Code snippets and diffs are © their author. Use under the license shown in each repo
+ (default: not licensed for redistribution unless stated).</li>
+ <li>No support obligation. Reach Steve at his usual channels for questions.</li>
+ </ul>
+ <p class="bp-meta"><a href="/">← back to all projects</a></p>
+ `, '', { canonical: 'https://projects.agentabrams.com/terms', desc: 'build-pages terms — public-as-is content from git, no support obligation.' }));
+});
+
// /about — short explainer for visitors arriving at projects.agentabrams.com.
app.get('/about', (_req, res) => {
res.send(shell('About — build-pages', `
diff --git a/test/smoke.js b/test/smoke.js
index f0f4677..4b66ee2 100644
--- a/test/smoke.js
+++ b/test/smoke.js
@@ -154,11 +154,17 @@ function check(name, cond, hint = '') {
r = await fetch('/p/nope-not-a-project');
check('unknown project: 404', r.status === 404);
- // 7b. /about page
+ // 7b. /about + /privacy + /terms
r = await fetch('/about');
check('about: 200', r.status === 200);
check('about: build-pages title',/About — build-pages/.test(r.body));
check('about: explainer copy', /live build journal/.test(r.body));
+ r = await fetch('/privacy');
+ check('privacy: 200', r.status === 200);
+ check('privacy: no tracking', /collects nothing about you/.test(r.body));
+ r = await fetch('/terms');
+ check('terms: 200', r.status === 200);
+ check('terms: as-is', /as-is for transparency/.test(r.body));
// 8. robots.txt — public crawlable + sitemap referenced
r = await fetch('/robots.txt');
← e4c31da ui: /about page explaining build-pages + sitemap + footer li
·
back to build-pages
·
alias: /search?q= 302→/?q= (convention path) + 2 smoke 451c6ad →