rmnr
DocsLayoutsModulesDirectoryBest PracticeAgentsInstall

Command Palette

Search for a command to run...

New
  • Introduction
  • Installation
  • Architecture
  • Stack
  • Directory
  • Install with Agent
    new
  • Bundle Builder
    new
  • MCP server
    new
  • VPS Control Room
    new
  • Changelog
    new
  • All website templates
    new
  • Personal Brand OS
  • Agency Studio OS
  • Notion Page Clone OS — localStorage demo (pointer to open-silong for production)
  • SaaS Marketing OS
  • Kreator Studio OS
  • Konsultan OS
  • Wirausaha OS
  • Riset Kit
  • All layouts
  • 19
  • 3
  • 6
  • All slices
    new
  • 2
  • 2
  • 6
  • 3
  • 3
  • 1
  • 1
  • 7
  • 24
  • 6
  • All recipes

Architecture

Vertical-slice. Copy-first. One dispatcher across N templates. Subdomain demos. No fork.

Subdomain routing

Each of the 8 website templates gets a portfolio-quality demo URL via wildcard DNS + a host-header rewriter in proxy.ts. Zero forked repos. All 8 subdomains serve the same Next.js build — edit once, push, all 8 reflect on next request.

proxy.ts → AdminFeatureStubPagetext
Request → demo-konsultan.rahmanef.com/admin/admin-panel/users
            │
            ▼
        proxy.ts (root, Next 16)
            │
            ├── Host header → resolveDemoSlug("demo-konsultan") → "konsultan-os"
            └── Path rewrite → /preview/konsultan-os/dashboard/admin/admin-panel/users
                                                      │
                                                      ▼
                                          AdminFeatureStubPage(segment="users")
                                                      │
                                                      └─► <UsersBlockView />

Admin-panel dispatcher pattern

Each template's admin panel feature route is a 1-line stub that calls a shared dispatcher. Adding a new real block = one switch case + one BlockView file — propagates to all 8 templates' routes simultaneously.

components/templates/_shared/admin-panel/AdminFeatureStubPage.tsxtsx
// components/templates/_shared/admin-panel/AdminFeatureStubPage.tsx
//
// One file, 6 dispatch cases. 8 templates × 6 admin-panel blocks = 48
// routes. Every template's /admin/admin-panel/<segment>/page.tsx just
// calls <AdminFeatureStubPage segment="X" /> — zero per-template
// duplication.

export function AdminFeatureStubPage({ segment }: { segment: string }) {
  const block = ADMIN_PANEL_BLOCKS.find((b) => b.segment === segment);
  if (!block) notFound();
  if (segment === "users")     return <UsersBlockView />;
  if (segment === "audit-log") return <AuditLogBlockView />;
  if (segment === "ai-config") return <AiConfigBlockView />;
  if (segment === "analytics") return <AnalyticsBlockView />;
  if (segment === "webhooks")  return <WebhooksBlockView />;
  if (segment === "settings")  return <SettingsBlockView />;
  return <AdminFeatureCard block={block} />;  // fallback
}
Block × template coveragetext
             users  audit-log  ai-config  analytics  webhooks  settings
konsultan      ✅        ✅          ✅          ✅          ✅         ✅
personal-brand ✅        ✅          ✅          ✅          ✅         ✅
kreator        ✅        ✅          ✅          ✅          ✅         ✅
wirausaha      ✅        ✅          ✅          ✅          ✅         ✅
riset          ✅        ✅          ✅          ✅          ✅         ✅
agency         ✅        ✅          ✅          ✅          ✅         ✅
saas           ✅        ✅          ✅          ✅          ✅         ✅
notion-clone   ✅        ✅          ✅          ✅          ✅         ✅

   8 templates × 6 blocks = 48 routes served by 1 dispatcher

Block file shape

Every block follows the same shape — view orchestrator + extracted sub-components, all ≤200 LOC. Shared chrome (BlockHeader, SectionHeader, EmptyState) lives in _shared/admin-panel/ui/. Semantic tones (success / warn / danger / neutral / info / accent / elevated) come from a single SSOT — every status badge across all 6 blocks resolves through it.

_shared/admin-panel/text
_shared/admin-panel/
├── AdminFeatureStubPage.tsx     # dispatcher (6 cases + fallback)
├── AdminFeatureCard.tsx         # placeholder for future segments
├── feature-blocks.ts            # registry (id, segment, icon, label, poweredBy)
├── ui/                          # shared chrome (BY-wave)
│   ├── tones.ts                 # semantic palette SSOT (success/warn/danger/…)
│   ├── block-header.tsx
│   ├── section-header.tsx
│   └── empty-state.tsx
└── blocks/<segment>/            # 1 dir per real block
    ├── types.ts
    ├── seed.ts                  # demo data (resets on browser reload)
    ├── <Segment>BlockView.tsx   # orchestrator, ≤200 LOC
    └── <…>.tsx                  # sub-components

Hard rules

  • NO Clerk. Auth = @convex-dev/auth.
  • shadcn-only UI. No raw <button> / <dialog> / native date+file inputs. Use ResponsiveDialog, DateField, FileUpload.
  • Copy-first. Never greenfield. Every artifact comes from a proven source project (see CLAUDE.md Source Map).
  • Stack lock: Next 16 + React 19 + Tailwind 4 + Convex self-hosted + TS strict.
  • ≤200 LOC per file. Enforced by audit-file-size across 1.4K+ files.
  • Audit chain green before push: audit-slice (44 slices), audit-templates (36 templates), audit-file-size.
  • No marketing chrome on workspace surfaces. Notion-clone template renders h-dvh full-bleed (BZ-wave) — workspace = the product, not a landing about it.
  • proxy.ts not middleware.ts — Next 16 convention.
CLAUDE.md (full rules)

Wave progression (recent)

  • BR — wildcard subdomain routing (8 demo URLs, host-based rewriter, zero fork)
  • BS → BX — 6 admin-panel blocks graduated from stub to real impl (users / audit-log / ai-config / analytics / webhooks / settings)
  • BY — polish wave: tones SSOT + shared chrome + a11y + dark-mode + ai-config tabs
  • BZ — notion-clone strip marketing chrome, full-bleed workspace
  • CA — this docs refresh
changelog.ts (full history)