# THIS YOU — DEV SPEC
## Personalized Sponsored Ad + Locked 32-page Skeleton
### Target current reference build: `personalized_magazine_engine_v1_4`

---

# 0. PURPOSE

Integrate the newly approved editorial structure into the existing THIS YOU engine without creating a second advertising subsystem.

The current engine already stores:
- shared issue pages in `issue_pages`,
- reader-specific overrides in `user_issue_pages`,
- reader-specific products in `user_issue_products`,
- page personalization modes as `shared / personalized / hybrid`,
- reusable layouts selected by `layout_key`,
- human review state per personalized page.

Use those existing primitives.

Do **not** build a separate “personalized ads engine”.

---

# 1. LOCKED DEFAULT 32-PAGE SKELETON

Update the default issue skeleton to:

```text
01 cover                         personalized
02 concept / how it works       shared
03 editor letter / issue intro  shared
04 contents / city map          shared

05 story                         shared
06 scene                         shared
07 moment / arrival              hybrid
08 style                         personalized

09 story                         shared
10 scene                         shared
11 moment / arrival              hybrid
12 style                         personalized

13 story                         shared
14 scene                         shared
15 moment / arrival              hybrid
16 style                         personalized

17 story                         shared
18 scene                         shared
19 moment / arrival              hybrid
20 style                         personalized

21 story                         shared
22 scene                         shared
23 moment / arrival              hybrid
24 style                         personalized

25 story                         shared
26 scene                         shared
27 moment / arrival              hybrid
28 style                         personalized

29 style summary                 personalized
30 sponsored ad                  hybrid
31 next issue / credits          shared
32 Absurd.website back cover     shared
```

Important changes from current v1.4 default:
- remove the old opening Moment / Style from pages 03–04,
- page 03 becomes shared editor letter / issue intro,
- page 04 becomes shared contents / city map,
- page 30 changes from `house_ad` to `sponsored_ad`,
- page 32 remains back cover but is editorially reserved for Absurd.website.

The engine must still support non-32-page issues. Do not hard-code `32` into runtime rendering.

---

# 2. STORY / INTERVIEW RULE — NO NEW SYSTEM REQUIRED

The editorial `STORY` slot is flexible.

A STORY can be:
- article,
- essay,
- interview,
- Q&A,
- profile,
- feature,
- fiction,
- other editorial input.

For MVP, do **not** add a new DB table for interviews.

Recommended implementation:

```text
page_type = story
layout_key = story-editorial-01
```

or, when a dedicated interview design is needed:

```text
page_type = story
layout_key = story-interview-01
```

Add new layout only when needed:

```text
/layouts/story/story-interview-01.php
```

Register it in `layout_registry()` in `/lib/issues.php`.

This keeps the fixed chapter grammar while allowing real interviews.

If a long interview needs a second page, use the SCENE page as a visually edited continuation:
- portrait,
- pull quote,
- selected Q&A continuation,
- objects,
- track,
- image-led continuation.

If truly more pages are required, increase issue page count / add an editorial insert. Do not delete Arrival/Style pages to make room.

---

# 3. SCENE IS PROTECTED

Do not allow the standard issue creator to replace a chapter SCENE page with an ad.

Every standard chapter remains:

```text
STORY
SCENE
MOMENT / ARRIVAL
STYLE
```

Ads live outside the six chapters.

This is an editorial rule, not merely a design preference.

---

# 4. NEW PAGE TYPE: `sponsored_ad`

Add a logical page type:

```text
sponsored_ad
```

Recommended page record for page 30:

```text
page_type = sponsored_ad
layout_key = sponsored-personalized-ad-01
personalization_mode = hybrid
chapter_id = NULL
```

Do not use `style` as the page type.

The page is an ad, even though it uses personalized image generation.

---

# 5. NEW LAYOUT

Create:

```text
/layouts/ad/sponsored-personalized-ad-01.php
```

Register in:

```text
/lib/issues.php
→ layout_registry()
```

The layout should support:

## Shared campaign layer
- `SPONSORED` / `ADVERTISEMENT` disclosure
- sponsor logo
- sponsor name
- product name
- shared campaign headline
- shared campaign body / tagline
- product CTA
- product URL
- optional price
- product reference image / detail image
- shared art direction

## Personalized layer
- reader-specific hero image from `user_issue_pages.hero_image`
- optional `personal_title`
- optional `personal_subtitle`

The ad should remain visually premium and magazine-like.

Do not render normal STYLE-page:
- WHY IT WORKS,
- STYLE NOTES,
- look reactions,
- product reactions.

Advertising should not masquerade as editorial styling.

---

# 6. USE EXISTING TABLES — MVP NEEDS NO NEW AD TABLE

For the MVP, avoid premature schema complexity.

## Shared sponsor/campaign data
Store in the page 30 `issue_pages` row.

Use:
- normal page fields for title/subtitle/body,
- `image_asset` where useful,
- `data_json` for campaign metadata.

Recommended `data_json`:

```json
{
  "ad_type": "personalized_sponsor",
  "disclosure_label": "SPONSORED",
  "sponsor_name": "Egretta Garzetta",
  "brand_logo_asset": "page-30-sponsor-logo.svg",
  "campaign_name": "Autumn Shawl",
  "product_id": 123,
  "product_name": "Kid Mohair Shawl",
  "product_url": "https://...",
  "cta_label": "DISCOVER",
  "price": null,
  "currency": null,
  "product_reference_assets": [
    "page-30-product-reference-01.jpg"
  ],
  "shared_headline": "ONE PIECE. YOUR WAY.",
  "shared_copy": "...",
  "creative_direction": "Editorial autumn New York...",
  "generation_constraints": {
    "product_must_be_visible": true,
    "preserve_product_identity": true,
    "reader_identity_required": true
  }
}
```

If the product exists in the shared `products` table, prefer `product_id` as the canonical reference and keep page JSON as campaign configuration.

No new `issue_ads` table is necessary for the first production version.

Future:
- if campaigns need scheduling,
- advertiser accounts,
- many SKUs,
- billing,
- impressions/click reporting,
then introduce dedicated advertiser / campaign tables with a migration.

---

# 7. PERSONALIZED AD OUTPUT

Reuse `user_issue_pages`.

For page 30, create one row per reader:

```text
user_issue_id
issue_page_id = page 30 issue_page id
hero_image = generated personalized sponsor image
personal_title = optional
personal_subtitle = optional
generation_prompt
generation_data_json
review_status
reviewed_by
reviewed_at
```

Do not duplicate the shared sponsor campaign copy into every `user_issue_pages` row.

Shared campaign = `issue_pages`.

Reader-specific creative = `user_issue_pages`.

This preserves the existing architecture.

---

# 8. SPONSORED PRODUCT MODEL

Default rule:

> **The advertised product is shared; the way the reader wears / inhabits it is personalized.**

Example:
- same Egretta Garzetta shawl in every copy,
- different reader,
- different styling interpretation,
- same sponsor CTA.

For MVP:
- reference the shared product from `products`,
- render the sponsor product link from the shared campaign config.

Do not create six reader-specific outfit products for this page unless the campaign actually needs them.

Future optional mode:
- if sponsor allows a different product / color / SKU per reader,
- use `user_issue_products` attached to the sponsored page,
- use a clear slot such as:

```text
slot_name = sponsored_product
```

This is not required for v1.

---

# 9. GENERATION PIPELINE

Current generation lives in:

```text
/lib/generation.php
```

Current `generate_user_issue()` must be taught that `sponsored_ad` is a personalized target.

Add a dedicated branch / handler.

Recommended conceptual functions:

```php
generation_sponsored_ad_context(...)
generation_sponsored_ad_prompt(...)
generation_sponsored_ad_output(...)
```

Do not force sponsored ads through normal STYLE copy generation.

Input should combine:

```text
reader profile
+ reader photos
+ optional learned style context
+ sponsor campaign data
+ exact sponsor product reference(s)
+ issue art direction
+ page layout requirements
```

Important difference from an Arrival:

```text
Arrival:
reader + Moment + fashion direction

Sponsored Ad:
reader + sponsor product + campaign art direction
```

The sponsor product is not optional.

---

# 10. GENERATED IMAGE REQUIREMENTS

The sponsor hero image should satisfy:

1. reader identity is recognizable,
2. reader body proportions remain believable,
3. advertised product is clearly visible,
4. product color / shape / key construction details are preserved as closely as the generation workflow allows,
5. image matches the issue art direction,
6. image does not imply a different SKU or material,
7. no invented sponsor logos,
8. final image is human-reviewed before print.

For early campaigns, the editor should provide:
- 1–3 clean product reference images,
- brand logo asset,
- product name,
- product URL,
- campaign direction.

Egretta Garzetta can be the first test campaign, but the system must never hard-code that brand name.

---

# 11. REVIEW GATE

The sponsored personalized ad is a required personalized page.

It must appear in the same human review workflow as:
- cover,
- arrivals,
- style pages,
- style summary.

Required states remain:

```text
not_generated
generated
needs_review
approved
rejected
```

`update_user_issue_ready_state()` should not allow the reader issue to become ready while page 30 is missing or unapproved.

The current code map says readiness is based on required non-shared pages. Verify that this is mode-based.

If current code instead contains a hard-coded page-type allowlist, add:

```text
sponsored_ad
```

to that required set.

---

# 12. GENERATION JOBS

Use existing `generation_jobs`.

Recommended job type:

```text
generate_sponsored_ad
```

Optional split later:

```text
build_sponsored_ad_context
generate_sponsored_ad_image
```

MVP can use one job.

Save:
- campaign input,
- reader input reference,
- output metadata,
- error state.

---

# 13. ADMIN — SHARED PAGE EDITOR

For a `sponsored_ad` page, admin should expose clear campaign fields instead of requiring the editor to remember raw JSON.

Minimum fields:

```text
Disclosure label
Sponsor name
Sponsor logo
Campaign name
Shared headline
Shared copy
Product
Product URL / CTA
Product reference image(s)
Creative direction
Generation constraints / notes
```

The initial implementation may store them into `data_json`.

Important:
the admin UI can be better than the DB schema.

Do not create DB columns merely because they are convenient form labels.

---

# 14. ADMIN — READER PERSONALIZED PAGE

On reader generation/review screens, page 30 should be shown as:

```text
SPONSORED PERSONALIZED AD
Sponsor: [brand]
Product: [product]

SHARED CAMPAIGN
----------------
headline
campaign brief
product references

[READER] — PERSONALIZED CREATIVE
----------------
hero image
optional personal title
optional personal subtitle
generation notes
review status
```

Actions:
- Generate
- Replace image
- Edit optional copy
- Approve
- Reject

Do not show normal styling product-selection UI unless the campaign uses reader-specific sponsored products.

---

# 15. FEEDBACK / MEMORY RULE

Do **not** use normal look feedback controls on the sponsored ad by default.

Reason:
- “I dislike this ad/product” is not the same signal as
- “this silhouette is not me”.

Therefore sponsored-ad interaction should not contaminate `reader_feedback_memory()`.

MVP:
- no ♥ / × / $ / + controls on page 30.

Future:
- track ad interactions separately:
  - CTA click,
  - product click,
  - share,
  - optional ad-specific preference.

That should be a separate analytics layer.

---

# 16. DIGITAL CTA

Page 30 digital edition can have:

```text
DISCOVER ↗
SHOP ↗
VIEW PRODUCT ↗
```

Use campaign-specific CTA.

The link belongs to the shared campaign.

Guest/public preview may also see the sponsor CTA.

Owner-only feedback remains absent for the ad.

---

# 17. PRINT

The print renderer should use the exact same page record and reader override:

```text
shared campaign page
+ approved reader hero image
→ print page 30
```

No special second print system.

Ensure:
- disclosure remains visible in print,
- logo remains sharp,
- sponsor URL/QR is readable,
- generated image uses approved print asset,
- no web-only controls render.

---

# 18. BACK COVER — ABSURD.WEBSITE

Page 32 is reserved editorially for the publisher.

Recommended:

```text
page_type = back_cover
layout_key = back-absurd-01
personalization_mode = shared
```

Create a new layout only if the existing back cover cannot represent the desired ad cleanly:

```text
/layouts/back/back-absurd-01.php
```

Shared `data_json` can contain:

```json
{
  "publisher_ad": "absurd.website",
  "mode": "practice",
  "project_name": null,
  "headline": "...",
  "body": "...",
  "url": "https://absurd.website/",
  "image_asset": "..."
}
```

or:

```json
{
  "publisher_ad": "absurd.website",
  "mode": "project",
  "project_name": "PARAD.AI.SE",
  "headline": "...",
  "body": "...",
  "url": "...",
  "image_asset": "..."
}
```

This page is shared and does not enter generation/review for every reader beyond normal shared editorial review.

---

# 19. UPDATE `create_standard_issue()`

File:

```text
/lib/issues.php
```

Change the default page map created by `create_standard_issue()`.

Old v1.4 opening:

```text
01 cover
02 concept
03 opening moment / arrival
04 opening style
```

New:

```text
01 cover
02 concept
03 editor letter / issue intro
04 contents / city map
```

Old closing:

```text
29 style summary
30 house ad
31 next issue / credits
32 back cover
```

New:

```text
29 style summary
30 sponsored ad
31 next issue / credits
32 Absurd.website back cover
```

Do not change already published issues automatically.

For AUTUMN/WINTER development records, explicitly update/reset those issue page rows as appropriate because they are current working issues, not historical published artifacts.

---

# 20. PAGE TYPE / LAYOUT REGISTRY

File:

```text
/lib/issues.php
```

Add:

```text
sponsored_ad
```

to page-type/admin choices if they are enumerated in code.

Register:

```text
sponsored-personalized-ad-01
```

under `/layouts/ad/`.

If page types are free-form strings, no migration is necessary.

---

# 21. DATABASE MIGRATION DECISION

Preferred MVP implementation requires **no schema migration** because:
- `issue_pages.page_type` is string-based,
- `personalization_mode = hybrid` already exists,
- `data_json` already exists,
- `user_issue_pages` already supports hero image + generated metadata,
- `generation_jobs.job_type` is string-based,
- products table already exists.

Do not add a migration just to create a new logical page type.

Only add a migration if inspection of the actual code/database reveals an enum/check constraint not documented in the current code map.

If a migration is required, add a new migration version in `/lib/migrations.php`; never rewrite migration 1.

---

# 22. RENDERER

File:

```text
/lib/renderer.php
```

The renderer already resolves:
- shared page,
- personalized page context,
- layout key.

The sponsored ad should follow the same resolution path.

Do not create:

```text
sponsored-ad.php?user=...
```

or a parallel endpoint.

Expected:

```text
issue page 30
→ renderer loads shared campaign
→ renderer loads current reader page override
→ sponsored ad layout renders both
```

---

# 23. PUBLIC / OWNER MODES

Sponsored ad should render in:
- owner edition,
- public/shared preview if that page is visible,
- print.

Public preview behavior:
- use the demo/public reader override if the preview is reader-specific,
- otherwise provide a deliberately selected campaign demo image.

Do not expose private reader identity/assets in a generic public issue preview.

---

# 24. ASSET FOLDERS

Recommended shared campaign assets:

```text
assets/uploads/issues/issue-001/shared/page-30/
```

Examples:

```text
sponsor-logo.svg
product-reference-01.jpg
product-reference-02.jpg
campaign-detail.jpg
```

Reader generated assets:

```text
assets/uploads/generated/issue-001/user-0047/sponsored-ad/
```

Examples:

```text
sponsored-ad-v1-master.jpg
sponsored-ad-approved-master.jpg
sponsored-ad-web.webp
sponsored-ad-print.jpg
```

Back cover shared assets:

```text
assets/uploads/issues/issue-001/shared/page-32/
```

---

# 25. PERSONALIZATION WORKFLOW UPDATE

The personalized target list becomes:

```text
A. COVER
B. 6 × MOMENT / ARRIVAL
C. 6 × STYLE
D. STYLE SUMMARY
E. SPONSORED PERSONALIZED AD
```

The sponsored ad has a different context package from a normal Arrival.

Recommended manual ChatGPT package:

```json
{
  "page_type": "sponsored_ad",
  "reader": { "...": "..." },
  "issue": {
    "city": "New York",
    "season": "Autumn 2026",
    "art_direction": "..."
  },
  "campaign": {
    "sponsor": "Egretta Garzetta",
    "product": "Kid Mohair Shawl",
    "product_reference_assets": ["..."],
    "shared_headline": "ONE PIECE. YOUR WAY.",
    "creative_direction": "...",
    "constraints": [
      "keep product visually recognizable",
      "reader identity must be recognizable",
      "do not invent another product"
    ]
  }
}
```

Output:

```json
{
  "personal_title": null,
  "personal_subtitle": null,
  "image_brief": "...",
  "generation_notes": "...",
  "hero_image": "..."
}
```

Copy can remain entirely shared if desired.

---

# 26. SHARED ISSUE WORKFLOW UPDATE

When building each issue, the shared package must now also define:

```text
Sponsor for page 30
Sponsor product
Sponsor campaign direction
Sponsor product reference assets
Sponsor CTA / URL
Sponsor disclosure

Absurd.website back-cover mode:
- practice
or
- specific project
```

This happens during shared issue creation because the campaign shell is shared.

The reader-specific sponsor image is generated later during personalization.

---

# 27. TESTS TO ADD / UPDATE

Update:

```text
/tests/render_layouts.php
/tests/static_checks.php
```

Required checks:

1. `sponsored-personalized-ad-01` renders with shared campaign only.
2. It renders with reader `hero_image`.
3. It does not fatal when optional personal title is null.
4. Disclosure is visible.
5. CTA renders only when URL exists.
6. No normal style reactions render.
7. Page 30 appears in owner edition.
8. Page 30 appears correctly in print.
9. Page 30 is included in readiness gate.
10. Missing/unapproved page 30 prevents READY.
11. Page 32 is shared and never gets a reader override in standard generation.
12. public preview never leaks another reader's sponsor hero image.
13. page count remains dynamic.
14. old published issue layouts remain untouched.

---

# 28. ISSUE 01 / AUTUMN IMPLEMENTATION

For the first AUTUMN issue:

Page 30 campaign:
- sponsor: **Egretta Garzetta**
- product: selected shawl
- generated individually for every reader
- final campaign copy/art direction still editorially defined before generation.

Important:
this is seed/content data only.

Do **not** hard-code:

```php
if ($issue_id === 1) sponsor = Egretta...
```

WINTER or later issues must be able to use another brand without code changes.

Page 32:
- Absurd.website practice or selected Absurd.website project.
- shared for all AUTUMN readers.

---

# 29. DEFINITION OF DONE

This change is done when:

- new issues start with the approved 32-page skeleton,
- pages 03–04 are shared editorial pages,
- all six SCENE pages always exist,
- STORY can use an interview-specific layout without changing the data model,
- page 30 can hold any sponsor,
- page 30 generates a unique approved hero image per reader,
- same sponsor product/campaign remains shared across the issue,
- sponsored page is clearly disclosed,
- sponsored page does not train style feedback,
- page 30 blocks issue readiness until approved,
- page 32 is always the shared Absurd.website back cover in the standard skeleton,
- Egretta Garzetta is content, not hard-coded logic,
- existing multi-issue behavior remains intact,
- existing published issues are not silently modified.

---

# 30. HANDOFF SUMMARY

Implement the sponsored personalized ad as a normal THIS YOU **hybrid page**.

Do not create a separate ads engine.

Use:

```text
issue_pages
    shared sponsor campaign
        +
user_issue_pages
    reader-specific hero image
        ↓
layouts/ad/sponsored-personalized-ad-01.php
        ↓
digital + print
```

The new advertising product is conceptually:

> **The brand owns the product. THIS YOU styles how each reader enters the campaign.**

The publisher back cover remains separate:

> **Page 30 = personalized sponsor**  
> **Page 32 = Absurd.website**
