# PERSONALIZED MAGAZINE — SYSTEM ARCHITECTURE
## Technical build specification for multi-issue publishing, personalization, admin, digital and print

---

# 0. PURPOSE

Build **one magazine publishing engine** that can contain and publish many issues:

- MAGAZINE 01
- MAGAZINE 02
- MAGAZINE 03
- ...

Each issue has:

1. **shared editorial content**
   - STORY
   - SCENE
   - THE MOMENT
   - interviews
   - art
   - music
   - ads
   - credits
   - other shared magazine pages

2. **personalized style slots**
   - personalized cover
   - YOUR ARRIVAL
   - THE STYLE
   - reader-specific products
   - WHY IT WORKS
   - STYLE NOTES
   - reader feedback

The core concept is:

> **Shared magazine. Personalized arrivals.**

And:

> **The event belongs to the magazine. The outfit belongs to the reader.**

The system must let us build a new issue **without breaking old issues or changing the core engine**.

---

# 1. HIGH-LEVEL SYSTEM

```text
                         MAGAZINE ENGINE
                               │
            ┌──────────────────┼──────────────────┐
            │                  │                  │
       MAGAZINE 01        MAGAZINE 02        MAGAZINE 03
       NY / SUMMER        AUTUMN / ...       WINTER / ...
            │                  │                  │
      shared pages        shared pages        shared pages
      + moments           + moments           + moments
            │                  │                  │
      personalized       personalized       personalized
      reader pages       reader pages       reader pages
```

A reader exists independently of an issue.

```text
READER PROFILE
      ↓
MAGAZINE 01
      ↓
reactions + comments + purchases
      ↓
MAGAZINE 02 generation
      ↓
new reactions
      ↓
MAGAZINE 03 generation
```

The reader gets better styling over time.

---

# 2. CORE RULE: ENGINE ≠ ISSUE

Never create a new PHP project for every magazine.

The application should have:

```text
/core
/layouts
/themes
/admin
/renderers
/generation
/assets
```

The code is reusable.

Each issue is primarily:

```text
ISSUE DATA
+
PAGE ORDER
+
LAYOUT CHOICES
+
THEME
+
SHARED CONTENT
+
PERSONALIZED SLOTS
```

Therefore creating Magazine 02 should normally require **new data and optional new layout components**, not rewriting Magazine 01.

---

# 3. MAIN DATA MODEL

Recommended core entities:

```text
users
user_profiles
user_photos

issues
issue_chapters
issue_pages

user_issues
user_issue_pages
user_issue_products

products

reactions
comments

generation_jobs
review_log

share_links
```

Optional later:

```text
orders
subscriptions
affiliate_clicks
assets
contributors
advertisers
issue_ads
playlists
artworks
```

---

# 4. ISSUES TABLE

Each magazine issue is one record.

```sql
CREATE TABLE issues (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

    issue_number INT UNSIGNED NOT NULL,
    slug VARCHAR(160) NOT NULL UNIQUE,

    title VARCHAR(255) NOT NULL,
    subtitle VARCHAR(255) NULL,

    season VARCHAR(50) NULL,
    issue_year SMALLINT UNSIGNED NULL,

    theme_name VARCHAR(255) NULL,

    status ENUM(
        'draft',
        'editorial_review',
        'published',
        'archived'
    ) NOT NULL DEFAULT 'draft',

    cover_title VARCHAR(255) NULL,
    cover_subtitle VARCHAR(255) NULL,

    intro_text TEXT NULL,

    theme_key VARCHAR(100) NULL,
    theme_settings_json LONGTEXT NULL,

    page_count INT UNSIGNED NOT NULL DEFAULT 32,

    published_at DATETIME NULL,
    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL
);
```

Example:

```text
01 | ny-summer-street | NY / SUMMER / STREET | Summer | 2026
02 | autumn-2026      | AUTUMN / ...         | Autumn | 2026
```

---

# 5. CHAPTERS TABLE

Each editorial chapter belongs to one issue.

A chapter is normally the 4-page editorial unit:

> STORY → SCENE → THE MOMENT → THE STYLE

```sql
CREATE TABLE issue_chapters (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

    issue_id INT UNSIGNED NOT NULL,

    chapter_number INT UNSIGNED NOT NULL,

    title VARCHAR(255) NOT NULL,
    category VARCHAR(100) NULL,

    place_name VARCHAR(255) NULL,
    time_label VARCHAR(100) NULL,

    accent_key VARCHAR(100) NULL,
    accent_value VARCHAR(100) NULL,

    graphic_key VARCHAR(100) NULL,

    sort_order INT UNSIGNED NOT NULL,

    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL,

    INDEX(issue_id),
    FOREIGN KEY (issue_id) REFERENCES issues(id)
);
```

Example:

```text
CHAPTER 03
ART
CHELSEA
18:40
accent = cobalt
```

The same chapter identity appears on every page inside that chapter.

---

# 6. ISSUE PAGES TABLE

Every page in an issue is stored independently.

```sql
CREATE TABLE issue_pages (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

    issue_id INT UNSIGNED NOT NULL,
    chapter_id INT UNSIGNED NULL,

    page_number INT UNSIGNED NOT NULL,
    sort_order INT UNSIGNED NOT NULL,

    page_type VARCHAR(100) NOT NULL,
    layout_key VARCHAR(150) NOT NULL,

    personalization_mode ENUM(
        'shared',
        'personalized',
        'hybrid'
    ) NOT NULL DEFAULT 'shared',

    title VARCHAR(255) NULL,
    subtitle VARCHAR(255) NULL,
    eyebrow VARCHAR(255) NULL,

    body_html LONGTEXT NULL,
    excerpt TEXT NULL,

    image_asset VARCHAR(500) NULL,
    data_json LONGTEXT NULL,

    is_published TINYINT(1) NOT NULL DEFAULT 1,

    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL,

    UNIQUE(issue_id, page_number),
    INDEX(issue_id),
    INDEX(chapter_id),

    FOREIGN KEY (issue_id) REFERENCES issues(id),
    FOREIGN KEY (chapter_id) REFERENCES issue_chapters(id)
);
```

---

# 7. PAGE TYPES

The engine should support reusable types.

Initial page types:

```text
cover
concept
contents

story
scene
moment
style

interview
essay
poem
art
music
objects
city
photo_essay

ad
house_ad

style_summary
next_issue
credits
back_cover
```

Page type describes **what the page means**.

`layout_key` describes **how it is displayed**.

Example:

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

Another issue could use:

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

Same logical type, different design.

---

# 8. PERSONALIZATION MODES

Each page must explicitly declare its personalization behavior.

## `shared`

Exactly the same editorial content for all readers.

Examples:
- STORY
- SCENE
- interview
- poem
- art feature
- advertisement

## `personalized`

Everything important on the page belongs to the reader.

Examples:
- cover
- STYLE
- reader style summary

## `hybrid`

Shared page structure / Moment, but personalized reader arrival.

Example:

```text
THE MOMENT
Chelsea Gallery Opening / 18:40
(shared)

YOUR ARRIVAL
(reader-specific hero image + styling)
```

This is useful for a Moment + Arrival page.

---

# 9. USER TABLE

```sql
CREATE TABLE users (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

    email VARCHAR(255) NOT NULL UNIQUE,
    first_name VARCHAR(150) NULL,
    last_name VARCHAR(150) NULL,

    status ENUM(
        'active',
        'inactive'
    ) NOT NULL DEFAULT 'active',

    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL
);
```

MVP can use magic-link/private-token access rather than passwords.

---

# 10. USER PROFILE

The style profile belongs to the user, not the issue.

```sql
CREATE TABLE user_profiles (
    user_id INT UNSIGNED PRIMARY KEY,

    height_cm DECIMAL(5,2) NULL,
    clothing_size VARCHAR(50) NULL,
    shoe_size VARCHAR(50) NULL,

    fit_preference VARCHAR(100) NULL,

    favorite_brands TEXT NULL,
    style_vibes TEXT NULL,

    use_cases TEXT NULL,
    budget_notes TEXT NULL,

    style_profile_json LONGTEXT NULL,

    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL,

    FOREIGN KEY (user_id) REFERENCES users(id)
);
```

`style_profile_json` can later contain learned attributes:

```json
{
  "oversized": 0.92,
  "wide_trousers": 0.88,
  "black": 0.74,
  "bright_color": 0.42,
  "slim_fit": 0.08,
  "high_price_tolerance": 0.28
}
```

---

# 11. USER PHOTOS

```sql
CREATE TABLE user_photos (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

    user_id INT UNSIGNED NOT NULL,

    file_path VARCHAR(500) NOT NULL,
    photo_type VARCHAR(50) NULL,

    is_primary TINYINT(1) NOT NULL DEFAULT 0,

    created_at DATETIME NOT NULL,

    INDEX(user_id),
    FOREIGN KEY (user_id) REFERENCES users(id)
);
```

Possible types:

```text
full_body
front
side
portrait
reference
```

---

# 12. USER ISSUE

This record means:

> This specific reader owns / receives this specific issue.

```sql
CREATE TABLE user_issues (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

    user_id INT UNSIGNED NOT NULL,
    issue_id INT UNSIGNED NOT NULL,

    private_token VARCHAR(100) NOT NULL UNIQUE,

    status ENUM(
        'pending',
        'generating',
        'review',
        'ready',
        'published',
        'printed'
    ) NOT NULL DEFAULT 'pending',

    generation_version INT UNSIGNED NOT NULL DEFAULT 1,

    personalized_cover VARCHAR(500) NULL,

    digital_published_at DATETIME NULL,
    print_generated_at DATETIME NULL,

    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL,

    UNIQUE(user_id, issue_id),

    INDEX(user_id),
    INDEX(issue_id),

    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (issue_id) REFERENCES issues(id)
);
```

---

# 13. USER ISSUE PAGES

This stores the personalized result for a reader on a page.

Do **not** duplicate the whole shared magazine here.

Only personalized overrides / generated content.

```sql
CREATE TABLE user_issue_pages (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

    user_issue_id INT UNSIGNED NOT NULL,
    issue_page_id INT UNSIGNED NOT NULL,

    hero_image VARCHAR(500) NULL,

    personal_title VARCHAR(255) NULL,
    personal_subtitle VARCHAR(255) NULL,
    personal_intro TEXT NULL,

    why_it_works TEXT NULL,
    style_notes TEXT NULL,
    stylist_note TEXT NULL,

    generation_prompt LONGTEXT NULL,
    generation_data_json LONGTEXT NULL,

    review_status ENUM(
        'not_generated',
        'generated',
        'needs_review',
        'approved',
        'rejected'
    ) NOT NULL DEFAULT 'not_generated',

    reviewed_by VARCHAR(150) NULL,
    reviewed_at DATETIME NULL,

    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL,

    UNIQUE(user_issue_id, issue_page_id),

    INDEX(user_issue_id),
    INDEX(issue_page_id),

    FOREIGN KEY (user_issue_id) REFERENCES user_issues(id),
    FOREIGN KEY (issue_page_id) REFERENCES issue_pages(id)
);
```

---

# 14. PRODUCTS

Products should eventually have a shared catalog.

```sql
CREATE TABLE products (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

    brand VARCHAR(255) NOT NULL,
    product_name VARCHAR(500) NOT NULL,

    category VARCHAR(150) NULL,

    price DECIMAL(10,2) NULL,
    currency VARCHAR(10) NULL,

    product_url VARCHAR(1000) NOT NULL,
    affiliate_url VARCHAR(1000) NULL,

    source_image_url VARCHAR(1000) NULL,

    metadata_json LONGTEXT NULL,

    status ENUM(
        'active',
        'unavailable',
        'archived'
    ) NOT NULL DEFAULT 'active',

    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL
);
```

MVP can still enter products manually.

---

# 15. USER ISSUE PRODUCTS

A specific product is selected for a specific reader's style page.

```sql
CREATE TABLE user_issue_products (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

    user_issue_page_id INT UNSIGNED NOT NULL,

    product_id INT UNSIGNED NULL,

    brand VARCHAR(255) NOT NULL,
    product_name VARCHAR(500) NOT NULL,

    price DECIMAL(10,2) NULL,
    currency VARCHAR(10) NULL,

    product_url VARCHAR(1000) NOT NULL,

    slot_name VARCHAR(100) NULL,
    sort_order INT UNSIGNED NOT NULL DEFAULT 0,

    verification_status ENUM(
        'unverified',
        'verified',
        'unavailable'
    ) NOT NULL DEFAULT 'unverified',

    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL,

    INDEX(user_issue_page_id),
    INDEX(product_id),

    FOREIGN KEY (user_issue_page_id) REFERENCES user_issue_pages(id),
    FOREIGN KEY (product_id) REFERENCES products(id)
);
```

Example slots:

```text
outerwear
top
trousers
shoes
bag
accessory
```

---

# 16. REACTIONS

Reactions can apply to:

1. a whole style page
2. an individual product

```sql
CREATE TABLE reactions (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

    user_id INT UNSIGNED NOT NULL,
    user_issue_id INT UNSIGNED NOT NULL,
    user_issue_page_id INT UNSIGNED NULL,
    user_issue_product_id INT UNSIGNED NULL,

    reaction ENUM(
        'love',
        'not_me',
        'too_expensive',
        'more_like_this'
    ) NOT NULL,

    created_at DATETIME NOT NULL,

    INDEX(user_id),
    INDEX(user_issue_id),
    INDEX(user_issue_page_id),
    INDEX(user_issue_product_id),

    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (user_issue_id) REFERENCES user_issues(id)
);
```

Owner reactions train future issues.

Guest reactions should not.

---

# 17. COMMENTS

```sql
CREATE TABLE comments (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

    user_id INT UNSIGNED NOT NULL,
    user_issue_id INT UNSIGNED NOT NULL,
    user_issue_page_id INT UNSIGNED NULL,

    comment_text TEXT NOT NULL,

    comment_type ENUM(
        'stylist_feedback',
        'general'
    ) NOT NULL DEFAULT 'stylist_feedback',

    created_at DATETIME NOT NULL,

    INDEX(user_id),
    INDEX(user_issue_id),

    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (user_issue_id) REFERENCES user_issues(id)
);
```

These comments become generation input for the next issue.

---

# 18. GENERATION INPUT FOR NEXT ISSUE

When generating Magazine 02 for a reader, build one structured input package.

Example:

```json
{
  "reader": {
    "height_cm": 185,
    "clothing_size": "S",
    "shoe_size": "42",
    "fit": "oversized",
    "brands": ["Zara", "Uniqlo"],
    "style": ["minimal", "sporty", "Scandinavian"],
    "budget": "mostly under 100 EUR"
  },

  "learned_feedback": {
    "love": [
      "wide trousers",
      "minimal leather shoes"
    ],
    "not_me": [
      "slim trousers"
    ],
    "too_expensive": [
      "300 EUR coats"
    ],
    "more_like_this": [
      "oversized technical outerwear"
    ]
  },

  "comments": [
    "Love these shoes.",
    "This one was too formal.",
    "More looks like page 17."
  ],

  "new_issue": {
    "issue_id": 2,
    "title": "AUTUMN / ...",
    "moments": [...]
  }
}
```

The generator does **not** invent the editorial issue.

The issue already exists.

It only answers:

> **How should this reader arrive at each predefined Moment?**

---

# 19. GENERATION JOBS

Generation should be trackable.

```sql
CREATE TABLE generation_jobs (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

    user_issue_id INT UNSIGNED NOT NULL,
    issue_page_id INT UNSIGNED NULL,

    job_type VARCHAR(100) NOT NULL,

    status ENUM(
        'queued',
        'running',
        'completed',
        'failed'
    ) NOT NULL DEFAULT 'queued',

    input_json LONGTEXT NULL,
    output_json LONGTEXT NULL,

    error_text TEXT NULL,

    started_at DATETIME NULL,
    completed_at DATETIME NULL,
    created_at DATETIME NOT NULL,

    INDEX(user_issue_id),
    FOREIGN KEY (user_issue_id) REFERENCES user_issues(id)
);
```

Possible job types:

```text
build_style_context
select_products
write_style_copy
generate_hero_image
generate_cover
generate_style_summary
generate_print_pdf
```

---

# 20. HUMAN REVIEW

The promise is:

> **Human-edited. AI-assisted. Every personalized issue is individually reviewed.**

Therefore personalized pages must have a review step.

Admin should show:

```text
JĀNIS
MAGAZINE 02

Arrival 01   ✓ Approved
Arrival 02   ✓ Approved
Arrival 03   ⚠ Needs review
Arrival 04   ✓ Approved
Arrival 05   ✓ Approved
Arrival 06   ✓ Approved
Cover        ✓ Approved
```

Only allow final print generation when required personalized pages are approved.

Optional table:

```sql
CREATE TABLE review_log (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

    user_issue_page_id INT UNSIGNED NULL,
    user_issue_id INT UNSIGNED NOT NULL,

    action VARCHAR(100) NOT NULL,
    reviewer VARCHAR(150) NULL,
    notes TEXT NULL,

    created_at DATETIME NOT NULL
);
```

---

# 21. LAYOUT SYSTEM

Never hard-code one layout per issue.

Use reusable layout files.

Suggested:

```text
/layouts/
    cover/
        cover-01.php
        cover-02.php

    story/
        story-editorial-01.php
        story-editorial-02.php
        story-photo-led.php

    scene/
        scene-photo.php
        scene-collage.php
        scene-quote.php
        scene-playlist.php
        scene-art.php

    moment/
        moment-arrival-01.php
        moment-arrival-02.php

    style/
        style-products-01.php
        style-products-02.php

    interview/
        interview-01.php

    ad/
        house-ad-01.php

    art/
        art-01.php
```

A DB page says:

```text
layout_key = scene-collage
```

The renderer resolves:

```text
/layouts/scene/scene-collage.php
```

---

# 22. WHY THIS MATTERS

Magazine 01 can use:

```text
story-editorial-01
scene-photo
moment-arrival-01
style-products-01
```

Magazine 02 can use:

```text
story-editorial-02
scene-collage
moment-arrival-02
style-products-01
```

If a new layout is needed, add it.

Do **not** modify old layouts unless fixing a genuine shared bug.

This prevents new issues from visually breaking published ones.

---

# 23. THEME SYSTEM

Base styling belongs to the engine.

```text
/assets/css/base.css
```

Issue-specific art direction belongs in themes:

```text
/themes/
    issue-001.css
    issue-002.css
    issue-003.css
```

or:

```text
/themes/ny-summer-street.css
/themes/autumn-2026.css
```

The issue record stores:

```text
theme_key = ny-summer-street
```

Possible theme values:
- fonts
- background
- text color
- accent palette
- chapter marker style
- margins
- image treatment
- page-number style
- heading scale

Themes should override the base system without changing engine structure.

---

# 24. CONTENT + LAYOUT SEPARATION

Shared editorial content should not live inside PHP templates.

Bad:

```php
<h1>ART AFTER DARK</h1>
<p>Hard-coded article...</p>
```

Good:

```php
<h1><?= h($page['title']) ?></h1>
<div><?= $page['body_html'] ?></div>
```

Templates render.

Database stores content.

This is what makes the admin CMS possible.

---

# 25. ADMIN — MAIN NAVIGATION

Recommended top-level admin:

```text
DASHBOARD

ISSUES
READERS
ORDERS          later
PRODUCTS
GENERATION
SETTINGS
```

---

# 26. ADMIN — ISSUES LIST

```text
MAGAZINE 01
NY / SUMMER / STREET
Published
32 pages

[ EDIT ]
[ PREVIEW ]
[ READERS ]
[ PRINT ]

--------------------------------

MAGAZINE 02
AUTUMN / ...
Draft
32 pages

[ EDIT ]
[ PREVIEW ]
[ PUBLISH ]
```

Button:

```text
+ CREATE NEW ISSUE
```

---

# 27. ADMIN — ISSUE EDITOR

Inside an issue:

```text
MAGAZINE 02 — AUTUMN / ...

01 COVER
02 CONCEPT
03 MOMENT / ARRIVAL
04 STYLE

05 STORY — ...
06 SCENE — ...
07 MOMENT — ...
08 STYLE — PERSONALIZED

09 STORY — ...
10 SCENE — ...
11 MOMENT — ...
12 STYLE — PERSONALIZED

...
```

Admin capabilities:
- edit page
- change layout
- change title
- edit body
- upload image
- change chapter
- change accent
- reorder pages
- duplicate page
- create page
- delete draft page
- preview page
- preview full issue

---

# 28. ADMIN — PAGE EDITOR

Fields depend on page type.

Example STORY:

```text
Title
Subtitle
Eyebrow
Body
Image
Layout
Chapter
Accent
```

Example SCENE:

```text
Title
Mood words
Short text
Main image
Secondary images
Quote
Playlist
Layout
```

Example MOMENT:

```text
Place
Time
Moment title
2–4 sentence situation
Environment
Social context
What happens next
Layout
```

Example STYLE personalized slot:

```text
Personalized: YES
Product slots:
  Top
  Bottom
  Outerwear
  Shoes
  Bag

Generation instructions
Layout
```

---

# 29. ADMIN — CHAPTER EDITOR

Example:

```text
CHAPTER 03

Category: ART
Title: ART AFTER DARK

Place: CHELSEA
Time: 18:40

Accent: cobalt
Graphic: line-03

Pages:
[ STORY ]
[ SCENE ]
[ MOMENT ]
[ STYLE ]
```

Changing chapter identity should update all pages in that chapter.

---

# 30. ADMIN — READERS

Readers list:

```text
Jānis
Magazine 01 ✓
Magazine 02 ✓
Magazine 03 —

Līga
Magazine 01 ✓
Magazine 02 —

Customer 003
Magazine 01 ✓
```

Click reader:

```text
PROFILE
PHOTOS
STYLE MEMORY
ISSUES
FEEDBACK
```

---

# 31. ADMIN — READER STYLE MEMORY

Example:

```text
JĀNIS

Strong:
Oversized          ↑↑
Wide trousers      ↑↑
Minimal             ↑
Black               ↑
Technical outerwear ↑

Avoid:
Slim fit            ↓↓
Too formal          ↓

Budget:
€300+ outerwear     ↓

Recent comments:
“Love these shoes.”
“Too formal.”
“More like page 17.”
```

This summary can initially be human-readable.

Later it can be generated from structured reactions.

---

# 32. ADMIN — GENERATE ISSUE

Reader page:

```text
JĀNIS
MAGAZINE 02 / AUTUMN

Profile ✓
Photos ✓
Previous feedback ✓
Issue moments ✓
Product pool ✓

[ GENERATE MAGAZINE ]
```

The button should create generation jobs for personalized pages.

Important:

`GEN MAGAZINE` does not generate shared editorial pages.

Those are already created by the editor.

It generates:
- cover
- arrivals
- style copy
- products
- style summary

---

# 33. GENERATION PIPELINE

Recommended pipeline per reader:

```text
1. Load reader profile
2. Load photos
3. Load historical feedback
4. Load current issue moments
5. Load product pool
6. Build style context
7. Generate candidate product selections
8. Generate arrival direction
9. Generate hero image
10. Generate Why it works
11. Generate Style notes
12. Save draft
13. Human review
14. Approve
15. Publish digital
16. Generate print PDF
```

Do not generate everything in one giant prompt.

Keep steps inspectable.

---

# 34. PRODUCT SELECTION PIPELINE

MVP:

```text
human/editor selects product pool
↓
AI picks suitable items for reader + moment
↓
human verifies products
↓
approved style page
```

Later:

```text
catalog ingestion
↓
metadata / tags
↓
filter by:
    gender / category
    sizes
    price
    stock
    region
↓
retrieve top candidates
↓
AI stylist
↓
final selection
```

---

# 35. ISSUE CREATION WORKFLOW

The ideal future workflow:

```text
1. CREATE ISSUE

2. Editor describes concept:
   “Autumn issue about ...”

3. Build editorial outline

4. Create chapters:
   STORY
   SCENE
   MOMENT
   STYLE SLOT

5. Generate rough shared copy

6. Human edits / improves

7. Add real interviews / art / music / ads

8. Select layouts

9. Set issue theme

10. Preview shared issue

11. Lock editorial structure

12. Generate reader versions

13. Review personalized pages

14. Publish digital

15. Generate print files
```

This means a future issue is mostly **content creation**, not software development.

---

# 36. SAFE ISSUE VERSIONING

Published issues must not unexpectedly change.

Recommended:

```text
issue.status = published
```

After publishing:
- do not reorder pages casually
- do not delete layouts used by the issue
- do not overwrite issue-specific CSS destructively

If an old issue needs a real correction:
- edit deliberately
- optionally store `updated_at`
- later introduce issue revisions

Potential later:

```text
issue_revision = 1
issue_revision = 2
```

---

# 37. DIGITAL RENDERER

The digital renderer receives:

```text
issue
+
ordered issue_pages
+
user_issue
+
user_issue_page overrides
```

Pseudo logic:

```php
$page = get_issue_page($issueId, $pageNumber);

if ($page['personalization_mode'] === 'shared') {
    render_shared_page($page);
}

if ($page['personalization_mode'] === 'personalized') {
    $personal = get_user_issue_page(...);
    render_personalized_page($page, $personal);
}

if ($page['personalization_mode'] === 'hybrid') {
    $personal = get_user_issue_page(...);
    render_hybrid_page($page, $personal);
}
```

---

# 38. DIGITAL URLS

Owner private issue:

```text
/i/{private_token}
```

Example:

```text
https://domain.com/i/8FJ3K9X2
```

Individual page:

```text
/i/8FJ3K9X2/7
```

Optional public/shared link:

```text
/s/{share_token}
```

---

# 39. DIGITAL SHARING

Possible share scopes:

```text
page_only
page_and_issue
full_issue
```

Owner can share.

Guests:
- can read
- can shop
- should not modify owner style memory

MVP can keep guest experience read-only.

---

# 40. DIGITAL CONTENT MODEL

Digital should contain the **same core editorial content** as print.

Not a separate publication.

Rule:

> **Print tells the story. Digital extends it.**

Digital may add:
- clickable products
- reactions
- comments
- Spotify
- videos
- ACL animation
- extra images
- full interview
- share
- live availability

But STORY / SCENE / MOMENT / ARRIVAL remain the same editorial sequence.

---

# 41. PRINT RENDERER

Print is a second renderer from the same issue source.

Do not manually redesign the entire magazine in another app.

Architecture:

```text
ISSUE DATA
    │
    ├── DIGITAL RENDERER → web
    │
    └── PRINT RENDERER   → print HTML → PDF
```

Suggested routes:

```text
/admin/print-preview.php?user_issue_id=123
/admin/generate-print.php?user_issue_id=123
```

---

# 42. PRINT PAGE COMPONENTS

Print renderer uses dedicated print templates where needed.

Possible structure:

```text
/print-layouts/
    cover.php
    story.php
    scene.php
    moment.php
    style.php
    ad.php
```

Some digital and print layouts can share data but not necessarily identical CSS.

The content source remains the same.

---

# 43. PRINT CSS

Separate from digital CSS.

```text
/assets/css/print.css
```

Principles:
- fixed page dimensions
- no browser navigation
- no reaction controls
- no interactive buttons
- no overflow
- explicit page breaks
- print-safe typography
- safe zones
- bleed support

Each page:

```css
.print-page {
    break-after: page;
    position: relative;
    overflow: hidden;
}
```

Exact POD dimensions should live in configuration.

---

# 44. PRINT FILES

Per reader / issue:

```text
/exports/
    issue-002/
        user-00047/
            interior.pdf
            cover.pdf
```

Admin status:

```text
Print generated: 2026-...
Print version: 3
```

Do not overwrite approved print files without recording a new generation.

---

# 45. PRINT GENERATION BUTTON

Admin:

```text
[ PREVIEW DIGITAL ]

[ PREVIEW PRINT ]

[ GEN MAGAZINE PDF ]
```

Before allowing final PDF:

```text
✓ shared issue published
✓ cover approved
✓ every required arrival approved
✓ products verified
✓ images available
```

If not:

```text
Cannot generate final print:
Arrival 04 needs review.
```

---

# 46. ASSET SYSTEM

Prefer a central asset directory / database.

Suggested filesystem:

```text
/assets/uploads/
    issues/
        issue-001/
            shared/
            art/
            ads/

    users/
        user-47/
            profile/

    generated/
        issue-001/
            user-47/
                cover/
                arrival-01/
                arrival-02/
```

Avoid mixing permanent source files with temporary generation files.

---

# 47. IMAGE VARIANTS

Where practical:

```text
master image
↓
web optimized
↓
print optimized
```

Example:

```text
arrival-03-master.png
arrival-03-web.webp
arrival-03-print.jpg
```

Print renderer should never accidentally use a low-resolution web thumbnail.

---

# 48. PUBLISH WORKFLOW

Issue-level publish:

```text
DRAFT
↓
EDITORIAL REVIEW
↓
PUBLISHED
```

Reader-level:

```text
PENDING
↓
GENERATING
↓
REVIEW
↓
READY
↓
PUBLISHED
↓
PRINTED
```

These are separate states.

Magazine 02 may be published editorially even while some readers are still being generated.

---

# 49. SELF-PROMO / VISITOR LOGIC

A shared issue link can be seen by someone who is not the owner.

Therefore early in the issue include:

```text
ONE MOMENT. THREE READERS.
Same issue. Same moment. Different you.

[ GET YOUR OWN ISSUE ]
```

And later:

```text
PRINT + DIGITAL
DIGITAL ONLY
```

The digital engine should know:

```text
owner_mode
guest_mode
```

Guest mode:
- hides owner-only comments
- disables training reactions
- keeps shopping/share/marketing CTA

---

# 50. FIRST ISSUE / FUTURE ISSUE DISTINCTION

The engine must never assume:

```text
issue_id = 1
```

Everything should load from current issue context.

Bad:

```php
SELECT * FROM issue_pages WHERE issue_id = 1
```

Good:

```php
SELECT * FROM issue_pages WHERE issue_id = ?
```

This is critical for stacking Magazine 02, 03, 04...

---

# 51. DATABASE RELATIONSHIP SUMMARY

```text
issues
  │
  ├── issue_chapters
  │      │
  │      └── issue_pages
  │
  └── user_issues
         │
         ├── user_issue_pages
         │       │
         │       └── user_issue_products
         │
         ├── reactions
         └── comments

users
  │
  ├── user_profiles
  ├── user_photos
  └── user_issues
```

---

# 52. RECOMMENDED PROJECT STRUCTURE

```text
/
├── index.php
├── issue.php
├── page.php
├── share.php
│
├── config/
│   ├── config.php
│   └── print.php
│
├── lib/
│   ├── db.php
│   ├── issues.php
│   ├── readers.php
│   ├── pages.php
│   ├── products.php
│   ├── reactions.php
│   ├── generation.php
│   ├── renderer.php
│   └── print.php
│
├── layouts/
│   ├── cover/
│   ├── story/
│   ├── scene/
│   ├── moment/
│   ├── style/
│   ├── interview/
│   ├── art/
│   └── ad/
│
├── print-layouts/
│
├── themes/
│   ├── issue-001.css
│   └── issue-002.css
│
├── assets/
│   ├── css/
│   │   ├── base.css
│   │   ├── digital.css
│   │   └── print.css
│   ├── js/
│   └── uploads/
│
├── admin/
│   ├── index.php
│   ├── issues.php
│   ├── issue-edit.php
│   ├── page-edit.php
│   ├── chapter-edit.php
│   ├── readers.php
│   ├── reader.php
│   ├── generate.php
│   ├── review.php
│   ├── print-preview.php
│   └── generate-print.php
│
├── generation/
│   ├── build-context.php
│   ├── select-products.php
│   ├── generate-copy.php
│   └── generate-image.php
│
└── exports/
```

---

# 53. MVP BUILD PHASES

Do not build everything at once.

## PHASE 1 — MULTI-ISSUE CORE

Build:
- issues
- chapters
- pages
- reusable layouts
- issue themes
- multi-issue routing
- digital renderer
- admin issue editor

Goal:

> Magazine 01 and Magazine 02 can exist independently in the same system.

---

## PHASE 2 — READERS + PERSONALIZED PAGES

Build:
- users
- profiles
- photos
- user_issues
- user_issue_pages
- reader issue renderer
- products
- reactions
- comments

Goal:

> Two readers can open the same issue and see the same shared content but different arrivals.

---

## PHASE 3 — GENERATION WORKFLOW

Build:
- generation jobs
- previous feedback aggregation
- GEN MAGAZINE
- generated drafts
- review / approve workflow

Goal:

> Generate a new issue's personalized slots for an existing reader.

---

## PHASE 4 — PRINT

Build:
- print renderer
- print CSS
- preview
- PDF generation
- cover generation
- export history

Goal:

> Press one button and receive print-ready interior + cover files.

---

## PHASE 5 — COMMERCE

Later:
- orders
- Stripe
- subscription
- digital-only
- print + digital
- gifts
- POD handoff
- shipping status

---

# 54. ADMIN MVP PRIORITY

For the first real working system, the most important admin screens are:

1. Issues
2. Issue editor
3. Page editor
4. Chapters
5. Readers
6. Reader issue
7. Generate
8. Review
9. Digital preview
10. Print preview
11. Generate PDF

Fancy dashboard analytics can wait.

---

# 55. CONTENT CREATION PRINCIPLE

A new issue should feel easy to create.

Desired future conversation/workflow:

> “Create an Autumn issue around art, music, architecture and one real festival.”

Then:

1. generate rough chapter ideas
2. create pages in DB
3. choose layouts
4. generate rough copy
5. human edits
6. add real editorial content
7. define Moments
8. publish issue structure
9. generate personalized arrivals

The engine stays untouched unless a truly new capability is needed.

---

# 56. NEW LAYOUT RULE

When an issue requires a new visual idea:

Add:

```text
/layouts/scene/scene-architecture-01.php
```

Do not rewrite:

```text
/layouts/scene/scene-photo.php
```

unless fixing a bug.

This preserves old magazines.

---

# 57. NEW ISSUE RULE

Creating Magazine 03 should ideally require:

```text
INSERT issue
INSERT chapters
INSERT pages
ADD theme CSS
OPTIONALLY add new layout components
```

Not:

```text
copy whole codebase
rename PHP files
rewrite URLs
```

---

# 58. CORE GENERATION PRINCIPLE

AI should not decide the magazine structure for each reader.

The editor defines:

```text
ISSUE
CHAPTER
STORY
SCENE
MOMENT
```

AI + human stylist decide:

```text
YOUR ARRIVAL
THE STYLE
PRODUCTS
WHY IT WORKS
STYLE NOTES
```

This protects the editorial identity.

---

# 59. HUMAN REVIEW PRINCIPLE

Never expose raw AI generation automatically as a paid premium issue.

Flow:

```text
AI draft
↓
human review
↓
correction if needed
↓
approve
↓
reader sees it
```

This is both a quality-control feature and part of the brand promise.

---

# 60. PRODUCT MEMORY PRINCIPLE

Every issue should make the next one better.

The next issue generator should use:
- profile
- previous reactions
- previous product reactions
- comments
- price sensitivity
- liked silhouettes
- rejected silhouettes
- brand preferences
- repeated choices

But do not let historical preference make the product boring.

The system can include:
- 70–80% aligned choices
- 20–30% editorial challenge / wildcard

This can later become configurable.

---

# 61. FINAL SYSTEM MODEL

```text
                    ONE PUBLISHING ENGINE
                           │
          ┌────────────────┴────────────────┐
          │                                 │
      ISSUE SYSTEM                      READER SYSTEM
          │                                 │
   shared editorial                     profile
   chapters                             photos
   layouts                              history
   themes                               feedback
   moments                              preferences
          │                                 │
          └───────────────┬─────────────────┘
                          │
                   PERSONALIZED ISSUE
                          │
                 shared editorial pages
                          +
                personalized arrivals
                          +
                 personalized products
                          │
              ┌───────────┴───────────┐
              │                       │
           DIGITAL                  PRINT
              │                       │
     interaction / feedback       POD-ready PDF
```

---

# 62. DEFINITION OF DONE

The architecture is working correctly when we can do all of the following:

### Issue system
- create Magazine 01
- create Magazine 02
- publish both
- edit Magazine 02 without breaking Magazine 01

### Reader system
- create Reader A
- create Reader B
- attach both to Magazine 01

### Personalization
- Reader A and Reader B see the same STORY / SCENE / MOMENT
- Reader A and Reader B see different ARRIVAL / STYLE / PRODUCTS

### Memory
- Reader A's feedback from Magazine 01 is available when generating Magazine 02

### Admin
- editor can change page copy/layout/order without code edits
- editor can review reader-specific pages

### Publishing
- `Publish Issue` exposes the digital issue
- `GEN MAGAZINE` produces the complete personalized edition

### Print
- one reader-specific issue can be rendered as:
  - interior PDF
  - cover PDF

That is the MVP target.

---

# 63. ONE-LINE TECHNICAL SUMMARY

> **One reusable publishing engine stores shared issue content once, overlays reader-specific fashion arrivals and products per issue, remembers feedback across issues, and renders the same source into digital and print editions.**
