# GitHub Copilot Instructions for MetaBuilder

## Architecture Overview

MetaBuilder is a **data-driven, multi-tenant platform** with 95% functionality in JSON/Lua, not TypeScript. The system combines:

- **5-Level Permission System**: Public → User → Admin → God → Supergod access hierarchies
- **DBAL (Database Abstraction Layer)**: TypeScript SDK + C++ daemon, language-agnostic via YAML contracts
- **Declarative Components**: Render complex UIs from JSON configuration using `RenderComponent`
- **Package System**: Self-contained modules in `/packages/{name}/seed/` with metadata, components, scripts
- **Multi-Tenancy**: All data queries filter by `tenantId`; each tenant has isolated configurations

## 0-kickstart Operating Rules

Follow `.github/prompts/0-kickstart.md` as the current workflow source of truth. Key rules:
- Work through `.github/prompts/` as needed; start with `0-kickstart.md`.
- Commit as you go with descriptive messages; default to trunking on `main`.
- Use `act` to diagnose GitHub workflow issues locally.
- Keep unit tests parameterized; create new test files where possible; use 1:1 source-to-test naming.
- Leave TODO comments for missing functionality.
- Check `docs/todo/` before starting.
- One lambda per file; classes only serve as containers for related lambdas (see `.github/prompts/LAMBDA_PROMPT.md`).
- Route data access through DBAL; treat it as the trusted layer.
- Design for flexibility, modularity, and containerization.
- See `docs/RADIX_TO_MUI_MIGRATION.md` for UI migration guidance.

## Critical Patterns

### 1. API-First DBAL Development
When adding features to DBAL:
1. **Define in YAML first**: `api/schema/entities/*.yaml` and `api/schema/operations/*.yaml`
2. **Generate types**: `python tools/codegen/gen_types.py` (creates TS and C++ types)
3. **Implement adapters**: TypeScript (`ts/src/adapters/`) for speed, C++ (`cpp/src/adapters/`) for security
4. **Add conformance tests**: `common/contracts/*_tests.yaml` (runs on both implementations to guarantee parity)
5. Never add fields/operations directly in code without updating YAML source of truth

**Why**: C++ daemon isolates credentials (users never see DB URLs), enforces row-level security, and protects against malicious queries.

### 2. Generic Component Rendering
Instead of hardcoded components, use declarative config:
```tsx
// ❌ Wrong: Hardcoded
<UserForm user={user} onSave={handleSave} />

// ✅ Right: Declarative
<RenderComponent component={{
  type: 'form',
  props: { schema: formSchema },
  children: [/* field components */]
}} />
```
See: `RenderComponent.tsx`, `declarative-component-renderer.ts`

### 3. Package Seed Data Structure
Each package auto-loads on init:
```
packages/{name}/
├── seed/
│   ├── metadata.json      # Package info, exports, dependencies
│   ├── components.json    # Component definitions
│   ├── scripts/           # Lua scripts organized by function
│   └── index.ts           # Exports packageSeed object
├── src/                   # Optional React components
└── static_content/        # Assets (images, etc.)
```
Loaded by `initializePackageSystem()` → `buildPackageRegistry()` → `exportAllPackagesForSeed()`

### 4. Database Helpers Pattern
Always use `Database` class methods, never raw Prisma:
```typescript
// ✅ Right
const users = await Database.getUsers()
await Database.setSchemas(schemas)

// ❌ Wrong
const users = await prisma.user.findMany()
```
See: `src/lib/database.ts` (1200+ LOC utility wrapper)

### 5. Lua Sandbox Execution
Lua scripts run in isolated sandbox without access to `os`, `io`, `require`:
```typescript
// Sandbox context provided in script
function validateEmail(email)
  -- No file I/O, no system access, no external requires
  return string.match(email, "^[^@]+@[^@]+$") ~= nil
end
```
Always test scripts with `DeclarativeComponentRenderer.executeLuaScript()`

## Code Conventions

### UI Components & Styling

**⚠️ CRITICAL: This project does NOT use Radix UI or Tailwind CSS**

- ❌ **NEVER import from `@radix-ui/*`** - These dependencies have been removed
- ❌ **NEVER use Tailwind utility classes** in `className` props
- ✅ **ALWAYS use Material-UI** (`@mui/material`) for UI components
- ✅ **Use MUI's `sx` prop** for inline styles with theme access
- ✅ **Create `.module.scss` files** for component-specific custom styles
- ✅ **Use `@mui/icons-material`** for icons, not lucide-react or heroicons

```tsx
// ❌ Wrong: Using Radix UI or Tailwind
import { Dialog } from '@radix-ui/react-dialog'
<button className="bg-blue-500 text-white px-4 py-2">Click</button>

// ✅ Right: Using Material-UI
import { Dialog, Button } from '@mui/material'
<Button variant="contained" color="primary">Click</Button>
<Box sx={{ display: 'flex', gap: 2, p: 3 }}>Content</Box>
```

**Component Mapping:**
- Radix Dialog → MUI Dialog
- Radix Select → MUI Select
- Radix Checkbox → MUI Checkbox
- Radix Switch → MUI Switch
- Tailwind classes → MUI `sx` prop or SCSS modules

**See:** `UI_STANDARDS.md` and `docs/UI_MIGRATION.md` for complete reference

### TypeScript/React
- One lambda per file; classes are containers for related lambdas.
- Keep files small and focused; split by responsibility when they grow.
- Use `@/` absolute paths
- Functional components with hooks; avoid class components
- Test files next to source with matching names: `utils.ts` + `utils.test.ts`, using parameterized `it.each()`

### Tests
All functions need coverage with parameterized tests:
```typescript
// From schema-utils.test.ts: 63 tests for 14 functions
it.each([
  { input: 'case1', expected: 'result1' },
  { input: 'case2', expected: 'result2' },
])('should handle $input', ({ input, expected }) => {
  expect(myFunction(input)).toBe(expected)
})
```
Run `npm run test:coverage:report` to auto-generate coverage markdown.

### Database
- Schema in `prisma/schema.prisma`, always run `npm run db:generate` after changes
- Hash passwords with SHA-512 (see `password-utils.ts`)
- Queries must include `where('tenantId', currentTenant.id)` for multi-tenancy

### Styling
Material-UI with SASS; theme in `src/theme/mui-theme.ts` with light/dark mode support. Font families: IBM Plex Sans (body), Space Grotesk (headings), JetBrains Mono (code). Use MUI's `sx` prop for inline styles or create `.module.scss` files for custom component styles.

## Development Checklist

**Before implementing**: Check `docs/` and `docs/todo/`, and review `.github/prompts/0-kickstart.md` for current workflow rules.

**During implementation**:
1. Define database schema changes first (Prisma)
2. Add seed data to `src/seed-data/` or package `/seed/`
3. Use generic renderers (`RenderComponent`) not hardcoded JSX
4. Add Lua scripts in `src/lib/lua-snippets.ts` or package `/seed/scripts/`
5. Keep one lambda per file and split as needed
6. Add parameterized tests in `.test.ts` files with matching names

**Before commit**:
- `npm run lint:fix` (fixes ESLint issues)
- `npm test -- --run` (all tests pass)
- `npm run test:coverage:report` (verify new functions have tests)
- `npm run test:e2e` (critical workflows still work)
- Use `npm run act:diagnose` or `npm run act` when investigating CI/workflow failures
- Commit with a descriptive message on `main` unless a PR workflow is explicitly required

## Multi-Tenant Safety

Every query must filter by tenant:
```typescript
// ❌ Never
const data = await Database.getData()

// ✅ Always  
const data = await Database.getData({ tenantId: user.tenantId })
```

Permission checks cascade from lowest level:
```typescript
if (user.level >= 3) {  // Admin and above
  showAdminPanel()
}
```

## DBAL-Specific Guidance

**TypeScript DBAL**: Fast iteration, development use. Located in `dbal/ts/src/`.
**C++ DBAL Daemon**: Production security, credential protection. Located in `dbal/cpp/src/`.
**Conformance Tests**: Guarantee both implementations behave identically. Update `common/contracts/` when changing YAML schemas.

If fixing a DBAL bug:
1. Verify the bug exists in YAML schema definition
2. Reproduce in TypeScript implementation first (faster feedback loop)
3. Apply fix to both TS and C++ adapters
4. Add/update conformance test in `common/contracts/`
5. Verify both implementations pass test: `python tools/conformance/run_all.py`

## Common Mistakes

❌ **Hardcoding values in TSX** → Move to database or YAML config
❌ **Forgetting tenantId filter** → Breaks multi-tenancy
❌ **Adding fields without Prisma generate** → Type errors in DB helper
❌ **Plain JS loops over Fengari tables** → Use Lua, not TS, for Lua data
❌ **Multiple lambdas per file** → Split into single-lambda files and wrap with a class only when needed
❌ **New function without test** → `npm run test:check-functions` will fail
❌ **Missing TODO for unfinished behavior** → Leave a TODO comment where functionality is pending

## Key Files

- **Architecture**: `docs/architecture/5-level-system.md` (permissions), `docs/architecture/packages.md` (packages)
- **Components**: `src/components/RenderComponent.tsx` (generic renderer), `src/lib/declarative-component-renderer.ts`
- **Database**: `src/lib/database.ts` (all DB operations), `prisma/schema.prisma` (schema)
- **Packages**: `src/lib/package-loader.ts` (initialization), `packages/*/seed/` (definitions)
- **Tests**: `src/lib/schema-utils.test.ts` (parameterized pattern), `FUNCTION_TEST_COVERAGE.md` (auto-generated report)
- **DBAL**: `dbal/AGENTS.md` (detailed DBAL agent guide), `api/schema/` (YAML contracts)

## Questions to Ask

1. Is this hardcoded value better in database?
2. Could a generic component render this instead of custom TSX?
3. Does this query filter by tenantId?
4. Could Lua handle this without code changes?
5. Is this one lambda per file (and test file name matches)?
6. Does this function have a parameterized test?
7. Is this DBAL change reflected in YAML schema first?
