[object Object]

← back to Wallco Ai

wallco-ai: gate Rate panel on admin, restore See-in-Room generator button

e5bfcadecc4a8382f72c16591821503fed4ecad7 · 2026-05-13 12:44:39 -0700 · SteveStudio2

- Rate panel only renders for admins. The POST /api/design/:id/rate
  handler is admin-gated, so non-admins saw the panel but every click
  produced 'save error' — render-time gate fixes both surface and root.

- Add See-in-Room generator bar above the rooms gallery (room-type +
  angle pickers, Generate Room button). Wired to existing POST /api/room
  and dispatches wallco:room-generated so the gallery refreshes in place.
  Admin-only since each call hits the upstream renderer (ROOM_API).

Files touched

Diff

commit e5bfcadecc4a8382f72c16591821503fed4ecad7
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Wed May 13 12:44:39 2026 -0700

    wallco-ai: gate Rate panel on admin, restore See-in-Room generator button
    
    - Rate panel only renders for admins. The POST /api/design/:id/rate
      handler is admin-gated, so non-admins saw the panel but every click
      produced 'save error' — render-time gate fixes both surface and root.
    
    - Add See-in-Room generator bar above the rooms gallery (room-type +
      angle pickers, Generate Room button). Wired to existing POST /api/room
      and dispatches wallco:room-generated so the gallery refreshes in place.
      Admin-only since each call hits the upstream renderer (ROOM_API).
---
 data/designs.json | 462 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 server.js         |  80 +++++++++-
 2 files changed, 538 insertions(+), 4 deletions(-)

diff --git a/data/designs.json b/data/designs.json
index 93c8409..c71887e 100644
--- a/data/designs.json
+++ b/data/designs.json
@@ -74478,5 +74478,467 @@
     "user_scale_good": null,
     "user_stars": null,
     "room_mockups": []
+  },
+  {
+    "id": 3613,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#946645",
+    "saturation": 0.364,
+    "title": "Amber Atelier No.3613",
+    "handle": "wallco-3613",
+    "image_url": "/designs/img/1778701097120_670545827.png",
+    "filename": "1778701097120_670545827.png",
+    "generator": "wallco.ai",
+    "seed": 670545827,
+    "is_published": false,
+    "created_at": "2026-05-13T19:38:34.561649+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3614,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#946645",
+    "saturation": 0.364,
+    "title": "Amber Salon No.3614",
+    "handle": "wallco-3614",
+    "image_url": "/designs/img/var_3613_hue+60_1778701114878.png",
+    "filename": "var_3613_hue+60_1778701114878.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-13T19:38:37.319804+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3615,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#946645",
+    "saturation": 0.364,
+    "title": "Amber Baroque No.3615",
+    "handle": "wallco-3615",
+    "image_url": "/designs/img/var_3613_hue+120_1778701117324.png",
+    "filename": "var_3613_hue+120_1778701117324.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-13T19:38:39.504732+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3616,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#946645",
+    "saturation": 0.364,
+    "title": "Amber Damask No.3616",
+    "handle": "wallco-3616",
+    "image_url": "/designs/img/var_3613_hue+180_1778701119507.png",
+    "filename": "var_3613_hue+180_1778701119507.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-13T19:38:41.682915+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3617,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#946645",
+    "saturation": 0.364,
+    "title": "Amber Heirloom No.3617",
+    "handle": "wallco-3617",
+    "image_url": "/designs/img/var_3613_hue-60_1778701121686.png",
+    "filename": "var_3613_hue-60_1778701121686.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-13T19:38:44.321034+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3618,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#946645",
+    "saturation": 0.364,
+    "title": "Amber Atelier No.3618",
+    "handle": "wallco-3618",
+    "image_url": "/designs/img/var_3613_mono_1778701124345.png",
+    "filename": "var_3613_mono_1778701124345.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-13T19:38:46.924466+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3619,
+    "kind": "seamless_tile",
+    "category": "drunk-animals",
+    "dominant_hex": "#221d21",
+    "saturation": 0.079,
+    "title": "Noir Folly No.3619",
+    "handle": "wallco-3619",
+    "image_url": "/designs/img/1778701171331_388503547.png",
+    "filename": "1778701171331_388503547.png",
+    "generator": "wallco.ai",
+    "seed": 388503547,
+    "is_published": false,
+    "created_at": "2026-05-13T19:39:40.304022+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3620,
+    "kind": "seamless_tile",
+    "category": "stoned-animals",
+    "dominant_hex": "#676954",
+    "saturation": 0.111,
+    "title": "Olive Stealie No.3620",
+    "handle": "wallco-3620",
+    "image_url": "/designs/img/1778701171481_944749873.png",
+    "filename": "1778701171481_944749873.png",
+    "generator": "wallco.ai",
+    "seed": 944749873,
+    "is_published": false,
+    "created_at": "2026-05-13T19:39:43.234407+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3621,
+    "kind": "seamless_tile",
+    "category": "stoned-animals",
+    "dominant_hex": "#372e23",
+    "saturation": 0.222,
+    "title": "Amber Trip No.3621",
+    "handle": "wallco-3621",
+    "image_url": "/designs/img/1778701261994_1216365692.png",
+    "filename": "1778701261994_1216365692.png",
+    "generator": "wallco.ai",
+    "seed": 1216365692,
+    "is_published": false,
+    "created_at": "2026-05-13T19:41:12.892104+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3622,
+    "kind": "seamless_tile",
+    "category": "drunk-animals",
+    "dominant_hex": "#4b252e",
+    "saturation": 0.339,
+    "title": "Rose Tableau No.3622",
+    "handle": "wallco-3622",
+    "image_url": "/designs/img/1778701261993_1028134879.png",
+    "filename": "1778701261993_1028134879.png",
+    "generator": "wallco.ai",
+    "seed": 1028134879,
+    "is_published": false,
+    "created_at": "2026-05-13T19:41:13.424197+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3623,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#3a484a",
+    "saturation": 0.121,
+    "title": "Marine Atelier No.3623",
+    "handle": "wallco-3623",
+    "image_url": "/designs/img/1778701294966_261236032.png",
+    "filename": "1778701294966_261236032.png",
+    "generator": "wallco.ai",
+    "seed": 261236032,
+    "is_published": false,
+    "created_at": "2026-05-13T19:41:43.184939+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3624,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#3a484a",
+    "saturation": 0.121,
+    "title": "Marine Salon No.3624",
+    "handle": "wallco-3624",
+    "image_url": "/designs/img/var_3623_hue+60_1778701303289.png",
+    "filename": "var_3623_hue+60_1778701303289.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-13T19:41:45.375027+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3625,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#3a484a",
+    "saturation": 0.121,
+    "title": "Marine Baroque No.3625",
+    "handle": "wallco-3625",
+    "image_url": "/designs/img/var_3623_hue+120_1778701305380.png",
+    "filename": "var_3623_hue+120_1778701305380.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-13T19:41:47.463367+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3626,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#3a484a",
+    "saturation": 0.121,
+    "title": "Marine Damask No.3626",
+    "handle": "wallco-3626",
+    "image_url": "/designs/img/var_3623_hue+180_1778701307466.png",
+    "filename": "var_3623_hue+180_1778701307466.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-13T19:41:49.515658+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3627,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#3a484a",
+    "saturation": 0.121,
+    "title": "Marine Heirloom No.3627",
+    "handle": "wallco-3627",
+    "image_url": "/designs/img/var_3623_hue-60_1778701309519.png",
+    "filename": "var_3623_hue-60_1778701309519.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-13T19:41:51.576248+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3628,
+    "kind": "seamless_tile",
+    "category": "damask",
+    "dominant_hex": "#3a484a",
+    "saturation": 0.121,
+    "title": "Marine Atelier No.3628",
+    "handle": "wallco-3628",
+    "image_url": "/designs/img/var_3623_mono_1778701311580.png",
+    "filename": "var_3623_mono_1778701311580.png",
+    "generator": "wallco.ai",
+    "seed": 0,
+    "is_published": false,
+    "created_at": "2026-05-13T19:41:53.727466+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3629,
+    "kind": "seamless_tile",
+    "category": "drunk-animals",
+    "dominant_hex": "#83575a",
+    "saturation": 0.202,
+    "title": "Rose Folly No.3629",
+    "handle": "wallco-3629",
+    "image_url": "/designs/img/1778701311998_1888951892.png",
+    "filename": "1778701311998_1888951892.png",
+    "generator": "wallco.ai",
+    "seed": 1888951892,
+    "is_published": false,
+    "created_at": "2026-05-13T19:42:00.633368+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3630,
+    "kind": "seamless_tile",
+    "category": "drunk-animals",
+    "dominant_hex": "#be9a61",
+    "saturation": 0.417,
+    "title": "Honey Hiccup No.3630",
+    "handle": "wallco-3630",
+    "image_url": "/designs/img/1778701351335_1951006117.png",
+    "filename": "1778701351335_1951006117.png",
+    "generator": "wallco.ai",
+    "seed": 1951006117,
+    "is_published": false,
+    "created_at": "2026-05-13T19:42:39.58865+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3631,
+    "kind": "seamless_tile",
+    "category": "stoned-animals",
+    "dominant_hex": "#949a7b",
+    "saturation": 0.133,
+    "title": "Olive Trip No.3631",
+    "handle": "wallco-3631",
+    "image_url": "/designs/img/1778701351484_977935512.png",
+    "filename": "1778701351484_977935512.png",
+    "generator": "wallco.ai",
+    "seed": 977935512,
+    "is_published": false,
+    "created_at": "2026-05-13T19:42:43.439481+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3632,
+    "kind": "seamless_tile",
+    "category": "drunk-animals",
+    "dominant_hex": "#6f6a4d",
+    "saturation": 0.181,
+    "title": "Honey Tableau No.3632",
+    "handle": "wallco-3632",
+    "image_url": "/designs/img/1778701441329_111881294.png",
+    "filename": "1778701441329_111881294.png",
+    "generator": "wallco.ai",
+    "seed": 111881294,
+    "is_published": false,
+    "created_at": "2026-05-13T19:44:10.042957+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
+  },
+  {
+    "id": 3633,
+    "kind": "seamless_tile",
+    "category": "stoned-animals",
+    "dominant_hex": "#292829",
+    "saturation": 0.012,
+    "title": "Noir Daydream No.3633",
+    "handle": "wallco-3633",
+    "image_url": "/designs/img/1778701441479_1026850218.png",
+    "filename": "1778701441479_1026850218.png",
+    "generator": "wallco.ai",
+    "seed": 1026850218,
+    "is_published": false,
+    "created_at": "2026-05-13T19:44:13.069861+00:00",
+    "motifs": [],
+    "user_removed": false,
+    "user_color_good": null,
+    "user_style_good": null,
+    "user_scale_good": null,
+    "user_stars": null,
+    "room_mockups": []
   }
 ]
\ No newline at end of file
diff --git a/server.js b/server.js
index 3662dac..ed4330d 100644
--- a/server.js
+++ b/server.js
@@ -5527,10 +5527,11 @@ ${htmlHeader('/designs')}
         </script>
         ` : ''}
 
+        ${_isAdmin ? `
         <!-- ── USER RATING PANEL ─────────────────────────────────────────
              Feeds spoon_all_designs.user_color_good / style_good / scale_good /
-             stars / removed. Localhost-admin auto-allowed. Aggregated counts
-             will tune future prompt generation. -->
+             stars / removed. Admin-only — POST handler is admin-gated, so
+             rendering for non-admins guarantees "save error" on every click. -->
         <div id="rating-panel" data-design-id="${design.id}"
              style="margin:18px 0;padding:14px 16px;background:var(--card-bg,#f4f0e8);border:1px solid var(--line,#d8d0c0);border-radius:8px;font:13px var(--sans,system-ui)">
           <div style="display:flex;flex-wrap:wrap;gap:14px;align-items:center;justify-content:space-between">
@@ -5649,6 +5650,7 @@ ${htmlHeader('/designs')}
           });
         })();
         </script>
+        ` : ''}
 
         <div class="scale-preview" style="margin-top:18px">
           <div class="scale-controls" style="display:flex;align-items:center;gap:14px;margin-bottom:10px;flex-wrap:wrap">
@@ -7327,13 +7329,83 @@ ${htmlHeader('/designs')}
 
   <!-- Generated Rooms gallery — hydrates from /api/rooms?design_id={{id}} -->
   <section id="rooms-gallery" class="rooms-gallery" data-design-id="${design.id}" style="margin:48px auto 0;max-width:1200px;padding:0 24px;">
-    <div class="rg-head" style="display:flex;align-items:baseline;gap:16px;border-top:1px solid var(--rule,#e5e5e0);padding-top:24px;margin-bottom:18px;">
+    <div class="rg-head" style="display:flex;align-items:baseline;gap:16px;border-top:1px solid var(--rule,#e5e5e0);padding-top:24px;margin-bottom:18px;flex-wrap:wrap;">
       <h2 style="margin:0;font:500 22px/1.2 ui-serif,Georgia,serif;">Generated rooms</h2>
       <span id="rg-count" style="font:11px/1.4 ui-sans-serif,system-ui,sans-serif;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-faint,#6e6e68);"></span>
       <span id="rg-admin-badge" style="display:none;margin-left:auto;font:10px/1.4 ui-sans-serif,system-ui,sans-serif;letter-spacing:.14em;text-transform:uppercase;color:#b00020;">admin mode</span>
     </div>
+    ${_isAdmin ? `
+    <!-- See in Room generator — admin-only because it hits the upstream
+         renderer at ROOM_API ($/call). Triggers POST /api/room and dispatches
+         wallco:room-generated so the gallery below refreshes in place. -->
+    <div id="rg-gen-bar" style="display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-bottom:18px;padding:12px 14px;background:var(--card-bg,#f4f0e8);border:1px solid var(--rule,#e5e5e0);border-radius:8px;font:13px ui-sans-serif,system-ui,sans-serif;">
+      <strong style="font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-faint,#7a6e5a)">See in room</strong>
+      <label style="display:flex;align-items:center;gap:6px;font-size:11px;color:var(--ink-faint,#7a6e5a);">
+        Room
+        <select id="rg-room-type" style="font:12px ui-sans-serif,system-ui,sans-serif;padding:4px 8px;border:1px solid var(--line,#d8d0c0);background:#fff;border-radius:4px;">
+          <option value="bedroom">Bedroom</option>
+          <option value="living_room">Living room</option>
+          <option value="dining_room">Dining room</option>
+          <option value="office">Office</option>
+          <option value="bathroom">Bathroom</option>
+        </select>
+      </label>
+      <label style="display:flex;align-items:center;gap:6px;font-size:11px;color:var(--ink-faint,#7a6e5a);">
+        Angle
+        <select id="rg-angle" style="font:12px ui-sans-serif,system-ui,sans-serif;padding:4px 8px;border:1px solid var(--line,#d8d0c0);background:#fff;border-radius:4px;">
+          <option value="straight_on">Straight on</option>
+          <option value="three_quarter">3/4 view</option>
+          <option value="wide">Wide</option>
+        </select>
+      </label>
+      <button id="rg-generate-btn" type="button"
+        style="background:#1f1808;border:1px solid #1f1808;color:#fff;padding:6px 14px;border-radius:14px;cursor:pointer;font-size:12px;letter-spacing:.06em;text-transform:uppercase;">
+        Generate Room
+      </button>
+      <span id="rg-generate-status" style="font-size:11px;color:var(--ink-faint,#888);margin-left:auto;"></span>
+    </div>
+    <script>
+    (function(){
+      var btn = document.getElementById('rg-generate-btn');
+      var statusEl = document.getElementById('rg-generate-status');
+      var roomTypeSel = document.getElementById('rg-room-type');
+      var angleSel = document.getElementById('rg-angle');
+      var designId = document.getElementById('rooms-gallery').dataset.designId;
+      btn.addEventListener('click', function(){
+        btn.disabled = true;
+        var originalLabel = btn.textContent;
+        btn.textContent = 'Generating…';
+        statusEl.textContent = 'rendering room (15-30s)…';
+        fetch('/api/room', {
+          method: 'POST',
+          headers: { 'Content-Type': 'application/json' },
+          credentials: 'same-origin',
+          body: JSON.stringify({
+            design_id: parseInt(designId, 10),
+            roomType: roomTypeSel.value,
+            angle: angleSel.value
+          })
+        }).then(function(r){
+          return r.json().then(function(j){ return { ok: r.ok, j: j }; });
+        }).then(function(wrap){
+          if (!wrap.ok || wrap.j.ok === false) {
+            throw new Error((wrap.j && wrap.j.error) || ('http ' + (wrap.j.status || '?')));
+          }
+          statusEl.textContent = 'saved · refreshing gallery';
+          window.dispatchEvent(new CustomEvent('wallco:room-generated'));
+          setTimeout(function(){ statusEl.textContent = ''; }, 2000);
+        }).catch(function(e){
+          statusEl.textContent = 'error: ' + e.message;
+        }).then(function(){
+          btn.disabled = false;
+          btn.textContent = originalLabel;
+        });
+      });
+    })();
+    </script>
+    ` : ''}
     <div id="rg-grid" style="display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14px;"></div>
-    <div id="rg-empty" style="display:none;padding:32px;text-align:center;color:var(--ink-faint,#6e6e68);font-style:italic;">No rooms generated for this pattern yet. Use the "Generate Room" button above to create one.</div>
+    <div id="rg-empty" style="display:none;padding:32px;text-align:center;color:var(--ink-faint,#6e6e68);font-style:italic;">${_isAdmin ? 'No rooms generated for this pattern yet. Use the "Generate Room" button above to create one.' : 'No rooms generated for this pattern yet.'}</div>
   </section>
 </main>
 ${FOOTER}

← 39b4997 api/designs: filter out rows whose image file is missing on  ·  back to Wallco Ai  ·  package: pin multer dep (wallco prod kept losing it on npm c 05ab37b →