# AGENTS.md — Alphabd Technology

## Stack
Laravel 11 + Vue 3 (Inertia.js) + Tailwind CSS v4 + MySQL. No API routes — all admin via Inertia SSR. No Fortify/Jetstream — hand-rolled auth.

## Commands
```bash
composer dev          # Run all 4 dev processes (server, queue, logs, vite)
php artisan serve     # Backend only
npm run dev           # Vite HMR only
npm run build         # Production build (NOT "npm run production")
php artisan migrate:fresh --seed  # Reset DB
composer test         # PHPUnit (SQLite in-memory)
./deploy.sh           # Shared hosting deploy
```

## Column Naming Gotchas
These differ from what you'd intuitively guess:

| Expected | Actual | Table |
|----------|--------|-------|
| `service_category_id` | `category_id` | `services` |
| `product_category_id` | `category_id` | `products` |
| `blog_category_id` | `category_id` | `blog_posts` |
| `name` | `title` | `products`, `services` |
| `image` | `featured_image` | `blog_posts` |
| `is_active` | `is_published` | `pages`, `blog_posts` |
| `order` | `sort_order` | all tables |

Exception: `service_requests.service_category_id` IS fully prefixed.

## Relationship Naming
FK is `category_id` but relationship methods are fully qualified:
- `Service::serviceCategory()` (not `category()`)
- `Product::productCategory()` (not `category()`)
- `BlogPost::blogCategory()` (not `category()`)
- Category models: `hasMany(Service::class, 'category_id')` — must specify FK

## Admin Auth
- URL: `/admin/login`
- Email: `admin@alphabdtechnology.com` / Password: `password`
- Middleware: `admin` — checks `super_admin` or `content_manager` role slug
- Support staff role exists but is blocked from admin panel

## Frontend Components
Use these (in `resources/js/Components/`):
- `FormInput`, `FormSelect`, `FormTextarea`, `FormCheckbox` — all support `v-model`, `label`, `error`, `required`
- `FormFileUpload` — drag-drop image upload with preview, supports `v-model`, `label`, `error`, `currentImage`
- `FormActions` — submit + cancel buttons
- `PageHeader` — title + optional add button
- `DeleteConfirmModal` — paired with `useDeleteModal` composable
- `Pagination` — accepts Laravel paginator object
- `StatusBadge` — colored pill, accepts `status` prop
- `IconPicker` — 16 predefined ICT icons for service categories

## Validation
- **Library:** Yup (`npm install yup`)
- **Composable:** `useFormValidation(form, schema)` from `@/Composables/useFormValidation`
- **Schemas:** `@/Utils/validationSchemas` — all form schemas (contact, support, products, blog, etc.)
- **Pattern:** Validate before submit, errors auto-set on `form.errors`
- **Forms:** All `<form>` elements have `novalidate` (browser validation disabled)
- **Red borders:** Fields show `border-red-500` when validation fails

## Key Patterns
- Controllers use `Inertia::render()` — not Blade views
- Settings cached 1 hour via `Setting::get()` (`cache()->remember()`)
- Media uploads use UUID filenames, originals not preserved
- Page routes are slug-based (`admin/pages/{slug}/edit`), not ID-based
- Blog has extra `togglePublish` route at `admin/blog/{id}/toggle-publish`
- User controller prevents self-deletion
- Email is logged locally (`MAIL_MAILER=log`), no SMTP configured

## Tailwind CSS v4
Uses new v4 syntax in `resources/css/app.css`:
- `@import 'tailwindcss'` (not `@tailwind base/components/utilities`)
- `@theme {}` block for custom colors/fonts
- `@source` for content scanning
- Custom classes: `.btn-primary`, `.btn-accent`, `.btn-outline`, `.card`, `.input-field`

## Deploy Gotchas
- `deploy.sh` auto-downloads `composer.phar` if system `composer` is missing (phar extension issue on shared hosting)
- Uses `npm run build` (not `npm run production`)
