← back to Wallco Ai
styleguides.wallco.ai → admin-only; revert public metering on batch/recolor
5b012f979ce9b625bb7abc78fdc97973d3718fa1 · 2026-06-01 12:33:14 -0700 · Steve Abrams
Files touched
Diff
commit 5b012f979ce9b625bb7abc78fdc97973d3718fa1
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Mon Jun 1 12:33:14 2026 -0700
styleguides.wallco.ai → admin-only; revert public metering on batch/recolor
---
server.js | 43 ++++++++++++++-----------------------------
1 file changed, 14 insertions(+), 29 deletions(-)
diff --git a/server.js b/server.js
index 5f07e71..d895997 100644
--- a/server.js
+++ b/server.js
@@ -1174,17 +1174,18 @@ setInterval(() => load(true), 30000);
// check as a CRITICAL bypass (anyone could mint a token with {role:"admin"}).
const { isAdmin, requireAdmin } = require('./src/admin-gate');
-// ── Style Guides — Brand Selector (PUBLIC, metered) ────────────────────────
+// ── Style Guides — Brand Selector (ADMIN-ONLY) ─────────────────────────────
// A curated picker of fashion + wallcovering houses whose palettes/signatures
// seed the generative pipeline. Three live actions on the page:
// • Generate → POST /api/generator/batch (new SDXL designs in the houses' look)
// • Apply → POST /api/design/:id/recolor (restyle an existing studio design)
// • Export → portable style-guide JSON / Figma block (client-side)
-// Open to the public (Steve 2026-06-01 "give user all abilities") but METERED:
-// every non-admin visitor gets SG_IMAGE_CAP paid renders per rolling 24h,
-// keyed by client IP. Generate counts its batch size; Recolor counts 1 each.
-// Admins (cookie / ?admin / localhost) are unlimited. The cap protects the
-// Replicate/Gemini bill from open-internet abuse.
+// Admin-only for now (Steve 2026-06-01 — "styleguides.wallco.ai is for admin
+// accounts for now"). The public-metering experiment is reverted: the page and
+// its recolor action gate on isAdmin, and batch is back to its original public
+// uncapped behavior. The sg* quota helpers below are kept dormant so the page's
+// quota poll still answers cleanly (admins → unlimited) and re-enabling public
+// access later is a one-line flip, not a rewrite.
const SG_IMAGE_CAP = 5;
const SG_WINDOW_MS = 24 * 60 * 60 * 1000;
const _sgQuota = new Map(); // ip -> { used, resetAt }
@@ -1205,26 +1206,23 @@ function sgConsume(req, k) { sgBudget(req).entry.used += Math.max(0, k | 0); }
// the public here does NOT open it on the main storefront PDPs (those stay 404
// for non-admins). batch is already public, so it's capped for everyone non-admin.
function fromSG(req) { return String(req.headers['x-sg'] || '') === '1'; }
-// Recolor gate: admin → unlimited; styleguides public within budget → allow;
-// anyone else → 404 (storefront recolor stays admin-only as before).
+// Recolor gate: admin-only (Steve 2026-06-01 — styleguides reverted to
+// admin-only, so recolor goes back to its original admin-only behavior).
function sgRecolorGate(req, res, next) {
if (isAdmin(req)) return next();
- if (fromSG(req)) {
- if (sgBudget(req).remaining <= 0) {
- return res.status(429).json({ ok: false, error: `Free limit reached — ${SG_IMAGE_CAP} images per day. Come back tomorrow.` });
- }
- return next();
- }
return res.status(404).type('html').send('<h1>404</h1>');
}
app.get('/', (req, res, next) => {
if (/^styleguides\./i.test(req.hostname || '')) {
+ // Admin-only for now (Steve 2026-06-01). Non-admins get a 404 so the
+ // subdomain doesn't even advertise that the styleguides page exists.
+ if (!isAdmin(req)) return res.status(404).type('html').send('<h1>404</h1>');
return res.sendFile(path.join(__dirname, 'public', 'admin', 'styleguides.html'));
}
next();
});
-app.get('/admin/styleguides', (req, res) => {
+app.get('/admin/styleguides', requireAdmin, (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'admin', 'styleguides.html'));
});
app.get('/api/styleguides/quota', (req, res) => {
@@ -21289,15 +21287,6 @@ app.post('/api/generator/batch', (req, res) => {
// Clamp the requested count to a sane 1–50 so a fat-fingered number can't
// spawn a runaway render job.
let n = Math.max(1, Math.min(50, parseInt(req.body && req.body.n, 10) || 1));
- // Public metering (Steve 2026-06-01): non-admin callers get SG_IMAGE_CAP
- // paid renders / 24h per IP. Clamp n to what's left; refuse when exhausted.
- if (!isAdmin(req)) {
- const b = sgBudget(req);
- if (b.remaining <= 0) {
- return res.status(429).json({ ok: false, error: `Free limit reached — ${SG_IMAGE_CAP} images per day. Come back tomorrow.`, remaining: 0, cap: SG_IMAGE_CAP });
- }
- n = Math.min(n, b.remaining);
- }
// Build the prompt (one prompt drives the whole batch; each render gets its
// own random seed so the N outputs are siblings, not duplicates).
@@ -21376,11 +21365,8 @@ app.post('/api/generator/batch', (req, res) => {
} catch {}
});
- // Charge the public budget for the renders we just kicked off.
- if (!isAdmin(req)) sgConsume(req, n);
// Respond immediately — the batch renders in the background.
res.json({ ok: true, run_id: runId, count: n, status: 'running', prompt,
- remaining: isAdmin(req) ? null : sgBudget(req).remaining,
note: `Rendering ${n} design${n>1?'s':''} in the background — watch the Recent Runs list. Safe to close this tab.` });
} catch (e) { res.status(500).json({ ok:false, error: e.message }); }
});
@@ -24042,8 +24028,7 @@ app.post('/api/design/:id/recolor', sgRecolorGate, express.json(), async (req, r
tags: baseTags,
});
- if (!isAdmin(req)) sgConsume(req, 1);
- res.json({ ok: true, parent_id: id, new_id: newId, new_image_url: '/designs/img/' + filename, hue: hueKey, elapsed_s: elapsed, remaining: isAdmin(req) ? null : sgBudget(req).remaining });
+ res.json({ ok: true, parent_id: id, new_id: newId, new_image_url: '/designs/img/' + filename, hue: hueKey, elapsed_s: elapsed });
} catch (e) {
res.status(500).json({ ok: false, error: e.message });
}
← 55c9073 batch-regen driver: 4-gate (seam+color+concept+settlement-OK
·
back to Wallco Ai
·
feat(admin): side-by-side prompt-vs-image A/B rating surface 2070bb0 →