# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

MTC Pharmacy Starter — a Laravel 11 + legacy PHP hybrid platform for online pharmacy websites. Built by mtcmedia.

## Development Commands

### Docker (primary dev environment)
```sh
make up              # Start containers
make down            # Stop containers
make shell           # Shell into PHP container (mtc-pharmacy-web)
make migrate         # Run migrations
make fresh           # Fresh migrate + seed + encryption
make cache           # Clear all caches
make db-sync         # Pull production DB locally (requires .env.prod.local)
make db-reset-admin  # Reset admin password
make new-migration   # Create a new migration file
make queue           # Run queue worker
```

### Frontend (Vite + LESS + Vue 2)
```sh
npm run dev          # Vite dev server with HMR (port 5173)
npm run build        # Production build to public/build/
```

### Testing
```sh
./vendor/bin/phpunit                    # Run all tests
./vendor/bin/phpunit tests/Unit         # Unit tests only
./vendor/bin/phpunit tests/Feature      # Feature tests only
./vendor/bin/phpunit --filter=TestName  # Single test
```
Tests bootstrap via `core/includes/header.inc.php` (legacy core), not Laravel's standard bootstrap.

### Artisan (run inside container or prefix with `docker exec -it mtc-pharmacy-web`)
```sh
php artisan migrate
php artisan db:seed
php artisan queue:work
php artisan route:list
```

## Architecture

### Dual Bootstrap System

The app boots through a **two-phase process**:

1. **Legacy core** (`core/includes/header.inc.php`) — initializes sessions, settings, Twig, hooks, and auto-discovers modules/plugins. Loads Laravel container via `core/includes/container.php`.
2. **Laravel kernel** (`index.php`) — if Laravel routing returns 404, falls back to legacy CMS routing (`core/index.php` → `cms/index.php`)

### Key Directories
- `app/` — Laravel controllers, models, services, providers
- `core/` — Legacy core system (admin panel, classes, includes, templates)
- `shop/` — E-commerce module (products, basket, checkout, orders)
- `cms/` — Content management system
- `modules/` — Self-contained feature modules (both legacy and Laravel-style)
- `plugins/` — Payment gateways, integrations, features (auto-discovered)
- `sites/default/` — Site theme: templates, CSS, JS
- `config/` — Laravel config files

### Namespace Mapping (PSR-4)
- `App\` → `app/`
- `Mtc\Core\` → `core/src/`
- `Mtc\Shop\` → `shop/src/`
- `Mtc\Cms\` → `cms/src/`
- `Mtc\Modules\` → `modules/`
- `Mtc\Plugins\` → `plugins/`
- `MtcPharmacy\*` → pharmacy-specific plugins in `plugins/`

### Template System — Twig 3 (NOT Blade)

Templates use **Twig**, not Laravel Blade. The `template()` helper renders Twig templates. Twig instance is at `app('twig')`.

**Template path resolution order** (first match wins):
1. `sites/{SITE}/templates/`
2. `sites/default/templates/`
3. `modules/*/templates/` and `plugins/*/templates/` (globbed together, order not guaranteed between them)
4. `shop/templates/`
5. `cms/templates/`
6. `core/templates/`

**Template organization** (`sites/default/templates/`):
- `layouts/` — Base layouts (extends chain: page → `main.twig` → `default.twig`)
- `includes/page_blocks/` — Reusable page section components (hero_banner, title_banner, etc.)
- `includes/elements/` — Small reusable UI elements
- `includes/partials/` — Partial templates

### Module System

**Two types of modules** coexist in `modules/`:

1. **Legacy modules** — Auto-discovered via `loader.php`, `hooks.php`, and `templates/` directory. Use the `HooksAdapter` (WordPress-style actions/filters).
2. **Laravel modules** — Registered as service providers in `config/app.php`. Use standard Laravel conventions (ServiceProvider, migrations, Eloquent models, routes).

Key Laravel modules: `Members` (has ServiceProvider registered in `config/app.php`). `FormBuilder` and `ModuleBuilder` are legacy modules (no ServiceProviders).

**Plugins** (`plugins/`) follow the same auto-discovery pattern as legacy modules. 30+ plugins including payment gateways (Realex, Judopay, EvoPay), integrations (Wisebee, Feefo), and pharmacy features (Prescriptions, QualifyingAnswers, Bundles, Clinic).

### Frontend Stack
- **CSS**: LESS → entry at `sites/default/css/app.less`, variables at `sites/default/css/variables.less`
- **JS**: Vue 2 + jQuery + Vuex, entry at `sites/default/js/app.js`
- **Build**: Vite 4 with `@vitejs/plugin-vue2`, output to `public/build/`
- **Path aliases**: `@site` → `sites/default`, `@core` → `core`, `@components` → `sites/default/js/components`, `@plugins` → `plugins`, `@shop` → `shop`, `@site_scripts` → `sites/default/js/site_scripts`
- **LESS auto-imports**: Vite prepends a different token + mixin set depending on the file path (see `vite.config.js` `additionalData`):
  - **Public-site LESS** (everything outside an `admin/` segment): `sites/default/css/variables.less` + `plugins/mtc_assessments/css/variables.less` + `core/css/mixins.less` + `sites/default/css/base/mixins.less`.
  - **Admin LESS** (any path containing `/admin/` — including `plugins/*/admin/css/*.less` and Vue SFCs under `plugins/*/admin/js/`): a slim plugin-local pair only — `plugins/mtc_assessments/admin/css/admin_variables.less` + `plugins/mtc_assessments/admin/css/admin_mixins.less`.
  - Public and admin token sets are kept entirely separate so admin styling never affects the front end and `sites/default/css/variables.less` never leaks into admin builders. Admin colours / typography mirror `core/admin/styleguide.php`. The plugin-local admin token file is intentionally scoped to `mtc_assessments` for now; it'll move up to `core/admin/css/` when the wider admin (members area, etc.) is restyled.

### Database
- MySQL/MariaDB via Eloquent ORM (legacy code also uses direct PDO queries)
- Migrations in `database/migrations/`

### Docker Environment
- **mtc-pharmacy-web** — PHP Apache container (app server)
- **mariadb** — MariaDB database
- **mailhog** — Email testing (catches all outgoing mail)
- Setup script: `docker-setup.sh` handles initial `.env` and `.htaccess` configuration

## Figma-to-Code Workflow

Custom slash commands for converting Figma designs to Twig + LESS:
- `/mtc-rebrand <full-page-figma-url>` — Rebrand design system (run once per project)
- `/mtc-extract <component-figma-url>` — Extract new component to Twig + LESS
- `/mtc-update <figma-url> <component-name>` — Update existing component from Figma
- `/mtc-cms-structure <component-name>` — Generate CMS structure

Components preview at `http://localhost/component`. Generated files go to `sites/default/templates/includes/` and `sites/default/css/`. Workflow documentation in `.frontend/workflows/`.

## Rules

- **Never install packages without explicit user consent** — do not run `npm install`, `composer require`, or any other package manager install commands without asking first
- **Follow the project constitution** — see `.specify/memory/constitution.md` for core principles on healthcare compliance, plugin architecture, and development standards. The constitution supersedes other development practices.

## Conventions

- Twig templates use `.twig` extension with snake_case names
- LESS files use snake_case
- Module/Plugin directories use PascalCase
- Legacy code uses snake_case functions; Laravel code uses camelCase methods
- Use `<div>` (not `<p>`) to wrap `|raw` Twig content (TinyMCE compatibility)
- Use `/sites/default/{{ variable }}` for asset paths (not Laravel's `asset()` function)
- **Never use `var` in JavaScript** — always use `let` or `const`
- **PHP uses PSR curly brace syntax** — use `if () {` / `} else {` / `foreach () {`, never the alternative colon syntax (`if():` / `endif;` / `endforeach;`)

## Active Technologies
- PHP 8.4 / Laravel 11 + Eloquent ORM, Twig 3, Vue.js 2, HooksAdapter (legacy), Laravel Event Dispatcher
- MariaDB (via Eloquent + migrations)
