[object Object]

← back to Microsite Engine

prefilled dropdowns for slug + domain + site ideas (owned CNCP domains × catalog niches)

3071de6e778b166f25a2d785024e98875b25aa11 · 2026-07-17 10:18:44 -0700 · Steve Abrams

- /api/facets now ships domains (224 owned, non-expired, not in the live fleet)
  and ideas (27 owned-domain × catalog-tag pairings with real product counts)
- slug + domain inputs get datalists from the portfolio; picking an owned
  domain auto-derives the slug
- new '💡 start from a site idea' select prefills slug/domain/name/tagline/
  keywords and refreshes the live preview
- greedy domain-name segmentation with plural handling; filler words
  (wallpaper/wallcovering/designer) aid segmentation but never count as a niche

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Files touched

Diff

commit 3071de6e778b166f25a2d785024e98875b25aa11
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Jul 17 10:18:44 2026 -0700

    prefilled dropdowns for slug + domain + site ideas (owned CNCP domains × catalog niches)
    
    - /api/facets now ships domains (224 owned, non-expired, not in the live fleet)
      and ideas (27 owned-domain × catalog-tag pairings with real product counts)
    - slug + domain inputs get datalists from the portfolio; picking an owned
      domain auto-derives the slug
    - new '💡 start from a site idea' select prefills slug/domain/name/tagline/
      keywords and refreshes the live preview
    - greedy domain-name segmentation with plural handling; filler words
      (wallpaper/wallcovering/designer) aid segmentation but never count as a niche
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---
 server.js | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/server.js b/server.js
index 6acfd0a..440c407 100644
--- a/server.js
+++ b/server.js
@@ -90,14 +90,22 @@ function segmentBase(base, vocab) {
 function domainIdeas() {
   const taken = new Set(liveSites().map(s => (s.domain || '').toLowerCase()));
   const free = ownedDomains().filter(d => !taken.has(d));
-  const tagByLower = new Map(FACETS.tagList.map(t => [t.name.toLowerCase(), t]));
+  const tagByLower = new Map();
+  for (const t of FACETS.tagList) {
+    const k = t.name.toLowerCase();
+    tagByLower.set(k, t);
+    if (!k.endsWith('s')) tagByLower.set(k + 's', t); // "fabrics" → tag "Fabric"
+  }
   const vocab = [...new Set([...tagByLower.keys(), ...FILLER_WORDS])]
     .filter(w => w.length >= 3).sort((a, b) => b.length - a.length);
   const ideas = [];
   for (const dom of free) {
     const base = dom.split('.')[0].replace(/[^a-z0-9]/g, '');
     const words = segmentBase(base, vocab);
-    const tags = words.map(w => tagByLower.get(w)).filter(Boolean);
+    // filler words (wallpaper/wallcovering/designer/…) help segmentation but are
+    // not a niche — an idea needs at least one REAL niche tag
+    const tags = words.filter(w => !FILLER_WORDS.includes(w.replace(/s$/, '')) && !FILLER_WORDS.includes(w))
+      .map(w => tagByLower.get(w)).filter(Boolean);
     if (!tags.length) continue;
     ideas.push({
       domain: dom,

← ad0025e auto-save: 2026-07-17T10:16:09 (2 files) — public/index.html  ·  back to Microsite Engine  ·  fix idea site-name segmentation: DP coverage-max splitter + d37b802 →