# Public Site ESM Snapshot Task

## Goal

Implement a normal data delivery pipeline for `bent.ge` public pages where marketing and editorial content is not requested from Laravel at runtime.

Backend must generate importable frontend modules for Nuxt so the site can use:

```js
import { reviewsPage, reviewItems } from '~/generated/site/reviews'
import { vehiclesIndex } from '~/generated/site/vehicles/index'
```

instead of:

- runtime `GET /public-site/export/...`
- frontend-side `fetch` for static content
- large hand-maintained `app/data/*` files

The result must be fast, deterministic, and cleanly structured.

## Core Rule

Do not solve this with one giant JSON blob loaded at runtime.

Required approach:

- backend remains source of truth
- backend generates build-time snapshot files
- Nuxt imports those files directly as ESM modules
- runtime API stays only for transactional flows

## Why

Current public site has two different data modes:

- static or semi-static content:
  - pages
  - offers
  - reviews
  - services
  - locations
  - FAQ
  - articles
  - route page content
  - vehicle marketing content
- live transactional data:
  - search results with availability
  - quote calculation
  - booking creation
  - checkout
  - request submission

The first group should not hit backend per page render.
The second group must stay live.

## Required Result

### Static content

Laravel must generate ESM files into a target directory that Nuxt can import directly.

Example target during local development:

`/Volumes/Dev/apps/bent.ge/frontend/app/generated/site`

Later in production the same export must write into the deployed frontend project path on the server.

The target path must be configurable.
Do not hardcode environment-specific paths inside domain/export service code.

### Live content

These flows remain API-based and must not be frozen into snapshot files:

- `public-catalog`
- `public-catalog/quote`
- `public-booking`
- `public-booking/{token}`
- `public-booking/{token}/checkout`
- `public-requests`

## Important Dev Constraint

Right now backend exists only on live server and frontend exists only on local Mac.

Because of that, development workflow must support files ending up here locally:

`/Volumes/Dev/apps/bent.ge/frontend/app/generated/site`

Important technical note:

Live Laravel cannot safely write directly into a local macOS path unless that path is mounted remotely.
So the practical dev workflow should be:

1. Live backend generates snapshot into a configurable export directory on the server.
2. A local sync step copies the generated files from live server to the Mac frontend path.

This is still acceptable because:

- frontend runtime will use direct imports
- there will be no content fetch requests from Nuxt pages
- local development remains fast

## Required Architecture

### 1. Keep `PublicSiteExportService` as payload builder

Current file:

`backend/app/Support/PublicSite/PublicSiteExportService.php`

This service should remain responsible for normalized public payload preparation only.

It must not become a messy mix of:

- payload building
- path decisions
- file serialization details
- transport logic

### 2. Introduce separate writers

Add dedicated writers, for example:

- `PublicSiteJsonWriter`
- `PublicSiteEsmWriter`

Responsibilities:

- `PublicSiteExportService`
  - build normalized arrays
- `PublicSiteJsonWriter`
  - write JSON artifacts
- `PublicSiteEsmWriter`
  - write importable `.js` modules for Nuxt

### 3. Extend artisan export command

Current command:

`backend/app/Console/Commands/SiteExportCommand.php`

Required behavior:

- support `--format=json`
- support `--format=esm`
- support `--format=all`
- support configurable target root via `--path=...`
- write files atomically
- clear outdated generated files before writing new ones

Suggested examples:

```bash
php artisan site:export --format=esm --path=/tmp/bent-site-export
php artisan site:export --format=all --path=/home/ontripge/domains/.../generated/site
```

## Required Output Structure

Do not generate one huge module.
Split output by section and by route responsibility.

Suggested structure:

```text
frontend/app/generated/site/
  meta.js
  home.js
  offers.js
  services.js
  reviews.js
  faq.js
  locations.js
  pages.js
  route-pages.js
  relationships.js
  image-index.js
  vehicles/
    index.js
    by-slug.js
  news/
    index.js
    by-slug.js
  guides/
    index.js
    by-slug.js
```

If needed later, detail modules may also be split further:

```text
vehicles/items/<slug>.js
news/items/<slug>.js
guides/items/<slug>.js
```

But do not over-split without need.

## Output Format Rules

Generated files must be plain ESM JavaScript modules.

Do not generate TypeScript.

Preferred export style:

```js
export const generatedAt = '2026-04-01T00:00:00Z'
export const reviewItems = [ ... ]
export const reviewsPage = { ... }
```

Avoid default exports unless there is a strong reason.

Generated modules must be deterministic:

- stable key order
- stable array order
- stable formatting
- no random hashes in filenames

## Meta File

Generate one shared metadata file, for example `meta.js`, containing at minimum:

- `generatedAt`
- `source`
- `formatVersion`
- section counts
- optional content checksum/hash

This is needed for debugging and deployment validation.

## Atomic Write Rules

Generated output must not leave half-written files.

Required behavior:

1. write into temporary directory
2. validate generated output
3. replace target directory atomically as much as possible

At minimum:

- write temp files first
- rename into final location only after successful generation

## What Must Move To Snapshot

The following public-facing content should be available from generated imports:

- home page content
- offers
- services
- reviews
- FAQ
- locations
- public pages and route pages
- guides and news content
- luxury fleet marketing data
- vehicle presentation data for listing/detail pages where content is not availability-dependent
- redirect map
- relationships map
- image index

## What Must Stay Live

The following must continue to come from backend API at runtime:

- catalog availability for chosen dates
- quote calculation
- booking creation
- checkout session creation
- booking lookup
- request submission

Do not degrade transactional accuracy in the name of static speed.

## Nuxt Integration Target

Frontend must consume generated files from:

`frontend/app/generated/site`

Code should then migrate from runtime fetch to static import for content pages.

Examples of expected migration targets:

- `usePublicSiteLocations.js` should stop requesting `public-site/export/locations` for page content use cases
- public page/article/review/offers/luxury/news/fleet content should use generated imports

If a composable remains, it should become a thin accessor over generated modules, not an HTTP client.

## Dev Workflow Requirement

Because backend is live-only and frontend is local-only, support this workflow:

### Server side

Live Laravel command generates snapshot into temporary export directory on the server, for example:

`/home/ontripge/domains/api.hub.bent.ge/storage/app/site-export-esm`

### Local side

Mac pulls snapshot into:

`/Volumes/Dev/apps/bent.ge/frontend/app/generated/site`

Suggested wrapper flow:

1. local machine triggers remote `php artisan site:export --format=esm --path=...`
2. local machine `rsync` or `scp` pulls generated files
3. local Nuxt dev server reloads using imported modules

This may later be replaced by direct same-server export in production.

## Production Workflow Requirement

When frontend is deployed on server, export path must switch to the deployed frontend generated directory.

Same export command must work without code changes.

Only config/path changes are allowed.

## Non-Goals

This task does not replace:

- live pricing engine
- live booking flow
- live checkout flow
- live request submission

This task is about static public content delivery only.

## Acceptance Criteria

Task is done only when all of the following are true:

1. Laravel can generate ESM snapshot files for public site content.
2. Export target path is configurable.
3. Output is split by section, not one giant module.
4. Generated files are valid direct imports for Nuxt.
5. Static public pages can stop requesting Laravel content endpoints at runtime.
6. Transactional flows remain live.
7. Dev workflow supports live-backend-to-local-frontend sync.
8. Production workflow supports same-server export later.
9. Generated output is deterministic and written atomically.

## Suggested Implementation Order

1. Refactor export into payload builder + writers.
2. Add `ESM` writer.
3. Extend `site:export` command with format/path options.
4. Generate `meta.js`, `home.js`, `locations.js`, `reviews.js`, `offers.js`, `services.js`.
5. Generate `vehicles/*`, `news/*`, `guides/*`, `pages.js`, `route-pages.js`.
6. Add local sync wrapper for dev workflow.
7. Move Nuxt content pages from fetch/manual data files to generated imports.

## Explicit Anti-Patterns

Do not do any of the following:

- do not keep calling `GET /public-site/export/...` from Nuxt page runtime
- do not dump one multi-megabyte `public-export.js` and import it everywhere
- do not hardcode macOS path directly into domain service code
- do not mix transactional booking data into static snapshot files
- do not solve local dev by adding frontend fake fallbacks instead of real exported content

