# Global CMS Architecture — Overview

## What Is This?
This folder documents the complete step-by-step process for building a fully visual, database-driven CMS on top of **Next.js + Puck Editor + Neon (PostgreSQL)**. Every phase has been battle-tested on a live production website.

When implementing on a **new website**, give the agent one phase file at a time. Wait for that phase to be completed and tested before moving to the next.

---

## ⚠️ Global Rules for Every Phase

> [!CAUTION]
> **DO NOT modify the Neon database schema.** All required tables are already created in the shared Neon database. The agent must never run migrations, create new tables, or alter existing columns. Only update React components, API routes, and TypeScript logic.

> [!IMPORTANT]
> **Implement one phase at a time.** Do not jump ahead. Each phase depends on the previous one being stable and tested.

> [!IMPORTANT]
> **Always filter by `site_id`.** Every database query must include a `site_id` filter. We use a single shared Neon database across multiple websites. Never fetch data without this filter.

> [!IMPORTANT]
> **Enforce 1280px Max Width.** All pages, sections, and editor components MUST strictly enforce a maximum content width of 1280px (`max-w-7xl`). For text-heavy components, use narrower widths (like `max-w-5xl` or `max-w-4xl`) for readability. Outer `<section>` wrappers can use `w-full` for background colors, but the inner content MUST be constrained using `<div className="container max-w-7xl mx-auto px-4">`.

> [!IMPORTANT]
> **Verify Layout Consistency.** Always verify the website to ensure the 1280px (`max-w-7xl`) container width is correctly applied in each and every component and across every page. If anything is not matching this alignment or is not working as expected, you must immediately fix it to ensure a clean and consistent global design.

---

## Phase Index

| # | File | What It Builds | Key Tables Used |
|---|------|----------------|-----------------|
| 1 | [01-global-header-footer.md](./01-global-header-footer.md) | Wraps the Puck editor canvas with the real live Header and Footer. Logo, favicon, and footer text are editable from the CMS. | `homepage_content` |
| 2 | [02-multi-page-routing.md](./02-multi-page-routing.md) | Adds a Page Switcher dropdown and uses `?path=` URL params to load and save different page content. Includes critical cache bug prevention. | `homepage_content` |
| 3 | [03-custom-components.md](./03-custom-components.md) | Converts existing hardcoded React components (About Hero, Legal sections, etc.) into draggable Puck blocks using the "Wrap, Don't Rewrite" pattern. | — |
| 4 | [04-database-seeding.md](./04-database-seeding.md) | **Optional.** Exports the finished page designs from a source website and seeds them into the new website's database. Pages are pre-filled instantly. Only needed when migrating from an existing site. | `homepage_content` |
| 5 | [05-create-new-page.md](./05-create-new-page.md) | Adds a "➕ Create New Page" option in the page switcher dropdown. User sets the name, URL slug, menu placement (hardcoded to 3 locations), and optional parent nesting. Also adds a Page Settings modal (⚙️) for editing SEO fields post-creation. | `custom_pages`, `navigation_items` |
| 6 | [06-navigation-manager-ui.md](./06-navigation-manager-ui.md) | Builds the 🧭 Navigation Manager modal. Shows all menus in one place. Supports inline editing (✏️), visibility toggle, Ranktraction lock, and safe deletion. Menu sections are hardcoded to 3 locations: `top_header`, `category_bar`, `footer`. | `navigation_items` |
| 7 | [07-frontend-menu-rendering.md](./07-frontend-menu-rendering.md) | Updates the live website Header and Footer to fetch links dynamically from `navigation_items` instead of hardcoded arrays. Supports hover dropdowns and mobile tap behavior. | `navigation_items` |
| 8 | [08-advanced-navigation.md](./08-advanced-navigation.md) | Upgrades the Navigation Manager with Draft Mode (changes are not live until "Save Changes" is clicked), Drag-and-Drop reordering (⠿ handle), and ▲▼ button reordering. | `navigation_items` |
| 9 | [09-popup-modal.md](./09-popup-modal.md) | Creates a reusable `PopupModal` component and adds a Delete Page confirmation prompt with dynamic URL rendering and SEO warnings. | — |
| 10 | [10-rich-text-editor.md](./10-rich-text-editor.md) | Implements an advanced Tiptap WYSIWYG editor with Vercel Blob image uploads, custom React link modals, typography sync, and strict 1280px grid compliance. | — |

---

## 🔍 Mandatory: Component Audit & Fix (After Every Phase)

> [!IMPORTANT]
> **After completing each phase**, run a full audit of all components that were created or modified in that phase. Do NOT move to the next phase until the audit is complete and all bugs are fixed.

### Audit Process

1. **Batch size**: Audit **5 components at a time**.
2. **For each component**, check all 4 categories below.
3. **Fix all bugs immediately** — do not defer fixes to a later phase.
4. **Run `npx tsc --noEmit`** after each batch of fixes to verify zero TypeScript errors.

### 4 Audit Categories

| # | Category | What to Check |
|---|---|---|
| **1** | **Prop Mismatches** | Cross-reference every field in `lib/puck/config.tsx` with the component's props interface. Ensure every config field is accepted AND rendered. Check for props the component expects but config doesn't provide. |
| **2** | **Empty JSX / Silent Rendering Bugs** | Inspect every `<tag></tag>` in the JSX return. Look for empty `<span>`, `<div>`, `<td>`, `<h1>`–`<h6>`, `<Link>` tags inside `.map()` loops or conditionals. Every tag that should display dynamic content MUST have `{variable}` inside it. |
| **3** | **Icon Resolution** | If the component uses icons, verify it imports and calls `resolveIcon()` from `@/lib/puck/iconMap`. Never use `LucideIcons[iconName]` directly — it will silently fail for missing icons. |
| **4** | **Hardcoded Leftovers** | Search for any English text, placeholder strings, or hardcoded values that should be dynamic or in Japanese. Common culprits: "PROFILE", "PORTFOLIO", section headings, button labels. |

### anchorId Checklist

Every section-level component MUST:
- [ ] Have `anchorId?: string` in its TypeScript interface
- [ ] Accept `anchorId` in its props destructuring
- [ ] Apply `id={anchorId || undefined}` on the outermost `<section>` tag
- [ ] Include `scroll-mt-24` class on the same tag for sticky header offset

---


## Key Config: Menu Locations (Hardcoded in `editor-client.tsx`)

> [!IMPORTANT]
> Unlike what early drafts of this doc described, there is **NO separate `lib/navigation-config.ts` file** in the current implementation. The menu location configuration is hardcoded directly in `editor-client.tsx` using two inline constants: `LOCATION_CONFIG` and `LOCATION_ORDER`.

This is the actual config inside `editor-client.tsx`:

```typescript
// Inside NavManagerModal in editor-client.tsx
const LOCATION_CONFIG: Record<string, { label: string; emoji: string; color: string }> = {
  top_header:   { label: 'Top Header',       emoji: '📌', color: '#1e40af' },
  category_bar: { label: 'Blue Category Bar', emoji: '🔵', color: '#0e7490' },
  footer:       { label: 'Footer',            emoji: '📄', color: '#374151' },
};
const LOCATION_ORDER = ['top_header', 'category_bar', 'footer'];
```

The same three menu locations are also hardcoded in the `CreatePageModal` checkbox list:
```typescript
// Inside CreatePageModal in editor-client.tsx
const locations = [
  { menuLocation: 'top_header',   checked: showInHeader },
  { menuLocation: 'category_bar', checked: showInCategoryBar },
  { menuLocation: 'footer',       checked: showInFooter },
];
```

**When implementing on a new website:** If the new site does NOT have a Category Bar, simply remove the `category_bar` entry from both `LOCATION_CONFIG` and `LOCATION_ORDER` in `editor-client.tsx`, and remove the "Show in Blue Category Bar" checkbox from `CreatePageModal`. No separate config file is required.

---

## Key Database Tables (Reference)

| Table | Purpose |
|-------|---------|
| `homepage_content` | Stores the Puck JSON canvas data for ALL pages (homepage + custom pages). Keyed by `site_id` or `${site_id}-${slug}`. |
| `custom_pages` | Directory of custom pages — stores Title, Slug, `indexable`, `meta_title`, `meta_description`, `canonical_url`, `schema_json`. Does NOT store canvas data. |
| `navigation_items` | Controls all menu links across all locations. Uses `parent_id` for nesting and `sort_order` for ordering. |
| `categories` | Existing blog/content categories. Do NOT modify this table. |

---

## Key Files Reference (Actual Implementation)

| File | Role |
|------|------|
| `app/page_editor_admin/editor-client.tsx` | The entire CMS UI — all modals, nav manager, draft mode, drag-and-drop, and bulk-save live here |
| `app/page_editor_admin/page.tsx` | Server component — fetches initial data and renders the editor |
| `lib/navigation.ts` | Data layer — `getNavigationItems()`, `getAllNavigationItems()`, `buildMenuTree()`, CRUD |
| `lib/custom-pages.ts` | Data layer — `getCustomPage()`, `createCustomPage()`, etc. |
| `lib/homepage-content.ts` | Data layer — `getHomepageContent()`, save/publish logic |
| `lib/puck/config.tsx` | Puck component registry — all drag-and-drop blocks |
| `app/api/navigation-items/route.ts` | API — GET (flat list) and POST (create single item) |
| `app/api/navigation-items/bulk-save/route.ts` | API — POST bulk upsert/delete for Navigation Manager |
| `app/api/custom-pages/route.ts` | API — GET, POST, PUT, DELETE for custom pages |
| `app/[slug]/page.tsx` | Frontend catch-all route for custom pages |
| `app/sitemap.ts` | Auto-generates sitemap including all custom pages |
