# Builder Package - Cursor Rules

## Overview

This is the **bongo/builder** package — a Laravel visual page builder providing 713 pre-built HTML/CSS blocks (427 components, 266 designs, 20 layouts) plus a heavily customised, fully modularised vanilla-JS editor (a ContentBox.js v4.1 derivative, 156 ES modules). Blocks are stored on disk as Blade templates — there is no database layer in this package.

## Project Structure

```
src/
├── BuilderServiceProvider.php   # Extends AbstractServiceProvider (bongo/framework)
├── Config/builder.php           # Paths, categories, 2,045 FontAwesome icons (2,125 lines)
├── Models/BuilderItem.php       # File-based polymorphic model (component/design/layout)
├── Facades/                     # ComponentFacade, DesignFacade, LayoutFacade
├── Exceptions/                  # ComponentException, DesignException
├── Seeders/                     # DataSeeder, ComponentSeeder, DesignSeeder
├── Translations/en/backend.php
├── Http/
│   ├── Controllers/
│   │   ├── Api/                 # 22 controllers feeding the editor (JSON/HTML fragments)
│   │   └── Backend/             # 4 admin CRUD controllers (Component, Design, Layout, Icon)
│   └── Middleware/
│       └── HasShortCodes.php    # Replaces [company_*] setting shortcodes in responses
├── Routes/
│   ├── api.php                  # 11 authenticated endpoints (auth:sanctum, /api prefix)
│   ├── backend.php              # Admin CRUD routes (auth + employee, /admin prefix)
│   └── custom.php               # 11 public endpoints (noIndex middleware only)
└── Views/
    ├── frontend/                # The block library itself
    │   ├── component/           # 427 blocks in 16 categories
    │   ├── design/              # 266 blocks in 16 categories
    │   ├── layout/              # 20 blocks in 3 categories (Headers, Headings, Footers)
    │   └── carousels/ posts/ projects/ questions/ sliders/
    │                            # style_1..5.blade.php fragments rendered by the
    │                            # public custom.php module controllers
    ├── backend/                 # Admin UI views (component/, design/, layout/)
    └── api/                     # HTML fragment templates returned by API controllers

resources/
├── backend/
│   ├── js/
│   │   ├── editor.js            # Editor entry point (ContentBox v4.1, vanilla JS)
│   │   ├── EditorDefaults.js    # buildEditorDefaults() — default editor options
│   │   ├── AssetLoader.js       # Runtime CSS/JS asset loading
│   │   ├── helpers.js           # Compiled separately to public/backend/helpers.js
│   │   ├── shared/              # DomHelper, StringHelper, HtmlSanitiser, etc. (9 modules)
│   │   └── contentbuilder/      # The editor library (grid/, rte/, elements/, sections/,
│   │                            #   ui/, plugins/, config/, core/, openai/, utils/)
│   └── sass/editor.scss         # → public/backend/editor.css
└── frontend/
    ├── sass/box.scss            # → public/frontend/box.css
    └── js/box.js                # Bundled with vendored jquery.appear/skrollr/aos

public/                          # Compiled assets, published via tag builder:assets
tests/
├── browser/                     # 135 Playwright specs, 706 tests
├── vitest/                      # 82 unit spec files, 1,719 tests (fast jsdom layer)
├── Feature/, Unit/              # PHPUnit dirs (currently empty; Testbench TestCase exists)
└── TestCase.php                 # Orchestra Testbench base
```

## Architecture Rules

1. **BuilderItem is NOT an Eloquent model.** It is a plain class reading/writing files. Never add database queries, `$fillable`, or migrations to it.
2. **Vendor/resource override pattern**: originals live in `vendor/bongo/builder/src/Views/frontend/...`; user customisations are written to `resources/views/vendor/builder/...`. `getAllFiles()` merges the two with `array_replace()` — resource wins. `delete()` only ever removes the resource copy.
3. **Three singletons, one class**: `BuilderServiceProvider::registerBindings()` registers `component`, `design`, `layout` container singletons, each `new BuilderItem($type)`, plus global aliases `Component`, `Design`, `Layout` via `AliasLoader`.
4. **Caching**: `all()` caches per type under key `{type}_files` for 600 seconds. Every mutation (`save()`, `delete()`) must `Cache::forget("{$this->type}_files")`.
5. **Each block directory contains exactly** `index.blade.php` + `preview.png`. Names and categories are slugified by the setters (`Str::slug`, lowercase).
6. **Route middleware comes from AbstractServiceProvider** (bongo/framework): `api.php` → `/api` + `auth:sanctum`; `backend.php` → `/admin` + `auth` + `employee`; `custom.php` → no session middleware. Never re-add prefixes/middleware inside the route files.
7. **JS is framework-free.** The editor layer is vanilla ES modules — no jQuery, no Vue in `resources/backend/js`. Shared low-level helpers live in `resources/backend/js/shared/`; editor-specific code lives under `contentbuilder/`. See `ARCHITECTURE-JS.md` for the full JS architecture.
8. **Templates in `src/Views/api/`** are Blade fragments returned to the editor (snippets, icons, fonts, modules, etc.) — they render inside editor iframes/panels, not as full pages.

## Coding Conventions

- PHP 8.2+, PSR-4 namespace `Bongo\Builder\` → `src/`
- Always declare return types: `all(): Collection`, `allAsJson(): false|string`, `save(): void`
- Short nullable notation: `public ?string $name = null;`
- Use `DIRECTORY_SEPARATOR` for all path concatenation
- Log with the `log_exception($e)` helper; throw `ComponentException` / `DesignException`; 404 with `abort('404')`
- Config keys are snake_case: `component_path`, `backend_css_file`
- Route names: `component.index`, `design.create` (backend); `api.builder.icon.index` (API)
- Views/blocks: kebab-case directories (`component/headline/header-02/`)
- Laravel Pint (`pint.json`) enforces style — run `vendor/bin/pint` before committing
- JS: ESLint (`.eslintrc.json`) over `resources/backend/js`; CSS selectors linted by `scripts/lint-css-selectors.mjs` — both run automatically in `npm run dev`/`prod`

## Common Tasks

### Add a new block
1. Create `src/Views/frontend/{type}/{category}/{name}/` with `index.blade.php` + `preview.png`
2. It is auto-discovered on the next `Component::all()` (after the 10-minute cache expires or `Cache::forget('{type}_files')`)

### Add a new category
1. Add to `{type}_categories` in `src/Config/builder.php`
2. Create the matching slug directory under `src/Views/frontend/{type}/`

### Add an editor API endpoint
1. Controller in `src/Http/Controllers/Api/` (single `index()` action is the norm)
2. Route in `src/Routes/api.php` (authenticated) or `src/Routes/custom.php` (public)
3. Fragment template in `src/Views/api/` if returning HTML

### Change editor behaviour
1. Find the subsystem in `resources/backend/js/contentbuilder/` (grid, rte, elements, sections, ui — see `ARCHITECTURE-JS.md`)
2. `npm run dev` to rebuild `public/backend/editor.js`
3. Verify in a real browser AND run/extend the Playwright specs in `tests/browser/`

## Testing & Commands

```bash
vendor/bin/phpunit          # PHPUnit (Testbench; suites currently empty)
vendor/bin/pint --test      # Style check
vendor/bin/phpstan analyse  # Static analysis (phpstan.neon.dist)

npm run dev                 # Lint (JS + CSS selectors) then development build
npm run watch               # Rebuild on change
npm run prod                # Lint then production build

npm test                    # 135 Playwright browser specs, 706 tests (tests/browser/)
npm run test:unit           # 82 vitest files, 1,719 tests (fast, no consumer site needed)
npm run test:headed         # Headed browser
npm run test:ui             # Playwright UI mode
```

Playwright needs `.env.testing` (see `.env.testing.example`) with `TEST_BASE_URL` pointing at a consumer site; login state is stored in `storageState.json` by `tests/browser/global-setup.js`. Runs single-worker, 1 retry.

## Framework Integration

Extends `Bongo\Framework\Providers\AbstractServiceProvider` (bongo/framework), which auto-registers config (`src/Config/builder.php` as `builder.*`), routes, views (namespace `builder::`), translations, and the `hasShortCodes` middleware alias declared in `$middlewares`. The provider only adds `registerBindings()` (singletons + aliases) and `bootAssets()` (publishes `public/` under tag `builder:assets`).

Depends on `bongo/framework` (^3.0) and `bongo/image` (^3.0). The public `custom.php` endpoints integrate other Bongo packages into the editor: posts, projects, questions/FAQs, reviews, forms, menus, galleries, carousels, sliders.

## Do NOT

- Add database migrations or Eloquent behaviour to this package
- Write to the vendor views path at runtime — `save()` writes to the resource path only
- Hardcode `/api`, `/admin`, or middleware in route files (AbstractServiceProvider owns those)
- Introduce jQuery or a JS framework into `resources/backend/js`
- Edit files in `public/` by hand — they are build artefacts of `webpack.mix.js`
- Forget `Cache::forget('{type}_files')` after any file mutation
