# Hillcrest Living Architecture Runbook

## Purpose
This runbook defines the technical architecture, engineering standards, and operating model for building and maintaining the Hillcrest Living website and admin CMS.

## System Overview
- **Application Type:** Monolithic Laravel app
- **Frontend:** Blade + Tailwind + Alpine.js
- **Admin CMS:** Filament v3 (`/admin`)
- **Database:** MySQL 8
- **Hosting Target:** cPanel + Apache + PHP 8.3
- **Deployment Model:** Build assets before deploy, server runs PHP only

## Architecture Principles
- Keep frontend SEO-first and server-rendered.
- Keep all business content CMS-editable.
- Separate structural code from content data.
- Use design tokens (not raw hex) in UI classes/components.
- Keep modules isolated by business domain for maintainability.

## Implementation Strategy (Vertical Slices)
The website and admin portal must be developed together in incremental, feature-complete slices. Do not run a "frontend first, CMS later" delivery model for production work.

Required approach:
1. Pick a single scope slice (for example Home hero, Services section, News index, Careers listing).
2. Implement data layer (migration/model/relationship).
3. Implement CMS layer (Filament resource/forms/tables, publish states, permissions).
4. Implement public rendering layer (controller query + Blade/components).
5. Implement safeguards (validation, authorization, anti-spam/rate limits where relevant).
6. Validate end-to-end editor workflow and public output before moving to the next slice.

Why this is required:
- prevents hardcoded-content rework
- validates real editor experience early
- ensures every public section remains CMS-manageable
- reduces late integration risk between website and admin portal

## Theme Architecture (Admin-Editable Colors/Fonts)
To support future brand updates without code rewrites:

1. Store theme settings in database (single settings record), including:
   - Primary/accent/background/text colors
   - Heading and body font families
   - Optional CTA variant settings
2. Expose these fields in Filament under `Settings > Theme`.
3. Render settings into CSS custom properties at runtime (or cached compiled output):
   - `--color-primary`, `--color-accent`, `--font-heading`, etc.
4. Map Tailwind/component styles to semantic classes/tokens rather than hardcoded colors.
5. Add a cache refresh action after theme updates so changes are reflected immediately.

### Theme Data Contract (Recommended)
- `theme.primary`
- `theme.accent`
- `theme.heading`
- `theme.body`
- `theme.surface`
- `theme.surface_alt`
- `theme.font_heading`
- `theme.font_body`

This allows controlled updates from admin while preserving consistent UI behavior.

## Proposed Database Schema (Pre-Build)
This is the proposed baseline schema for v1. Names are Laravel-friendly and can be adjusted before first migration freeze.

### Global Settings and Theme
- `settings`
  - Purpose: single-source global site settings and theme values.
  - Core columns:
    - `id`
    - `site_name`
    - `site_tagline`
    - `contact_email`, `contact_phone`, `contact_address`
    - `contact_map_embed_url` (nullable)
    - `contact_map_place_label` (nullable)
    - `contact_latitude` (nullable decimal)
    - `contact_longitude` (nullable decimal)
    - `social_facebook`, `social_instagram`, `social_linkedin`, `social_x`
    - `footer_text`, `cookie_notice_text`, `cookie_notice_enabled`
    - `theme_primary_color`, `theme_accent_color`, `theme_heading_color`, `theme_body_color`
    - `theme_surface_color`, `theme_surface_alt_color`
    - `theme_font_heading`, `theme_font_body`
    - `logo_media_id` (nullable FK -> `media.id`)
    - `og_default_media_id` (nullable FK -> `media.id`)
    - `updated_by` (nullable FK -> `users.id`)
    - timestamps
  - Notes:
    - Keep as singleton row (id=1) with admin form-level guard.
    - Theme values are exposed as CSS variables at runtime.
    - Contact page map iframe source should come from `contact_map_embed_url` to allow admin-side updates without code changes.

### Content Structure
- `pages`
  - Purpose: route-level page metadata and SEO wrapper.
  - Core columns:
    - `id`
    - `title`
    - `slug` (unique)
    - `route_path` (unique, e.g. `/about`)
    - `intro` (nullable)
    - `status` (`draft|published`)
    - `published_at` (nullable)
    - `meta_title`, `meta_description`
    - `canonical_url` (nullable)
    - `og_title`, `og_description`, `og_media_id` (nullable FK -> `media.id`)
    - timestamps
- `page_sections`
  - Purpose: flexible ordered content sections per page.
  - Core columns:
    - `id`
    - `page_id` (FK -> `pages.id`)
    - `section_key` (e.g. `hero`, `what_we_do`, `stats_banner`)
    - `heading` (nullable), `subheading` (nullable)
    - `body` (long text/json depending on component)
    - `cta_primary_label`, `cta_primary_url` (nullable)
    - `cta_secondary_label`, `cta_secondary_url` (nullable)
    - `media_id` (nullable FK -> `media.id`)
    - `sort_order`
    - `is_active` (bool)
    - timestamps
  - Indexing:
    - composite index on (`page_id`, `section_key`)
    - index on (`page_id`, `sort_order`)

### Shared Media and Downloads
- `media`
  - Purpose: central media library for images/files.
  - Core columns:
    - `id`
    - `disk` (default `public`)
    - `path`
    - `filename`
    - `mime_type`
    - `size_bytes`
    - `alt_text` (nullable)
    - `caption` (nullable)
    - `width`, `height` (nullable)
    - `uploaded_by` (nullable FK -> `users.id`)
    - timestamps
- `downloads`
  - Purpose: public downloads listing and categorization.
  - Core columns:
    - `id`
    - `title`
    - `slug` (unique)
    - `category` (nullable)
    - `description` (nullable)
    - `media_id` (FK -> `media.id`)
    - `is_published` (bool)
    - `published_at` (nullable)
    - `sort_order`
    - timestamps

### Services, Team, Testimonials, Stats
- `services`
  - `id`, `title`, `slug`, `summary`, `body` (nullable), `icon` (nullable), `media_id` (nullable FK), `sort_order`, `is_published`, timestamps
- `team_members`
  - `id`, `name`, `role_title`, `bio` (nullable), `photo_media_id` (nullable FK), `sort_order`, `is_published`, timestamps
- `testimonials`
  - `id`, `quote`, `author_name` (nullable), `source_type` (`resident|family|referrer`), `star_rating` (nullable tinyint), `is_featured`, `is_published`, `sort_order`, timestamps
- `site_stats`
  - `id`, `label`, `value_text`, `value_number` (nullable), `suffix` (nullable), `sort_order`, `is_published`, timestamps

### News / Blog
- `news_categories`
  - `id`, `name`, `slug` (unique), timestamps
- `news_posts`
  - `id`
  - `title`, `slug` (unique)
  - `excerpt` (nullable), `body`
  - `cover_media_id` (nullable FK -> `media.id`)
  - `category_id` (nullable FK -> `news_categories.id`)
  - `status` (`draft|published`)
  - `published_at` (nullable)
  - `meta_title`, `meta_description`
  - `og_title`, `og_description`, `og_media_id` (nullable FK -> `media.id`)
  - `author_user_id` (nullable FK -> `users.id`)
  - timestamps
  - Indexing:
    - index on (`status`, `published_at`)

### Careers / Agency
- `job_listings`
  - Purpose: vacancy management for `/careers`.
  - Core columns:
    - `id`
    - `title`
    - `slug` (unique)
    - `department` (nullable)
    - `location` (nullable)
    - `employment_type` (`full_time|part_time|bank`)
    - `salary_text` (nullable)
    - `description`
    - `closing_date` (nullable date)
    - `status` (`open|closed`)
    - `is_published` (bool)
    - timestamps
  - Indexing:
    - index on (`status`, `closing_date`)
- `job_applications`
  - Purpose: applications inbox in admin.
  - Core columns:
    - `id`
    - `job_listing_id` (FK -> `job_listings.id`)
    - `full_name`
    - `email`
    - `phone`
    - `cover_note` (nullable)
    - `cv_media_id` (nullable FK -> `media.id`)
    - `status` (`new|reviewed|shortlisted|rejected`)
    - `review_notes` (nullable)
    - timestamps
  - Indexing:
    - index on (`job_listing_id`, `status`)

### Contact and Referral Forms
- `contact_submissions`
  - `id`, `name`, `email`, `phone` (nullable), `subject`, `message`, `ip_address`, `user_agent` (nullable), `status` (`new|read|resolved`), timestamps
  - Indexing:
    - index on (`status`, `created_at`)
- `referral_submissions`
  - `id`
  - `referrer_name`, `referrer_organisation` (nullable), `referrer_role` (nullable), `referrer_email`, `referrer_phone` (nullable)
  - `individual_name`, `individual_dob` (nullable), `individual_postcode` (nullable)
  - `support_needs` (json)
  - `additional_notes` (nullable long text)
  - `attachment_media_id` (nullable FK -> `media.id`)
  - `ip_address`, `user_agent` (nullable)
  - `status` (`new|reviewed|actioned|closed`)
  - timestamps
  - Indexing:
    - index on (`status`, `created_at`)

### Optional Audit and Operational Tables (Recommended)
- `activity_logs` (if using Spatie activitylog)
  - track key CMS edits, theme changes, and moderation actions.
- `failed_jobs`, `jobs`, `cache`, `sessions`
  - standard Laravel operational tables depending on selected drivers.

### Relationship Summary
- `pages` 1:N `page_sections`
- `news_categories` 1:N `news_posts`
- `job_listings` 1:N `job_applications`
- `media` referenced by many modules (`settings`, `pages`, `services`, `team_members`, `news_posts`, `downloads`, form attachments)
- `users` referenced as creator/updater where needed

### Migration Order (Recommended)
1. Core Laravel/auth tables
2. `media`
3. `settings`
4. `pages` + `page_sections`
5. domain tables (`services`, `team_members`, `testimonials`, `site_stats`)
6. news tables (`news_categories`, `news_posts`)
7. careers tables (`job_listings`, `job_applications`)
8. submission tables (`contact_submissions`, `referral_submissions`)
9. optional operational/audit tables

### Seed Data Plan (Recommended)
- Seed one singleton `settings` row with brand defaults.
- Seed standard pages and baseline section keys.
- Seed one admin user and one editor user (dev/staging only).
- Seed demo services/testimonials/news/jobs for UI validation.

## Folder Structure Standards
Recommended layout for clean scaling:

- `app/`
  - `Filament/Resources/` (CMS resources by module)
  - `Http/Controllers/` (public controllers)
  - `Http/Requests/` (form validation classes)
  - `Models/` (domain entities)
  - `Services/` (business logic; keep controllers thin)
- `database/`
  - `migrations/`
  - `seeders/`
  - `factories/`
- `resources/`
  - `views/layouts/`
  - `views/components/`
  - `views/pages/`
  - `css/`
  - `js/`
- `routes/`
  - `web.php`
- `public/`
  - built assets and static files
- `storage/app/public/`
  - uploaded media and documents

Naming conventions:
- Use singular model names (`Service`, `Testimonial`, `JobListing`)
- Keep Blade components reusable and section-oriented
- Group Filament resources by business capability, not by tech layer

## Content and Domain Modules
- Core CMS modules:
  - Pages, Services, Team, Testimonials, News, Jobs, Downloads, Settings
- Submission modules:
  - Contact submissions, Referral submissions, Job applications
- Utility modules:
  - SEO metadata, Media library, User/role management

## Routing and Rendering
- Public routes in `routes/web.php`.
- Use route-model binding for content details (e.g., news slug).
- Keep route names stable for SEO and CMS link management.
- Render content through Blade pages with reusable components.
- Render Contact page map from settings table (`contact_map_embed_url`) and sanitize/validate URL format in admin form request.

## Form Architecture
- Use Form Request classes for validation.
- Anti-spam and security:
  - CSRF
  - honeypot
  - rate limiting by IP
- File upload rules:
  - strict MIME whitelist
  - max file sizes
  - secure storage path
- Persist all submissions and expose in Filament inbox resources.

## SEO and Performance Architecture
- Per-page meta and OG data stored in CMS.
- Auto XML sitemap generation.
- `robots.txt` configured to disallow admin paths.
- JSON-LD structured data on key pages.
- Image optimization pipeline on upload.
- Production caching:
  - `config:cache`
  - `route:cache`
  - `view:cache`

## Security Baseline
- Enforce HTTPS redirect.
- Secure admin authentication for `/admin`:
  - email + strong password policy (minimum length and complexity)
  - login rate limiting and lockout/backoff on repeated failures
  - CSRF protection on all auth and admin actions
  - session timeout with secure cookie settings (`httpOnly`, `secure`, `sameSite`)
  - optional 2FA for Super Admin accounts (recommended for production)
- Role-based access control for admin (`Super Admin`, `Editor`) via policies/permissions.
- Server-side validation and sanitization on all inputs.
- Session timeout and secure auth config.
- Store secrets in environment variables only.

## Environment Strategy
Two environments must exist at minimum:

### Dev (Local)
- URL example: `http://hillcrestlivingltd.test` or `http://localhost:8000`
- Debug enabled
- Local mail catcher or SMTP sandbox
- Fast feedback loop with Vite HMR

### Live (Production)
- Domain: `https://hillcrestlivingltd.co.uk`
- Debug disabled
- Real SMTP via cPanel mail
- Optimized cache and compiled assets only
- Strict permissions and backup policy enabled

## Environment Configuration Baseline
Manage settings via `.env` per environment:

- App: `APP_NAME`, `APP_ENV`, `APP_DEBUG`, `APP_URL`
- DB: `DB_*`
- Mail: `MAIL_*`
- Filesystem: `FILESYSTEM_DISK`
- Queue/cache/session drivers
- Optional feature flags for staged launches

Never commit production secrets to version control.

## Dev Workflow
1. Pull latest branch.
2. Install dependencies (`composer install`, `npm install`).
3. Set `.env`, generate key, migrate DB.
4. Run local server and Vite dev process.
5. Build feature by module with tests/checks.
6. Update docs (`DEVELOPMENT_GUIDELINES.md`, this runbook, and style guide) for any scope changes.

## Command Playbook (Copy/Paste Ready)
Use this as the default operator flow for local development.

### Initial Setup (First Time)
```bash
composer install
npm install
cp .env.example .env
php artisan key:generate
php artisan migrate
php artisan storage:link
```

### Start Development
Run these in separate terminals:
```bash
php artisan serve
```
```bash
npm run dev
```

### Useful Day-to-Day Commands
```bash
php artisan migrate
php artisan db:seed
php artisan optimize:clear
php artisan test
```

### Production-Oriented Build Check (Local)
```bash
npm run build
php artisan config:cache
php artisan route:cache
php artisan view:cache
```

### If Something Breaks (Safe Reset Helpers)
```bash
php artisan optimize:clear
php artisan config:clear
php artisan cache:clear
php artisan view:clear
```

Notes:
- Always run commands from the project root.
- If a command fails, capture the exact error output and resolve before continuing.
- Prefer explicit, repeatable commands over manual UI-only steps.

## Deployment Workflow (cPanel)
1. Deploy code to server.
2. Install PHP dependencies.
3. Set production `.env`.
4. Run migrations with `--force`.
5. Build/upload frontend assets.
6. Run storage link and cache commands.
7. Smoke test forms, CMS login, and key pages.

## Documentation Governance
When new requirements come in:
1. Update [DEVELOPMENT_GUIDELINES.md](DEVELOPMENT_GUIDELINES.md) for scope/context.
2. Update [BRAND_STYLE_GUIDE.md](BRAND_STYLE_GUIDE.md) if visual system changes.
3. Update this runbook if architecture or operational flow changes.
4. Add dated entry in each modified document's version section.

## Version History
- `2026-05-03`: Initial architecture runbook created; includes theming strategy, folder standards, and dev/prod environment model.
- `2026-05-03`: Added proposed database schema table list, relationships, indexing, migration order, and seed strategy.
- `2026-05-03`: Added copy/paste command playbook for non-PHP operators and repeatable dev workflow execution.
- `2026-05-05`: Added mandatory vertical-slice implementation strategy requiring parallel delivery of admin CMS and public site per feature.
