# Raj Group website architecture

## Application structure

```text
app/
  Config/Routes.php, Filters.php, App.php, Database.php
  Controllers/Home.php, Site.php, Enquiry.php, Admin.php
  Controllers/Admin/Content.php, Media.php
  Filters/AdminAuth.php
  Models/ContentRecordModel.php, EnquiryModel.php, AdminUserModel.php
  Database/Migrations/, Seeds/
  Views/layout.php
  Views/partials/head.php, header.php, navbar.php, footer.php
  Views/components/solution-card.php
  Views/pages/ (public pages, developed incrementally)
  Views/admin/layout.php, partials/sidebar.php, content/, media.php
public/assets/css/site.css, home.css, admin.css, admin-panel.css
public/assets/js/site.js
public/assets/img/
public/uploads/ (validated admin uploads)
writable/ (CI4 logs, cache, sessions)
```

The public master layout owns the document head, header, navigation, main landmark, footer and scripts. Each public page extends it and provides a `content` section. Admin has its own layout and sidebar so admin assets and navigation stay separate. The homepage solution cards are rendered from one component. Existing solution URLs are preserved.

## MySQL data model

| Table | Purpose | Main relationships |
| --- | --- | --- |
| `admin_users` | Hashed-password admin accounts | Unique email |
| `content_pages` | Editable page content and SEO | Unique slug |
| `brands` | Raj Cooling, Kiozy+, Agreyas | Unique slug |
| `products` | Product content and specifications | Optional `brand_id` to brands |
| `industries` | Industry content | Unique slug |
| `product_industries` | Many-to-many product applications | Foreign keys to products and industries |
| `articles` | Blog posts | Unique slug, publication date |
| `media_assets` | Uploaded image metadata and alt text | Path into `public/uploads` |
| `enquiries` | Contact requests and consent timestamp | Email and created date indexed |

Content records share title, slug, excerpt, plain-text body, image path, status, ordering, SEO title/description and timestamps. Admin records are draft until published. Use `php spark migrate` for schema creation; seed the three brands with `php spark db:seed BrandSeeder`. Do not import `database/rajgroup_mysql.sql` into the same database as migrations: it is a legacy starter schema with a different shape.

## Routes

| URL | Handler |
| --- | --- |
| `/` | `Home::index` |
| `/about`, `/brands`, `/solutions`, `/industries`, `/global-business`, `/contact` | `Site::page` |
| `/solution-{slug}` | `Site::page`, allowed solution slugs only |
| `POST /enquiry/send` | `Enquiry::send` |
| `/admin/login`, `POST /admin/login`, `POST /admin/logout` | Admin authentication |
| `/admin` | Enquiry dashboard |
| `/admin/content/{pages,products,industries,brands,blogs}` | Content management |
| `/admin/media` | Image library |

POST requests are CSRF protected globally. Content and media routes use `AdminAuth`; auto routing is disabled. `/home` and `/index.php` redirect to `/`. The next page-by-page phase should bind published database content to public detail routes and migrate any historical URLs into explicit 301 redirects.

## Release checks

Run `php spark migrate`, seed the admin user through environment variables, confirm the database connection, then test the homepage, contact form, admin login and uploads under the real web server. The PHP CLI needs the `intl` extension enabled. Set the document root to `public/`, use HTTPS in production, and keep `.env` outside version control. Review image rights and final company claims before launch.

For this XAMPP workspace, `deployment/run-local.ps1` runs the local site at `http://127.0.0.1:8087/` using the separate `rajgroup_local` database. It loads `deployment/local-env.php` with PHP's `auto_prepend_file`; production `.env` values are not changed.
