Skip to content

feat: Ottablog page content type + fully functional DB-driven homepage integration + shared contract package + Zod-validated API pipeline + admin UI + seed endpoint#153

Draft
Copilot wants to merge 19 commits intomainfrom
copilot/ottablog-page-marketing-homepage
Draft

feat: Ottablog page content type + fully functional DB-driven homepage integration + shared contract package + Zod-validated API pipeline + admin UI + seed endpoint#153
Copilot wants to merge 19 commits intomainfrom
copilot/ottablog-page-marketing-homepage

Conversation

Copy link
Copy Markdown

Copilot AI commented Mar 30, 2026

Adds CMS-managed static/marketing pages via Ottablog's contentType: 'page', with a dedicated public API, homepage navbar integration, and Next.js rendering at /page/[slug]. Implements the full homepage DB integration architecture where the TanStack app is the single source of truth (D1 + OttaORM) and the Next.js app consumes all content via HTTP with Zod-validated payloads from a shared contract package. Includes a comprehensive admin UI for end-to-end homepage content management with fully configurable sections, display settings, SEO, CMS page management, and one-click seed defaults.

Data model (@ottabase/ottablog)

  • ContentType union gains 'page'; CONTENT_TYPES record gains metadata
  • New exposeToHomepage boolean column on posts (expose_to_homepage, default false) with composite index on (contentType, status, exposeToHomepage)
  • New BLOG_FEED_CONTENT_TYPES allowlist: ['blog', 'docs', 'news', 'announcement'] — used by all public feeds to exclude changelog and page
  • Post model updated: casts, writable fields, field metadata, defaults

Shared contract package (@ottabase/homepage-contract)

New workspace package providing the single source of truth for homepage API types and validation:

  • Zod schemasExposedPageSchema, FeaturePayloadSchema, ActionPayloadSchema, SectionPayloadSchema, DisplayPayloadSchema, HomepageDataSchema — all API payload shapes defined once
  • TypeScript typesExposedPage, HomepageFeaturePayload, HomepageActionPayload, HomepageSectionPayload, HomepageDisplayPayload, HomepageDataPayload — inferred from Zod schemas (zero drift)
  • parseHomepageData() — safe parser with structured error logging
  • Both the Next.js app and TanStack worker import types/schemas from @ottabase/homepage-contract — no duplicate type definitions
  • 6 schema validation tests

Homepage DB models (TanStack app)

Four new OttaORM models for DB-driven homepage content, registered in schemas-helper.ts (for autoInit) and db-utils.ts (for CRUD API):

  • HomepageSection — stores section content per slot (navbar, hero, features, cta, footer, about) with title, subtitle, body, githubUrl, sortOrder, plus enabled (boolean toggle), icon (lucide icon name), cssClasses (custom Tailwind CSS), metadata (extensible JSON)
  • HomepageFeature — feature items linked to a section via sectionId FK (cascade delete), with icon, imageUrl, and href for rich feature displays
  • HomepageAction — action buttons linked to a section (label, href, variant, icon, external)
  • HomepageDisplaySettings — single-row settings storing variantBySlotJson (matching HomepageConfig shape), themePreset, customCss (injectable CSS), seoTitle, and seoDescription

Worker API

  • Blog list, RSS, sitemap now filter via $in: BLOG_FEED_CONTENT_TYPES instead of $ne: 'changelog'
  • handleBlogPostBySlug / unlock return 404 for page content type
  • GET /api/blog/pages/by-slug/:slug — published page by slug
  • GET /api/blog/pages/exposed{ exposedPages: [{ slug, title }] } for navbar links; never hard-fails
  • GET /api/homepage/data — public endpoint returning { sections, display, exposedPages }. Sections include all configurable fields (enabled, icon, cssClasses, metadata) plus child features (with icon, imageUrl, href) and actions (with icon). Display settings include variantBySlot, themePreset, customCss, seoTitle, seoDescription. All queries wrapped in try/catch with error logging — never hard-fails. Response typed via @ottabase/homepage-contract.
  • POST /api/homepage/seed — idempotent endpoint creating 6 demo sections (navbar, hero, features, cta, footer, about) with features, actions, and display settings. Integrated into bootstrap handleSeed for fresh deploys.
// Homepage data API response shape
{
  sections: [{ id, slot, title, subtitle, body, githubUrl, icon, enabled, cssClasses, metadata, sortOrder,
    features: [{ title, description, icon, imageUrl, href }],
    actions: [{ label, href, variant, icon, external }] }],
  display: { variantBySlot: { hero: 'centered', features: 'grid' }, themePreset: 'neo', fallbackThemePresetId: null,
    customCss: null, seoTitle: null, seoDescription: null },
  exposedPages: [{ slug: "pricing", title: "Pricing" }]
}

Admin blog editor

  • exposeToHomepage checkbox, visible only when contentType === 'page'
  • Auto-clears on content type change; wired into dirty state + save payload

Admin homepage management UI (TanStack app)

Full admin interface at /admin/homepage with shadcn Tabs navigation (Sections / Display / Pages) for end-to-end homepage content management via createModelHooks:

  • homepageHooks.ts — pre-configured createModelHooks for all 4 homepage entities with typed row interfaces including all new fields
  • homepage-constants.ts — shared DRY constants: SLOT_NAMES, SLOT_LABELS, SLOT_DESCRIPTIONS, SLOT_ICONS, SLOT_CONFIG, ACTION_VARIANTS, THEME_PRESETS (8 presets), ICON_SUGGESTIONS, getDefaultVariantBySlot()
  • HomepageAdminNav — shadcn Tabs navigation with lucide icons (Sections / Display / Pages)
  • Sections page (/admin/homepage) — enable/disable eye toggles per section, icon badges, sort up/down controls, collapsible feature/action mini-editors with icon support, slot-based quick-add cards with descriptions, delete confirmation dialogs, active section count badge, "Seed Defaults" button (IconDatabaseImport) for one-click D1 population with sample Ottabase homepage data (idempotent, disabled when sections exist, uses queryClient.invalidateQueries for efficient refresh, feedback badges for success/exists/error states)
  • Section editor (/admin/homepage/$sectionId/edit) — organized Content card (title, subtitle, body) + Display Options card (icon with suggestions, GitHub URL, CSS classes, metadata JSON editor); nested FeatureEditor with icon/imageUrl/href fields and ActionEditor with icon field; move up/down reordering for features and actions; auto-saves enabled toggle on change
  • Display settings (/admin/homepage/display) — theme preset card selector (8 presets with descriptions), consolidated layout variant picker for all 6 slots (radio cards with check badges), SEO title/description fields with character recommendations, custom CSS editor with monospace font, reset defaults button
  • Pages tab (/admin/homepage/pages) — lists CMS pages (contentType = 'page') with expose-to-homepage toggle switch, status badges, direct blog editor links, info card explaining how pages work
  • 4 lazy-loaded routes registered in router.tsx (admin-gated via renderAdminRoute); "Homepage" card added to admin dashboard Content category

Next.js homepage app — full runtime integration

  • Home page moved to app/(site)/page.tsx route group to avoid filesystem clash with /page/[slug]
  • Zod-validated data pipelinelib/get-homepage-data.ts imports HomepageDataSchema and parseHomepageData() from @ottabase/homepage-contract; getHomepageData() fetches + validates the API payload with structured error logging
  • (site)/page.tsx consumes API data — uses useHomepageData() context instead of hardcoded HERO_DATA/FEATURES_DATA/CTA_DATA constants; falls back to static defaults when API data is unavailable
  • HomepageDataProvider + useHomepageData() — React context bridging server-fetched data to client page components; layout passes full payload, page components consume per-slot
  • /page/[slug] renders CMS pages via @ottabase/ottarenderer (new dependency)
  • mergeNavLinks() deduplicates and appends exposed pages into the navbar
  • Root layout fetches full homepage data from GET /api/homepage/data via RSC with ISR (revalidate: 60)
  • SEO from DBlayout.tsx injects seoTitle/seoDescription from display settings into page metadata; custom CSS injected via <style> tag
  • Provider theming integrationProviders accepts initialHomepageConfig (variantBySlot) and themePresetId from API; theme precedence: localStorage > DB > SSR brand config
  • Variant config from DBHomepageConfigProvider accepts initialVariantBySlot from API; merge priority: localStorage > API > defaults
  • LayoutShell accepts the full HomepageDataPayload (imported from @ottabase/homepage-contract) and maps DB sections to slot data contracts via buildSlotDataFromSections() — filters disabled sections, passes icon data through; hero, features, cta, about, navbar, footer each map to their respective type contracts
  • Feature type contracts extendedFeatureItemData gains icon, imageUrl, href; HeroAction/CTAAction gain icon
  • DB navbar/footer data overrides defaults; static page data in (site)/page.tsx remains as fallback
  • .env.example updated with NEXT_PUBLIC_API_URL enabled by default
// Navbar merge (layout-shell.tsx)
const navbarLinks = mergeNavLinks(BASE_NAVBAR_LINKS, exposedPages);
// → [{ href: '/', label: 'Home' }, ..., { href: '/page/pricing', label: 'Pricing' }]

Tests

  • 25 tests covering homepage functionality: CONTENT_TYPES includes page, BLOG_FEED_CONTENT_TYPES excludes changelog+page, exposeToHomepage model metadata, mergeNavLinks helper (4 cases), homepage API types and fallback behavior (4 cases including new configurable fields test), HomepageSectionPayload full field coverage test, Zod validation tests (4 cases: valid payloads, missing sections, invalid display, empty API), contract package schema tests (6 cases)
  • All 90 homepage tests pass; all 129 ottablog tests pass; all 6 contract tests pass

Copilot AI changed the title [WIP] Add Ottablog pages support for marketing homepage feat: Ottablog page content type + marketing homepage integration Mar 30, 2026
Copilot AI requested a review from thinkdj March 30, 2026 18:13
@thinkdj
Copy link
Copy Markdown
Owner

thinkdj commented Mar 30, 2026

@copilot

Homepage DB integration (TanStack source of truth → Next.js consumer)image.png

Architecture
flowchart LR
subgraph tanstack [TanStack Worker D1]
models[Homepage models OttaORM]
admin[Admin UI createModelHooks]
publicGET["GET /api/homepage/data"]
ottaorm["/api/ottaorm/* AdminOnly"]
end
subgraph nextjs [Next.js Homepage]
rsc["RSC fetch + ISR"]
providers["Providers + HomepageConfigProvider"]
slots["SlotRenderer"]
end
admin --> ottaorm
admin --> models
ottaorm --> models
publicGET --> models
rsc -->|"NEXT_PUBLIC_API_URL"| publicGET
rsc --> providers
providers --> slots
Single database, single deployment boundary for writes: D1 + OttaORM live only in apps/ottabase-template-app-tanstack. The Next.js app has no D1 binding; it loads everything via HTTP (same pattern already described in HOMEPAGE_DATA_ONE_INTEGRATION.MD and aligned with public changelog reads in worker/routes/changelog.ts).

Why not duplicate D1 on Next.js: Avoids split-brain content; matches repo guidance and the existing integration doc.

  1. Data model (TanStack app)
    A. Section content (normalized) — Follow the structure already sketched in HOMEPAGE_DATA_ONE_INTEGRATION.MD (sections + features + actions), with one extension:

Extend slot beyond hero|features|cta to cover all SLOT_NAMES (navbar, hero, features, cta, footer, about) so every SlotRenderer slot can be driven from DB.

Use string titles/subtitles in DB; map to HeroData etc. on the Next.js side (replace current JSX title in app/page.tsx with string-only or a small optional titleHtml later if needed).

B. Display settings (full UI state) — New table/model, e.g. homepage_display_settings (single row id = 'default'):

variantBySlotJson — JSON object matching HomepageConfig (Record<SlotName, string>), validated against known variant IDs in SLOT_REGISTRY.

themePresetId — string (e.g. neo, verdant) aligned with getThemeByName / ThemePresetSwitcher.

This replaces localStorage as the source of truth when the API returns data; keep localStorage as optional client override only if you want (recommend: SSR from API first, then optional localStorage sync for dev).

  1. OttaORM wiring (TanStack)
    Step

Location

Drizzle tables + BaseModel classes

New files under apps/ottabase-template-app-tanstack/ottabase/models/ (mirror ChangelogEntry pattern)

Export tables

ottabase/db/schema.ts

Auto-migrations

ottabase/db/schemas-helper.ts appTables

Register models

worker/lib/db-utils.ts registerModels([...])

RLS policies

registerPolicy for each entity: AdminOnly (or PermissionBased + explicit permissions) so only authenticated admins can use /api/ottaorm/{entity} for writes. Public reads do not use secure CRUD (see below).

Note: PublicReadOnly blocks all writes on OttaORM, so it is not suitable if admins edit via /api/ottaorm. Use AdminOnly + dedicated public handler for reads.

  1. API surface
    GET /api/homepage/data (new) — Public aggregated payload (sections + nested features/actions + displaySettings). Implement like changelog: register D1, call BaseModel/paginate directly in a new handler (e.g. worker/routes/homepage.ts), then wire router.ts handleGetRoutes early (same placement as /api/changelog/entries).

/api/ottaorm/* — Auto CRUD for homepage_sections, homepage_features, homepage_actions, homepage_display_settings for TanStack admin via createModelHooks (same pattern as AdminChangelogListPage).

Seed — Optional POST (protected by existing migration/bootstrap secret pattern) or one-time script to insert current static defaults from app/page.tsx + default variantBySlot + themePresetId matching config/brand.config.ts.

  1. TanStack admin UI
    New route under /admin/... (e.g. /admin/homepage): list/edit sections; nested editor for features/actions; single form for display settings (variant map + theme preset).

Use createModelHooks for each entity; reuse @ottabase/ui-shadcn components.

Register routes in src/router.tsx and document in README.

  1. Next.js homepage app
    Add lib/get-homepage-data.ts — fetch(${NEXT_PUBLIC_API_URL}/api/homepage/data) with next: { revalidate: ... } (as in integration doc).

Env: document NEXT_PUBLIC_API_URL (e.g. http://localhost:3004 in dev).

Convert app/page.tsx to a Server Component where possible: fetch payload, map API rows to SlotRenderer props (HeroData uses string title / actions[].label).

Layout / theme: extend generateBrandConfig to accept optional themePresetId from fetched payload (fallback to themePreset). Pass initialBrandConfig into Providers so SSR matches the DB preset.

Variants: pass initialConfig from API into HomepageConfigProvider (extend provider to accept server HomepageConfig default) so slot variants match TanStack without requiring localStorage on first paint.

Prefer SlotRendererStatic for RSC where context is unavailable, or lift a small client wrapper that receives initialConfig + serverData only once.

  1. Tests and docs
    Update README.md (remove “no DB” claim; document API dependency + env).

Add/update TanStack tests for the new handler + models; extend Next.js tests for payload mapping if feasible.

Run pnpm test --filter=... for touched packages/apps per AGENTS.

  1. Risks / decisions
    CORS: Server-side fetch from Next to TanStack does not need browser CORS; ensure production URL for NEXT_PUBLIC_API_URL is correct.

Icon keys in actions: Store icon slugs in DB; map to Tabler/Lucide in a small client component (current static data uses inline React nodes).

RLS: Keep admin CRUD on /api/ottaorm with AdminOnly; public marketing site uses GET /api/homepage/data only (no secrets in response).


Above is from last implementation. I want you to be the best judge as you know this complete repo and implement these features into the monorepo in the best architecture.
Keep functionality, but for everything else you can do the best decisions for architecture etc as per this repo standards

Copy link
Copy Markdown
Author

Copilot AI commented Mar 30, 2026

@copilot

...

Implemented the full homepage DB integration architecture in commits 4db1801 and 67d57e2:

Homepage OttaORM modelsHomepageSection, HomepageFeature, HomepageAction, HomepageDisplaySettings — all registered in schemas-helper.ts (for autoInit) and db-utils.ts (for CRUD API). HomepageSection.slot covers all SLOT_NAMES (navbar, hero, features, cta, footer, about).

GET /api/homepage/data — public endpoint returning { sections, display, exposedPages }. Sections include child features and actions (batch-loaded). Display settings store variantBySlotJson (matching HomepageConfig) and themePreset. All queries wrapped in try/catch with console.error logging — never hard-fails.

Next.js consumer — root layout fetches from the API via RSC (revalidate: 60). LayoutShell receives the full payload and maps DB sections to slot data contracts via buildSlotDataFromSections() (hero→title/subtitle/actions, features→title/features, cta→title/description/actions, navbar→title/githubUrl, footer→siteName/tagline). Exposed pages merged into navbar links.

The static data in (site)/page.tsx remains as the fallback — DB sections override layout-level slots (navbar, footer) and can progressively replace page-level section data.

Copilot AI changed the title feat: Ottablog page content type + marketing homepage integration feat: Ottablog page content type + marketing homepage integration + homepage DB models Mar 30, 2026
@thinkdj
Copy link
Copy Markdown
Owner

thinkdj commented Mar 30, 2026

@copilot enhance admin ui in tanstack for managing the dynamic homepages and content end to end. Best UX and dx, stick with repo standards, dry.

Copy link
Copy Markdown
Author

Copilot AI commented Mar 30, 2026

@copilot enhance admin ui in tanstack for managing the dynamic homepages and content end to end. Best UX and dx, stick with repo standards, dry.

Implemented in a85fd4f and eeec6de. Three admin pages at /admin/homepage:

Sections — lists all slots with inline feature/action mini-editors; quick-add buttons for missing slots; section cards show child counts, body preview, and link to full editor.

Section Editor (/admin/homepage/$sectionId/edit) — full form with title, subtitle, body, githubUrl fields; nested FeatureEditor and ActionEditor components with auto-save on blur and useEffect+useRef-based saves for select/switch changes. Delete confirmations via AlertDialog.

Display Settings (/admin/homepage/display) — variant picker per slot (radio cards matching SLOT_REGISTRY with check badge), theme preset input, reset defaults button. Single-row upsert.

All wired via createModelHooks in homepageHooks.ts (4 entities), shared constants extracted to homepage-constants.ts (SLOT_NAMES, SLOT_LABELS, SLOT_CONFIG, ACTION_VARIANTS). Admin dashboard has a new "Homepage" card under Content. Routes lazy-loaded and admin-gated via renderAdminRoute.

Copilot AI changed the title feat: Ottablog page content type + marketing homepage integration + homepage DB models feat: Ottablog page content type + marketing homepage integration + homepage DB models + admin UI Mar 30, 2026
@thinkdj
Copy link
Copy Markdown
Owner

thinkdj commented Mar 30, 2026

@copilot make the system as flexible and dynamic as possible. Configurable everything for homepage and elements and pages . Best UX best dx best in class framework for this . Enhance anything you feel is required. Rewriting is also fine if required. No backwards compatibility required

@thinkdj
Copy link
Copy Markdown
Owner

thinkdj commented Mar 30, 2026

@copilot make the system as flexible and dynamic as possible. Configurable everything for homepage and elements and pages . Best UX best dx best in class framework for this . Enhance anything you feel is required. Rewriting is also fine if required. No backwards compatibility required

…to sections, icon/imageUrl/href to features, icon to actions, customCss/seo to display settings; rewrite admin UI with Tabs nav, enable/disable toggles, sort controls, collapsible children, new Pages tab

Agent-Logs-Url: https://github.com/thinkdj/ottabase/sessions/ae722b66-1678-4b6e-9ba2-78d05e83ba45

Co-authored-by: thinkdj <688055+thinkdj@users.noreply.github.com>
Copy link
Copy Markdown
Author

Copilot AI commented Mar 30, 2026

@copilot make the system as flexible and dynamic as possible. Configurable everything for homepage and elements and pages . Best UX best dx best in class framework for this . Enhance ...

Implemented in 0cb155f through 00a4fc6. The homepage system is now fully configurable end-to-end:

Enhanced data models — sections gain enabled (toggle on/off without deleting), icon (lucide icon name), cssClasses (custom Tailwind), metadata (extensible JSON). Features gain icon, imageUrl, href. Actions gain icon. Display settings gain customCss, seoTitle, seoDescription.

Rewritten admin UI with 3 tabs:

  • Sections — enable/disable toggles, icon badges, sort up/down controls, collapsible feature/action editors, slot-based quick-add with descriptions
  • Display — theme preset card selector (8 presets), consolidated variant picker for all 6 slots, SEO title/description fields, custom CSS editor with code font
  • Pages (new) — CMS pages list with expose-to-homepage toggle, direct editor links, info card

Section Editor — organized Content + Display Options cards, icon/cssClasses/metadata fields, feature editors with icon/imageUrl/href, action editors with icon, move up/down reordering for features and actions.

All 86 homepage tests + 129 ottablog tests pass. 0 CodeQL alerts.

Copilot AI changed the title feat: Ottablog page content type + marketing homepage integration + homepage DB models + admin UI feat: Ottablog page content type + marketing homepage integration + fully configurable homepage DB models + admin UI Mar 30, 2026
@thinkdj
Copy link
Copy Markdown
Owner

thinkdj commented Mar 31, 2026

@copilot I did a review of my local branch and this one. This one wins architecturally, which is great. But we need to make it fully functional inc. nuances.

Summary: Branch neopc-nextjs-homepage-integrated fully implements a database-backed, versioned homepage integration (Cloudflare D1 + OttaORM) with shared contract package and admin UX, while copilot/ottablog-page-marketing-homepage mostly adds planning docs but not the actual integration code.

Key differences (neopc vs copilot) – implementation table

Area neopc-nextjs-homepage-integrated copilot/ottablog-page-marketing-homepage
Data source Fetches homepage payload from worker GET /api/homepage/data (TanStack app) with Zod validation via new package @ottabase/homepage-contract (lib/get-homepage-data.ts, app/(site)/page.tsx, app/layout.tsx) No runtime data fetch; only plan docs
Contract pkg New workspace package packages/homepage-contract (schemas, builder, parser, slot registry, tests) Not present
Next.js runtime Server component homepage uses fetched payload; client mapper home-page-client.tsx; layout merges navbar/footer and slot variants from API; SSR fallback data map Still static app/page.tsx with hardcoded HERO/FEATURES/CTA constants
Admin / CMS TanStack app: new admin screen /admin/homepage with tabs (display/theme/variants, navbar/footer, hero, features, CTA, about), CRUD hooks, seed button; RLS policies Absent
DB models TanStack app: Drizzle+OttaORM models for homepage_sections/features/actions/display_settings; registered in schema/helpers and db-utils; policies added Absent
API routes Worker: GET /api/homepage/data, POST /api/homepage/seed, blog page fetch GET /api/blog/pages/by-slug/:slug; blog list/sitemap filters exclude page type; exposedPages support Absent
Marketing pages Next.js routes /[slug] and /page/[slug] render Ottablog “page” content via fetchMarketingPageBySlug; navbar merger for exposed pages; tests added Absent
Theming Brand config generated from API themePresetId; Providers accept initialHomepageConfig/themePresetId; layout uses API slots for navbar/footer Still config-first; no API-driven preset/variants
Tests Added vitest tests for merge helpers and contract package; suite count +2 None added
Docs README updated for data fetch/setup; HOMEPAGE_DATA_ONE_INTEGRATION.MD and HOMEPAGE_vNEXT.MD already existed in copilot branch; pnpm-lock updated for new deps Only the plan docs (same two MD files)

What’s present in neopc-nextjs-homepage-integrated but missing in copilot/ottablog-page-marketing-homepage

  • Runtime integration: server-fetch pipeline (lib/get-homepage-data.ts), Zod-validated payload, SSR layout wiring, client mapper, fallback maps, and removal of hardcoded app/page.tsx.
  • New routes: app/(site)/page.tsx, marketing page renderers /[slug] and /page/[slug].
  • Admin UX in TanStack app with CRUD tabs for navbar/footer/hero/cta/features/about, variant/theme controls, seed button; model hooks/utilities.
  • DB layer: homepage_* Drizzle schemas and OttaORM models, display settings, policies, schema exports/registration.
  • Worker endpoints: GET /api/homepage/data, POST /api/homepage/seed, GET /api/blog/pages/by-slug/:slug, blog filters for exposed pages.
  • Package @ottabase/homepage-contract (schemas, builder/parser, slot registry, tests) and dependency wiring.
  • Theme + variant bootstrapping (Providers/layout adjustments) and navbar exposed-pages merger.
  • Tests for merge helpers; marketing content renderer component.
  • Updated docs and .env guidance; pnpm-lock dependency updates.

Feature comparison & which “wins”

  • Data + API: neopc wins (actual DB-backed payload; copilot only a plan).
  • Admin/editing: neopc wins (full admin UI + CRUD + seed; copilot none).
  • Theming/variants persistence: neopc wins (themePresetId + variantBySlot from DB); copilot static.
  • Marketing pages integration: neopc wins (Ottablog “page” exposure + routes + navbar merge).
  • Contract/typing: neopc wins (shared package, validation, tests).
  • Performance/SSR: neopc adds cached fetch, ISR hints; copilot unchanged static render.
  • Documentation: both have plan docs; neopc also updates README with setup.

Feature Judgment:

  • neopc-nextjs-homepage-integrated is clearly superior: it delivers a typed, versioned contract, end-to-end data flow (D1 → worker API → Next.js SSR/CSR), admin surface, and marketing-page exposure. Most importantly -- It replaces hardcoded content with a single source of truth, supports theming/variants from DB, and includes validation and tests. Copilot branch is just the design docs without implementation, it needs to work on that (But has good architecture)

Copy link
Copy Markdown
Author

Copilot AI commented Mar 31, 2026

@copilot I did a review of my local branch and this one. This one wins architecturally, which is great. But we need to make it fully functional inc. nuances.

Summary: Branch neo...

Implemented full runtime integration in f1d3afc and 0aa0310, addressing all the gaps identified in the neopc comparison:

Runtime data pipeline(site)/page.tsx no longer uses hardcoded HERO_DATA/FEATURES_DATA/CTA_DATA. It consumes DB sections via useHomepageData() context (bridged from server-fetched layout data), with the original content preserved as graceful fallbacks.

Zod validation — New lib/get-homepage-data.ts with HomepageDataSchema validates all API payloads. layout.tsx uses getHomepageData() instead of raw fetchHomepageData().

Homepage seedPOST /api/homepage/seed creates 6 demo sections (navbar/hero/features/cta/about/footer) + 6 features + hero/CTA actions + display settings. Idempotent (skips if sections exist). Integrated into bootstrap handleSeed so fresh deploys get working homepage content.

Provider integrationProviders now accepts initialHomepageConfig (variantBySlot) and themePresetId from the API. Theme precedence: localStorage > DB themePresetId > SSR brand config.

Variant config from DBHomepageConfigProvider accepts initialVariantBySlot from API. Merge priority: localStorage > API > defaults.

Type contractsFeatureItemData gains icon, imageUrl, href. HeroAction/CTAAction gain icon. All slot types now support DB-driven icon names.

SEO + Custom CSSlayout.tsx injects seoTitle/seoDescription from display settings, plus custom CSS via <style> tag.

Environment.env.example now has NEXT_PUBLIC_API_URL enabled by default.

90 homepage tests + 129 ottablog tests pass. 0 CodeQL alerts.

Copilot AI changed the title feat: Ottablog page content type + marketing homepage integration + fully configurable homepage DB models + admin UI feat: Ottablog page content type + fully functional DB-driven homepage integration + Zod-validated API pipeline + admin UI + seed endpoint Mar 31, 2026
@thinkdj
Copy link
Copy Markdown
Owner

thinkdj commented Mar 31, 2026

@copilot Check if these are valid, implement if so:

  • Shared Contract Strictness: currently manages a lot of this logic inside local Zod schemas. You might want to unify these (shared / exportable.. whatever works best) so the Next.js app natively consumes the Monorepo's shared contract package, and not maintain duplicate types
  • Seed Defaults Tab/Button: We need a convenient "Seed Defaults" button (IconDatabaseImport) directly on the main admin screen to instantly populate the D1 database. Runnable once, fill it with initial sample data about ottabase nextjs homepage

Copy link
Copy Markdown
Author

Copilot AI commented Mar 31, 2026

@copilot Check if these are valid, implement if so:

  • Shared Contract Strictness: currently manages a lot of this logic inside local Zod schemas. You might want to unify these (share...

Both suggestions implemented in b6f6c5b and bf5b208:

Shared contract package — Created @ottabase/homepage-contract (packages/homepage-contract) with Zod schemas as the single source of truth. TypeScript types are inferred from schemas (z.infer<>) — zero drift. Both the Next.js app (lib/api.ts, lib/get-homepage-data.ts) and the TanStack worker (worker/routes/homepage.ts) now import types from the shared package instead of maintaining duplicate definitions. 6 contract schema tests pass.

Seed Defaults button — Added to the admin homepage sections page header with IconDatabaseImport. Calls POST /api/homepage/seed to populate D1 with sample data (6 sections, features, actions, display settings). Disabled when sections already exist. Uses queryClient.invalidateQueries for efficient data refresh. Shows success/exists/error feedback badges.

All 90 homepage + 129 ottablog + 6 contract tests pass. 0 CodeQL alerts.

Copilot AI changed the title feat: Ottablog page content type + fully functional DB-driven homepage integration + Zod-validated API pipeline + admin UI + seed endpoint feat: Ottablog page content type + fully functional DB-driven homepage integration + shared contract package + Zod-validated API pipeline + admin UI + seed endpoint Mar 31, 2026
thinkdj added 4 commits March 31, 2026 13:44
Introduce Row-Level Security configs for homepage models (sections, features, actions, display settings) and register them in DB init so homepage models are scoped and auditable. Provide defaults for optional EditorJS fields (time, version) when rendering Blocks to satisfy the expected data shape. Export ExposedPage type from the homepage contract. Simplify blog route queries to use BLOG_FEED_CONTENT_TYPES directly for where.contentType (remove the {$in: ...} wrapper) to match the expected query shape.
Introduce a single-page AdminHomepageBuilderPage to consolidate homepage editing (sections, features, actions, display settings) and remove legacy per-page admin UIs (AdminHomepageDisplayPage, AdminHomepagePagesPage, AdminHomepageSectionEditorPage, AdminHomepageSectionsPage, HomepageAdminNav).

Also tighten RLS for homepage models: homepage_sections, homepage_features, homepage_actions and homepage_display_settings are now configured with RLSPolicies.AdminOnly() and their contextFields cleared. Router/index and worker route/db utilities were updated to wire the new builder and related APIs.
Introduce a new flexible Marketing Pages system and wire it into frontend/admin workflows.

Key changes:
- Add DB schemas, models and RLS policies for pages, page_sections, page_features, and page_actions (drizzle/ottaorm) to support block-based and content pages.
- Add admin-side hooks and pages (pageHooks, admin pages list, page builder) and register a new "Marketing Pages" entry in the admin index.
- Add a detailed PAGES_README documenting the new pages system, API routes and usage.
- Add Next.js frontend support: dynamic route for /{slug} (app/[slug]/page.tsx) and a client renderer (MarketingPageContent) that maps page sections to slot components.
- Extend lib/api to fetch pages (fetchPageByPageSlug, fetchNavPages) and re-export additional contract types.
- Update layout/brand-server to read themePreset from homepage data and pass it into generateBrandConfig for SSR theme resolution.
- Update DB schema helper to include the new page tables (kept legacy homepage tables for migration).
- Add drag-and-drop deps to the TanStack app package.json (dnd-kit) for builder UX.

These changes implement an additive pages system (homepage remains compatible) and provide API/DB/admin/frontend support for creating and rendering multi-page marketing content.
Add comprehensive marketing pages design docs: a full feature specification and an optimized version (docs/MARKETING_PAGES_FEATURE_SPEC.md, docs/MARKETING_PAGES_FEATURE_SPEC_OPTIMIZED.md). The spec covers architecture, DB schema (pages, page_sections, page_features, page_actions), OttaORM models and hooks, public/admin APIs, contract package (Zod + TS types), admin drag-and-drop builder, Next.js frontend rendering/SlotRenderer, variant components, routing, and implementation/checklist details.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants