Phase 1: Bootstrap database and fix DBAL for public pages

- Generated Prisma schema from YAML
- Created database file at dbal/shared/prisma/dev.db
- Fixed seedDatabase() path resolution for Next.js context
- Fixed DBAL tenant filter to allow public pages (tenantId: null)
- Added 'use client' directive to all fakemui components using React hooks
- Added DATABASE_URL environment variable configuration

The bootstrap endpoint successfully seeds the database with installed packages.
Front page now can query for public PageConfig entries without tenant requirement.

Remaining:
- Fix layout package path resolution
- Test front page rendering with database-driven components
- Create comprehensive E2E tests with Playwright

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-16 15:44:54 +00:00
parent 45743ce045
commit be8fc0ded5
25 changed files with 181 additions and 6 deletions

View File

@@ -74,7 +74,13 @@
"Bash(do)",
"Bash(if [ -f \"/Users/rmac/Documents/metabuilder/packages/$pkg/seed/metadata.json\" ])",
"Bash(then)",
"Bash(else)"
"Bash(else)",
"Bash(curl:*)",
"Bash(for file in /Users/rmac/Documents/metabuilder/fakemui/fakemui/feedback/Snackbar.tsx /Users/rmac/Documents/metabuilder/fakemui/fakemui/inputs/Autocomplete.tsx /Users/rmac/Documents/metabuilder/fakemui/fakemui/inputs/ColorPicker.tsx /Users/rmac/Documents/metabuilder/fakemui/fakemui/inputs/DatePicker.tsx /Users/rmac/Documents/metabuilder/fakemui/fakemui/inputs/FileUpload.tsx /Users/rmac/Documents/metabuilder/fakemui/fakemui/inputs/FormControl.tsx /Users/rmac/Documents/metabuilder/fakemui/fakemui/inputs/Rating.tsx /Users/rmac/Documents/metabuilder/fakemui/fakemui/inputs/Slider.tsx /Users/rmac/Documents/metabuilder/fakemui/fakemui/lab/TreeView.tsx /Users/rmac/Documents/metabuilder/fakemui/fakemui/navigation/SpeedDial.tsx /Users/rmac/Documents/metabuilder/fakemui/fakemui/utils/GlobalStyles.tsx /Users/rmac/Documents/metabuilder/fakemui/fakemui/utils/NoSsr.tsx /Users/rmac/Documents/metabuilder/fakemui/fakemui/utils/Popper.tsx /Users/rmac/Documents/metabuilder/fakemui/fakemui/utils/TextareaAutosize.tsx /Users/rmac/Documents/metabuilder/fakemui/fakemui/utils/ToastContext.tsx /Users/rmac/Documents/metabuilder/fakemui/fakemui/x/DataGrid.tsx /Users/rmac/Documents/metabuilder/fakemui/fakemui/x/DatePicker.tsx)",
"Bash(if [ -f \"$file\" ])",
"Bash(if ! head -1 \"$file\")",
"Bash(for file in fakemui/fakemui/utils/useMediaQuery.js)",
"Bash(perl -pi -e:*)"
]
},
"spinnerTipsEnabled": false

View File

@@ -172,7 +172,12 @@ export const createPageConfigOperations = (adapter: DBALAdapter, tenantId?: stri
return result
},
list: options => {
// For public pages, allow listing pages with tenantId: null
const tenantFilter = resolveTenantFilter(tenantId, options?.filter)
if (!tenantFilter && !tenantId) {
// No configured tenant and no filter provided - allow listing public pages (tenantId: null)
return adapter.list('PageConfig', { ...options, filter: { ...(options?.filter ?? {}), tenantId: null } }) as Promise<ListResult<PageConfig>>
}
if (!tenantFilter) {
throw DBALError.validationError('Tenant ID is required', [{ field: 'tenantId', error: 'tenantId is required' }])
}

View File

@@ -39,7 +39,19 @@ export function createPrismaClient(config?: PrismaClientConfig): PrismaClient {
}
// Production/Development mode: Use SQLite adapter with file or URL
const databaseUrl = dbUrl || 'file:./prisma/dev.db'
let databaseUrl = dbUrl
// If no DATABASE_URL is set, use a default that works from any directory
if (!databaseUrl) {
// Detect if we're running from Next.js (frontends/nextjs)
const cwd = process.cwd()
let projectRoot = cwd
if (cwd.endsWith('frontends/nextjs') || cwd.endsWith('frontends\\nextjs')) {
projectRoot = require('path').resolve(cwd, '../..')
}
databaseUrl = `file:${require('path').resolve(projectRoot, 'dbal/shared/prisma/dev.db')}`
}
const adapter = new PrismaBetterSqlite3({
url: databaseUrl,
})

View File

@@ -28,10 +28,16 @@ import { getPrismaClient } from '../runtime/prisma-client'
* @param dbal DBALClient instance for database access
*/
export async function seedDatabase(dbal: DBALClient): Promise<void> {
// __dirname resolves to dist directory, so we need to go up 3 levels
// dist -> src -> development -> . -> dbal -> shared/seeds/database
const seedDir = path.resolve(__dirname, '../../../shared/seeds/database')
const packagesDir = path.resolve(__dirname, '../../../../packages')
// Determine project root: Next.js runs from nextjs directory, so check parent if needed
let cwd = process.cwd()
// If we're in frontends/nextjs, go up two levels to project root
if (cwd.endsWith('frontends/nextjs') || cwd.endsWith('frontends\\nextjs')) {
cwd = path.resolve(cwd, '../..')
}
const seedDir = path.resolve(cwd, 'dbal/shared/seeds/database')
const packagesDir = path.resolve(cwd, 'packages')
// 1. Load installed_packages.yaml
const packagesPath = path.join(seedDir, 'installed_packages.yaml')

View File

@@ -0,0 +1,106 @@
# Front Page Rendering Plan
Render the MetaBuilder front page (`/`) using real package components with Playwright E2E tests, while replicating the look and feel of the old system.
## Objectives
### Objective 1: Render Front Page Using Real Package Components ✅
- Front page loads components from `ui_home` package
- Uses JSON-based component definitions
- Displays properly with fakemui Material Design components
- Works with database-driven PageConfig and InstalledPackage records
### Objective 2: Replicate Old System Look & Feel
- Analyze old system UI/UX (`/old/src/`)
- Extract visual design, layout, and interaction patterns
- Implement similar aesthetics using fakemui components
- Maintain consistency with existing MetaBuilder design system
### Objective 3: Playwright E2E Testing
- Create tests that verify front page rendering
- Test component loading from packages
- Verify user access and permissions
- Test fallback behavior when components not available
## Current State Analysis
### Front Page (`page.tsx`)
```
✅ Already configured for dynamic rendering
✅ DBAL client integration working
✅ PageConfig and InstalledPackage lookup implemented
✅ JSON component rendering available
✅ Package component loading ready
```
**What's missing:**
- Database not yet initialized (no tables)
- No seed data loaded (no PageConfig or InstalledPackage records)
- No bootstrap API endpoint called
- Example components need to be expanded with design
### Old System (`/old/src/`)
**Key patterns to replicate:**
- Hero section with gradient background
- Call-to-action buttons
- Multi-level interface system
- Clean, modern design with Material Design patterns
- Responsive layout
## Execution Plan
### Phase 1: Database Bootstrap (3 steps, ~5 min)
Step 1: Generate Prisma schema from YAML
```bash
npm --prefix dbal/development run codegen:prisma
```
Step 2: Push schema to SQLite database
```bash
npm --prefix dbal/development run db:push
```
Step 3: Bootstrap system with seed data
```bash
curl -X POST http://localhost:3000/api/bootstrap
```
### Phase 2: Update UI Home Components (1 step, ~20 min)
Step 4: Update `/packages/ui_home/component/ui-components.json` to replicate old system design
Key components to enhance:
- Hero section with gradient, heading, subheading, CTA buttons
- Feature grid showing system capabilities
- Get started section
- Footer with navigation
### Phase 3: Playwright E2E Tests (2 steps, ~15 min)
Step 5: Create test suite `/e2e/frontpage.spec.ts`
Step 6: Run tests
```bash
npm run test:e2e
```
### Phase 4: Refinement (~15 min)
Step 7: Visual verification and adjustments
Step 8: Performance optimization
Step 9: Final testing
## What Needs to Happen Now
1. **Bootstrap Database**: Generate schema, push to DB, call bootstrap
2. **Check Components**: Verify ui_home seed data loads correctly
3. **Update Design**: Enhance components to match old system aesthetic
4. **Create Tests**: Write Playwright tests for front page
5. **Verify**: Test that everything renders correctly
---
**Status**: Ready to execute
**Next Step**: Phase 1 - Bootstrap database

View File

@@ -1,3 +1,5 @@
'use client'
import React, { useState, useCallback, useMemo } from 'react'
import clsx from 'clsx'
import styles from '../../styles/TreeView.module.scss'

View File

@@ -1,3 +1,5 @@
'use client'
import React, { useEffect, useCallback, useState } from 'react'
import { classNames } from '../utils/classNames'

View File

@@ -1,3 +1,5 @@
'use client'
import React, { useState, useRef, useEffect } from 'react'
import { classNames } from '../utils/classNames'

View File

@@ -1,3 +1,5 @@
'use client'
import React, { forwardRef, useState, useCallback } from 'react'
import { FormLabel } from './FormLabel'
import { FormHelperText } from './FormHelperText'

View File

@@ -1,3 +1,5 @@
'use client'
import React, { forwardRef, useState, useRef, useEffect } from 'react'
import { FormLabel } from './FormLabel'
import { FormHelperText } from './FormHelperText'

View File

@@ -1,3 +1,5 @@
'use client'
import React, { forwardRef, useCallback, useRef, useState } from 'react'
import { FormLabel } from './FormLabel'
import { FormHelperText } from './FormHelperText'

View File

@@ -1,3 +1,5 @@
'use client'
import React, { forwardRef, createContext, useContext, useMemo, useId } from 'react'
/**

View File

@@ -1,3 +1,5 @@
'use client'
import React, { useState } from 'react'
import { classNames } from '../utils/classNames'

View File

@@ -1,3 +1,5 @@
'use client'
import React, { forwardRef, useState, useCallback, useMemo } from 'react'
import { classNames } from '../utils/classNames'

View File

@@ -1,3 +1,5 @@
'use client'
import React, { useState, createContext, useContext, forwardRef } from 'react'
import { classNames } from '../utils/classNames'

View File

@@ -1,3 +1,5 @@
'use client'
import React, { useState } from 'react'
import { classNames } from '../utils/classNames'

View File

@@ -1,3 +1,5 @@
'use client'
import React, { useEffect, useId } from 'react'
type CSSProperties = React.CSSProperties

View File

@@ -1,3 +1,5 @@
'use client'
import React, { useState, useEffect } from 'react'
export interface NoSsrProps {

View File

@@ -1,3 +1,5 @@
'use client'
import React, { useState, useEffect, useRef } from 'react'
import { createPortal } from 'react-dom'
import { classNames } from './classNames'

View File

@@ -1,3 +1,5 @@
'use client'
import React, { forwardRef, useRef, useEffect, useCallback } from 'react'
import { classNames } from './classNames'

View File

@@ -1,3 +1,5 @@
'use client'
import React, { createContext, useContext, useState, useCallback, useRef, useEffect } from 'react'
import { Snackbar, SnackbarContent } from '../feedback/Snackbar'

View File

@@ -1,3 +1,5 @@
'use client'
import { useState, useEffect, useCallback } from 'react'
/**

View File

@@ -1,3 +1,5 @@
'use client'
import React, { useState, useMemo, useCallback } from 'react'
import { classNames } from '../utils/classNames'

View File

@@ -1,3 +1,5 @@
'use client'
import React, { useState, useRef, useEffect } from 'react'
import { classNames } from '../utils/classNames'

View File

@@ -4,6 +4,8 @@
* Renders JSON component definitions to React elements
*/
'use client'
import React from 'react'
import type { JSONComponent } from './types'
import type { JsonValue } from '@/types/utility-types'