# Modyo Resource Status Guide

**Complete guide to understanding resource states across templates, widgets, pages, and menus.**

---

## Table of Contents

1. [Overview](#overview)
2. [Universal States](#universal-states)
3. [Template States](#template-states)
4. [Widget Definition States](#widget-definition-states)
5. [Page States](#page-states)
6. [Menu States](#menu-states)

**See also**: [Status Operations](status-operations.md) — State Transitions, Querying Resource States, Common State Issues, Best Practices

---

## Overview

All Modyo Channels resources follow a **state machine** pattern:

```
Create → Draft → Pending Review* → Published → Unpublished → Archived*
         ↓                              ↓
         └──────── Scheduled ───────────┘

*Optional states (depend on site configuration)
```

**Key Concepts**:

- **Draft**: Resource exists but not live
- **Published**: Resource is active on site
- **Pending**: Awaiting approval (team review enabled)
- **Scheduled**: Will publish/unpublish at specific time
- **Unpublished**: Was published, now offline
- **Archived**: Removed from active use

---

## Universal States

### Draft

**What it means**: Resource created but not published.

**Characteristics**:
- Editable in Modyo admin
- Not visible on public site
- Can be modified freely
- Doesn't appear in `release-get-elements-to-publish` if unchanged

**Transitions**:
```
Draft → Pending Review (if team review enabled)
Draft → Published (via release-create)
Draft → Scheduled (via release-create with publish_at)
```

**Example**:
```typescript
// Create template (draft state)
const template = await template-create({
  name: "my_snippet",
  type: "custom_snippet",
  body: "<div>Draft content</div>"
});

// Still draft - can edit
await template-save({
  templateId: template.id,
  body: "<div>Updated draft</div>"
});

// State: draft
```

### Published

**What it means**: Resource is live and active on site.

**Characteristics**:
- Visible/accessible on public site
- Templates: Active in rendering
- Widgets: Available for use in pages
- Pages: Accessible at configured path
- Menus: Visible in navigation

**Transitions**:
```
Published → Draft (edit creates new draft version)
Published → Unpublished (via unpublish tools)
Published → Scheduled (schedule unpublish)
```

**Example**:
```typescript
// Publish template
const elements = await release-get-elements-to-publish({ siteId: 4612 });
const template = elements.template.find(t => t.name === "my_snippet");
await release-create({
  data: { template: [{ id: template.id, selected: true }] }
});

// State: published
// Now accessible via {% snippet 'my_snippet' %}
```

### Pending Review

**What it means**: Resource awaiting team approval before publishing.

**Characteristics**:
- Requires site setting: `enforced_review: true`
- Can't be published until approved
- Appears in review queue
- May require specific number of approvals

**Transitions**:
```
Pending Review → Published (after approval + release)
Pending Review → Draft (reject review)
```

**Note**: This state only exists if site has team review enabled.

```typescript
// Site with team review
site-update({
  siteId: 4612,
  site: {
    enforced_review: true,
    approvals_quantity: 2  // Requires 2 approvals
  }
});

// Edit template
await template-save({ templateId: 123, body: "..." });

// State: pending_review
// Won't appear in release-get-elements-to-publish until approved
```

### Scheduled

**What it means**: Resource will publish/unpublish at specific future time.

**Characteristics**:
- Has `publish_at` or `unpublish_at` timestamp
- Transitions automatically at scheduled time
- Can be canceled before execution
- Visible in scheduled releases list

**Transitions**:
```
Scheduled → Published (when publish_at time arrives)
Scheduled → Unpublished (when unpublish_at time arrives)
Scheduled → Draft (cancel before execution)
```

**Example**:
```typescript
// Schedule page publish
await release-create({
  platformSlug: "fed-team",
  siteId: 4612,
  scheduled: true,
  publish_at: "2025-02-01T09:00:00Z",
  data: { page: [{ id: 456, selected: true }] }
});

// State: scheduled
// Will become: published (on Feb 1 at 9 AM)
```

### Unpublished

**What it means**: Resource was published, now offline.

**Characteristics**:
- Previous published version available
- Can be re-published
- Changes since last publish may exist
- History preserved

**Transitions**:
```
Unpublished → Published (re-publish)
Unpublished → Archived (remove permanently)
```

**Example**:
```typescript
// Unpublish page
await page-unpublish({
  platformSlug: "fed-team",
  siteId: 4612,
  pageId: 456
});

// State: unpublished
// Page no longer accessible at /products
// Can re-publish to restore
```

### Archived

**What it means**: Resource removed from active workflows.

**Characteristics**:
- Not editable
- Doesn't appear in normal lists
- Can be restored (unarchived)
- History preserved

**Transitions**:
```
Archived → Draft (restore/unarchive)
```

**Example**:
```typescript
// Archive page workflow
await page-archive({
  platformSlug: "fed-team",
  siteId: 4612,
  pageId: 456
});

// State: archived
// Page appears in archived list only
// Can be restored if needed
```

---

## Template States

### State Machine

```
            ┌─────────────┐
            │   CREATE    │
            └──────┬──────┘
                   │
                   ▼
            ┌─────────────┐
     ┌─────▶│    DRAFT    │◀─────┐
     │      └──────┬──────┘      │
     │             │              │
     │             │ publish      │ unpublish
     │             ▼              │
     │      ┌─────────────┐      │
     └──────│  PUBLISHED  │──────┘
            └──────┬──────┘
                   │ archive
                   ▼
            ┌─────────────┐
            │  ARCHIVED   │
            └─────────────┘
```

### Template-Specific States

**System Snippets (Special Case)**:
- Always published
- Can't be unpublished
- Can't be deleted
- Can be edited (new version published)

**Examples**: `head`, `footer`, `header`, `menu`, grid snippets, widget snippets

### Checking Template State

```typescript
const template = await template-get({
  platformSlug: "fed-team",
  siteId: 4612,
  templateId: 123
});

console.log(template.published);  // boolean: true/false
console.log(template.status);     // "draft" | "published" | "scheduled"
```

### State Indicators

| State | `published` | Appears in `release-get-elements-to-publish` |
|-------|-------------|---------------------------------------------|
| Draft (new) | false | true (if modified) |
| Draft (edited) | false | true |
| Published | true | false (unless modified) |
| Published + Modified | true | true (draft version) |

---

## Widget Definition States

### State Machine

```
            ┌─────────────┐
            │   CREATE    │
            └──────┬──────┘
                   │
                   ▼
            ┌─────────────┐
     ┌─────▶│    DRAFT    │
     │      └──────┬──────┘
     │             │
     │             │ publish
     │             ▼
     │      ┌─────────────┐
     │      │  PUBLISHED  │
     │      └──────┬──────┘
     │             │
     │             │ edit
     │             ▼
     │      ┌─────────────┐
     └──────│DRAFT + PUB  │ (two versions)
            └──────┬──────┘
                   │ archive workflow
                   ▼
            ┌─────────────┐
            │  ARCHIVED   │
            └─────────────┘
```

### Critical: Dual Widget IDs

**Important**: Widgets exist in TWO different endpoints with DIFFERENT IDs:

**1. Widget Definitions** (`/widget_definitions`):
- Used for editing
- Retrieved by `widget-definitions-list`
- Used by `widget-definition-get`, `widget-definition-update`
- ID changes after publishing

**2. Custom Widgets** (`/custom_widgets`):
- Published widgets available for pages
- Retrieved by `widget-get-custom-widgets`
- Used by `page-add-widgets` (via UUID)
- Different IDs than definitions

**Workflow Implications**:
```typescript
// WRONG - Using custom widgets ID for editing
const customWidgets = await widget-get-custom-widgets({ siteId: 4612 });
const widgetId = customWidgets.custom_widgets[0].id;
await widget-definition-get({ widgetId });  // 404 Error!

// CORRECT - Using definitions ID for editing
const definitions = await widget-definitions-list({ siteId: 4612 });
const widgetId = definitions.widget_definitions[0].id;
await widget-definition-get({ widgetId });  // Success
```

**See**: [WIDGET_WORKFLOWS.md](WIDGET_WORKFLOWS.md) for complete guide.

### Widget State Properties

```typescript
{
  id: number,           // Definition ID (changes after publish)
  uuid: string,         // Stable identifier
  name: string,
  published: boolean,   // Is widget published?
  read_only: boolean,   // CLI widget (can't edit)
  zip: boolean,         // ZIP widget (full build)
  version_id: number,   // Current version
  versions: Array       // Version history
}
```

### Widget States in Practice

**Draft Widget**:
```typescript
const widget = await widget-definitions-create({ widgetName: "Card" });
await widget-definition-update({ widgetId: widget.id, html: "...", css: "", js: "" });

// State: draft
// published: false
// Not in widget-get-custom-widgets
// Can't add to pages yet
```

**Published Widget**:
```typescript
const elements = await release-get-elements-to-publish({ siteId: 4612 });
await release-create({ data: { widgetDefinition: [{ id: widget.id, selected: true }] } });

// State: published
// published: true
// Appears in widget-get-custom-widgets
// Can add to pages
// ID MAY HAVE CHANGED - use UUID to find it
```

**Published + Draft Version**:
```typescript
// Widget is published
const published = await widget-get-custom-widgets({ siteId: 4612 });

// Edit creates draft version
const definitions = await widget-definitions-list({ siteId: 4612 });
const widget = definitions.widget_definitions.find(w => w.uuid === published.custom_widgets[0].uuid);
await widget-definition-update({ widgetId: widget.id, html: "Updated" });

// State: published (old version live) + draft (new version pending)
// Pages show published version
// Admin shows draft version
// Can publish draft to replace live version
```

---

## Page States

### State Machine

```
            ┌─────────────┐
            │   CREATE    │
            └──────┬──────┘
                   │
                   ▼
            ┌─────────────┐
     ┌─────▶│    DRAFT    │◀─────┐
     │      └──────┬──────┘      │
     │             │              │
     │             │ publish      │ unpublish
     │             ▼              │
     │      ┌─────────────┐      │
     │      │  PUBLISHED  │──────┘
     │      └──────┬──────┘
     │             │ edit
     │             ▼
     │      ┌─────────────┐
     └──────│DRAFT + PUB  │
            └──────┬──────┘
                   │ unpublish + archive
                   ▼
            ┌─────────────┐
            │  ARCHIVED   │
            └─────────────┘
```

### Page-Specific States

**Home Page (Special Case)**:
- Can't be unpublished via API
- Can't be deleted via API
- Protected by Modyo platform
- Solution: Change home page in site settings, then unpublish old home

### Page State Properties

```typescript
{
  id: number,
  name: string,
  path: string,
  page_type: string,      // "default", "content", "entry", "origination"
  published: boolean,     // Is page published?
  status: string,         // "draft" | "published" | "scheduled" | "unpublished"
  publish_at: string,     // Scheduled publish time (ISO 8601)
  unpublish_at: string,   // Scheduled unpublish time (ISO 8601)
  workflow_id: number     // For archiving
}
```

### Page States in Practice

**Draft Page**:
```typescript
const page = await page-create({
  name: "Products",
  path: "products",
  type: "default"
});

// State: draft
// published: false
// status: "draft"
// Not accessible at /products
```

**Published Page**:
```typescript
const elements = await release-get-elements-to-publish({ siteId: 4612 });
await release-create({ data: { page: [{ id: page.id, selected: true }] } });

// State: published
// published: true
// status: "published"
// Accessible at /products
```

**Scheduled Page**:
```typescript
await release-create({
  scheduled: true,
  publish_at: "2025-02-01T00:00:00Z",
  data: { page: [{ id: page.id, selected: true }] }
});

// State: scheduled
// status: "scheduled"
// Will publish on Feb 1
```

**Unpublished Page**:
```typescript
await page-unpublish({ pageId: page.id });

// State: unpublished
// published: false
// status: "unpublished"
// Not accessible at /products
// Can be re-published
```

**Deleting Published Page (3-step workflow)**:
```typescript
// Step 1: Unpublish
await page-unpublish({ pageId: 456 });

// Step 2: Archive workflow
await page-archive({ pageId: 456 });

// Step 3: Delete
await page-delete({ pageId: 456 });
```

---

## Menu States

### State Machine

```
            ┌─────────────┐
            │   CREATE    │
            └──────┬──────┘
                   │
                   ▼
            ┌─────────────┐
            │    DRAFT    │◀─────┐
            └──────┬──────┘      │
                   │              │
                   │ publish      │ edit
                   ▼              │
            ┌─────────────┐      │
            │  PUBLISHED  │──────┘
            └──────┬──────┘
                   │ unpublish + delete
                   ▼
            ┌─────────────┐
            │   DELETED   │
            └─────────────┘
```

### Menu State Properties

```typescript
{
  id: number,
  name: string,
  slug: string,          // For Liquid: menus['slug']
  published: boolean,    // Is menu published?
  items: Array<{         // Menu items (hierarchical)
    id: number,
    label: string,
    url: string,
    position: number,
    parent_id: number | null,
    visible: boolean
  }>
}
```

### Menu States in Practice

**Draft Menu**:
```typescript
const menu = await navigation-menu-create({
  name: "Footer Links",
  slug: "footer-links"
});

// State: draft
// published: false
// Not in menus['footer-links'] Liquid drop
```

**Published Menu**:
```typescript
const elements = await release-get-elements-to-publish({ siteId: 4612 });
await release-create({ data: { menu: [{ id: menu.id, selected: true }] } });

// State: published
// published: true
// Accessible via menus['footer-links']
```

**Editing Published Menu**:
```typescript
// Add/update/delete items
await navigation-menu-add-item({
  menuId: menu.id,
  item: { label: "About", url: "/about" }
});

// State: published (old) + draft changes
// Must re-publish to see changes on site
```

---
