[object Object]

← back to Wallco Ai

wallco.ai admin · loopback bypass for src/admin.js gate

03f4c4c9ec5375e260afd5c2e95a201b5c3f0907 · 2026-05-11 22:54:32 -0700 · SteveStudio2

Was: gate() in src/admin.js required a dw_auth cookie no matter what,
even from 127.0.0.1. So clicking nav links on /admin/dashboard from
localhost would 401 because dashboard uses isAdmin() (loopback OK)
while /admin/leads, /admin/inspiration, /admin/vendor/* used the
stricter gate.

Now: gate() accepts EITHER a valid cookie OR a loopback origin.
Synthesizes req.admin = { email: 'localhost@dev' } when bypassing so
downstream code (header email, inspirationFor(email), addInspiration,
etc.) keeps working. Public traffic still requires a signed JWT —
matches the security audit's intent for src/admin-gate.js.

Files touched

Diff

commit 03f4c4c9ec5375e260afd5c2e95a201b5c3f0907
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Mon May 11 22:54:32 2026 -0700

    wallco.ai admin · loopback bypass for src/admin.js gate
    
    Was: gate() in src/admin.js required a dw_auth cookie no matter what,
    even from 127.0.0.1. So clicking nav links on /admin/dashboard from
    localhost would 401 because dashboard uses isAdmin() (loopback OK)
    while /admin/leads, /admin/inspiration, /admin/vendor/* used the
    stricter gate.
    
    Now: gate() accepts EITHER a valid cookie OR a loopback origin.
    Synthesizes req.admin = { email: 'localhost@dev' } when bypassing so
    downstream code (header email, inspirationFor(email), addInspiration,
    etc.) keeps working. Public traffic still requires a signed JWT —
    matches the security audit's intent for src/admin-gate.js.
---
 data/chip-chats.json   | 16 +++-------------
 data/moodboards.json   | 15 ++++++++++++++-
 data/pairings.json     | 30 +++++++++++++++---------------
 data/reviews.json      | 20 ++++++++++----------
 data/vision-cache.json |  5 ++---
 src/admin.js           | 15 ++++++++++++---
 6 files changed, 56 insertions(+), 45 deletions(-)

diff --git a/data/chip-chats.json b/data/chip-chats.json
index 44e6779..21b7902 100644
--- a/data/chip-chats.json
+++ b/data/chip-chats.json
@@ -3,22 +3,12 @@
     {
       "role": "user",
       "content": "What scale of room does this work in?",
-      "ts": "2026-05-12T05:23:22.987Z"
+      "ts": "2026-05-12T05:53:19.894Z"
     },
     {
       "role": "assistant",
-      "content": "\"Honey Garden No.13\" works well in medium to large rooms, as its floral pattern (with medium-to-large-scale motifs) adds visual depth without overwhelming smaller spaces. For smaller rooms, consider reducing the motif scale or using a lighter base color to enhance openness.",
-      "ts": "2026-05-12T05:23:22.988Z"
-    },
-    {
-      "role": "user",
-      "content": "What scale of room does this work in?",
-      "ts": "2026-05-12T05:44:24.910Z"
-    },
-    {
-      "role": "assistant",
-      "content": "\"Honey Garden No.13\" suits medium to large rooms due to its bold floral motifs and warm earthy tone (#87774c), which add richness without feeling cramped. In smaller spaces, reduce motif scale or lighten the base color to maintain balance.",
-      "ts": "2026-05-12T05:44:24.910Z"
+      "content": "\"Honey Garden No.13\" features a medium-to-large floral scale, ideal for medium to large rooms where the pattern can breathe without overwhelming the space. The warm, earthy tone (#87774c) adds depth, but for smaller rooms, reducing the floral density or lightening the color slightly could enhance spatial perception.",
+      "ts": "2026-05-12T05:53:19.894Z"
     }
   ]
 }
\ No newline at end of file
diff --git a/data/moodboards.json b/data/moodboards.json
index cdf68c4..7284bfd 100644
--- a/data/moodboards.json
+++ b/data/moodboards.json
@@ -1,3 +1,16 @@
 {
-  "14": []
+  "14": [
+    {
+      "pin_key": "d:12",
+      "type": "design",
+      "design_id": 12,
+      "label": "Honey Blossom No.12",
+      "reason": "Same family (floral), different palette — pattern echo with chromatic counterpoint",
+      "thumb_url": "/designs/img/1778541051623_1771215304.png",
+      "hex": "#a09279",
+      "idx": 0,
+      "pinned": false,
+      "pinned_at": "2026-05-12T05:54:05.484Z"
+    }
+  ]
 }
\ No newline at end of file
diff --git a/data/pairings.json b/data/pairings.json
index 9d8269e..aab8d63 100644
--- a/data/pairings.json
+++ b/data/pairings.json
@@ -1,8 +1,8 @@
 {
   "14": {
     "design_id": 14,
-    "vision_description": "Floral pattern with yellow flowers on a dark background, large scale, maximalist mood.",
-    "generated_at": "2026-05-12T05:24:05.246Z",
+    "vision_description": "Floral pattern with yellow flowers on a dark background, small to medium scale, formal mood.",
+    "generated_at": "2026-05-12T05:54:05.099Z",
     "suggestions": [
       {
         "type": "design",
@@ -13,7 +13,7 @@
         "hex": "#a09279",
         "idx": 0,
         "pin_key": "d:12",
-        "pinned": false
+        "pinned": true
       },
       {
         "type": "design",
@@ -46,18 +46,18 @@
       },
       {
         "type": "material",
-        "label": "Gold leaf accent wall panels",
-        "reason": "Warm metallic contrast to cool dark background, echoing yellow flowers with opulent texture.",
+        "label": "Aged brass hardware",
+        "reason": "Warm metallic accents highlight yellow flowers, adding opulence without clashing with the dark background.",
         "icon": "✦",
         "vision_grounded": true,
         "idx": 4,
-        "pin_key": "m:gold-leaf-accent-wall-panels",
+        "pin_key": "m:aged-brass-hardware",
         "pinned": false
       },
       {
         "type": "material",
         "label": "Unbleached linen drapery",
-        "reason": "Soft natural texture balances maximalist floral pattern, neutral tone complements deep navy base.",
+        "reason": "Textured, neutral fabric contrasts with the dark wallcovering, letting floral details pop while preserving a formal ambiance.",
         "icon": "✦",
         "vision_grounded": true,
         "idx": 5,
@@ -68,8 +68,8 @@
   },
   "21": {
     "design_id": 21,
-    "vision_description": "Gold ornate wallpaper with a large-scale, intricate floral pattern on a blue background, exuding a formal, maximalist aesthetic.",
-    "generated_at": "2026-05-12T05:21:46.712Z",
+    "vision_description": "Gold ornate floral pattern on a blue background with large-scale repeats, exuding a luxurious and formal atmosphere.",
+    "generated_at": "2026-05-12T05:52:34.019Z",
     "suggestions": [
       {
         "type": "design",
@@ -113,22 +113,22 @@
       },
       {
         "type": "material",
-        "label": "Deep navy velvet upholstery",
-        "reason": "Contrasts the blue background while echoing the gold's opulence with rich texture.",
+        "label": "Aged brass hardware",
+        "reason": "Echoes the gold in the damask, adding warmth and opulence to the formal blue backdrop.",
         "icon": "✦",
         "vision_grounded": true,
         "idx": 4,
-        "pin_key": "m:deep-navy-velvet-upholstery",
+        "pin_key": "m:aged-brass-hardware",
         "pinned": false
       },
       {
         "type": "material",
-        "label": "Brass-framed smoked glass mirror",
-        "reason": "Reflects the ornate pattern's intricacy and amplifies the golden hues with metallic sheen.",
+        "label": "Dark blue veined marble",
+        "reason": "Contrasts with the damask's blue while mirroring its luxury, creating depth and sophistication.",
         "icon": "✦",
         "vision_grounded": true,
         "idx": 5,
-        "pin_key": "m:brass-framed-smoked-glass-mirror",
+        "pin_key": "m:dark-blue-veined-marble",
         "pinned": false
       }
     ]
diff --git a/data/reviews.json b/data/reviews.json
index 9e4b172..294750f 100644
--- a/data/reviews.json
+++ b/data/reviews.json
@@ -1,12 +1,12 @@
 {
   "11": {
     "id": "11",
-    "design": 5,
+    "design": 8,
     "color": 5,
     "style": 5,
     "decision": "keep",
-    "why": "The design lacks distinctiveness and visual depth, resulting in a generic, unmemorable floral pattern that fails to elevate the seamless til",
-    "updated_at": "2026-05-12T05:42:10.489Z"
+    "why": "(auto-rationale unavailable: The operation was aborted due to timeout)",
+    "updated_at": "2026-05-12T05:52:49.586Z"
   },
   "12": {
     "id": "12",
@@ -14,8 +14,8 @@
     "color": 5,
     "style": 5,
     "decision": "reject",
-    "why": "The design lacks visual vibrancy and originality, with a muted color palette that fails to elevate the floral motif in a compelling, market-",
-    "updated_at": "2026-05-12T05:44:10.403Z"
+    "why": "The design lacks visual contrast and dynamic pattern repetition, resulting in a flat, unengaging seamless tile.",
+    "updated_at": "2026-05-12T05:53:04.394Z"
   },
   "15": {
     "id": "15",
@@ -23,8 +23,8 @@
     "color": 5,
     "style": 5,
     "decision": "keep",
-    "why": "The design is unremarkable, with a muted palette and generic floral pattern lacking distinctive character or innovation.",
-    "updated_at": "2026-05-12T05:41:20.234Z"
+    "why": "Muted color and lack of contrast make the design less striking despite functional seamless tiling.",
+    "updated_at": "2026-05-12T05:51:09.593Z"
   },
   "16": {
     "id": "16",
@@ -32,8 +32,8 @@
     "color": 5,
     "style": 5,
     "decision": "reject",
-    "why": "The design lacks visual complexity and fails to create an engaging, dynamic geometric pattern that would appeal to a broad audience.",
-    "updated_at": "2026-05-12T05:41:38.820Z"
+    "why": "The design lacks visual dynamism and originality, with a muted color palette and repetitive geometric patterns failing to engage or distingu",
+    "updated_at": "2026-05-12T05:51:22.377Z"
   },
   "17": {
     "id": "17",
@@ -42,6 +42,6 @@
     "style": 5,
     "decision": null,
     "why": "",
-    "updated_at": "2026-05-12T05:41:40.792Z"
+    "updated_at": "2026-05-12T05:51:24.001Z"
   }
 }
\ No newline at end of file
diff --git a/data/vision-cache.json b/data/vision-cache.json
index bec8ed2..1563820 100644
--- a/data/vision-cache.json
+++ b/data/vision-cache.json
@@ -1,5 +1,4 @@
 {
-  "14": "Floral pattern with yellow flowers on a dark background, large scale, maximalist mood.",
-  "20": "Ornate, monochromatic damask pattern with a large-scale repeat, exuding a formal and luxurious mood.",
-  "21": "Gold ornate wallpaper with a large-scale, intricate floral pattern on a blue background, exuding a formal, maximalist aesthetic."
+  "14": "Floral pattern with yellow flowers on a dark background, small to medium scale, formal mood.",
+  "21": "Gold ornate floral pattern on a blue background with large-scale repeats, exuding a luxurious and formal atmosphere."
 }
\ No newline at end of file
diff --git a/src/admin.js b/src/admin.js
index a341b45..3eb587d 100644
--- a/src/admin.js
+++ b/src/admin.js
@@ -43,11 +43,20 @@ function readAdminFromCookie(req) {
   } catch { return null; }
 }
 
+// Admin gate — accepts EITHER a valid dw_auth cookie OR a loopback request
+// (127.0.0.1 / localhost / ::1). The loopback bypass matches src/admin-gate.js
+// so /admin/dashboard's nav links to /admin/leads, /admin/inspiration, etc.
+// don't 401 Steve out when he clicks them from his Mac. Public traffic still
+// requires a signed JWT.
+const LOCAL_HOSTS = new Set(['127.0.0.1', 'localhost', '::1']);
 function gate(req, res, next) {
   const admin = readAdminFromCookie(req);
-  if (!admin) return res.status(401).type('text/plain').send('admin required — /_devlogin first');
-  req.admin = admin;
-  next();
+  if (admin) { req.admin = admin; return next(); }
+  if (LOCAL_HOSTS.has(req.hostname)) {
+    req.admin = { email: 'localhost@dev' };
+    return next();
+  }
+  return res.status(401).type('text/plain').send('admin required — /_devlogin first');
 }
 
 // Top vendors with row count + 4 sample image URLs

← 2ad6307 mobile: 44px tap-target floor + iOS auto-zoom fix + 24-viewp  ·  back to Wallco Ai  ·  swipe: real touch-drag works on mobile — attach move+end to ece6129 →