Files

448 lines
17 KiB
Markdown
Raw Permalink Normal View History

2026-04-23 01:08:18 +08:00
# Payload Schema — Remaining Collections and Globals (Final)
## Purpose
Final schema for every Payload collection and global used on the new Eversolo site, excluding Product (see `SCHEMA-PRODUCT.md`). This document is the source of truth for the Payload config.
## Shared Conventions
### Locales
- `en`, `zh`
- Field-level localization is used (not document-level).
- `**localized**` below means the field is per-locale.
- `**shared**` means a single value across locales.
### Status Workflow
All content-bearing collections share:
- `status`: `draft | review | published | archived`
- `publishedAt`: auto-set on first publish
- `createdAt`, `updatedAt`: auto
### Access Control
- Public read: only `status = published`.
- Write: authenticated editors and above.
- Admin-only fields are marked inline.
### SEO Group
Used on all public-facing documents:
- `title`**localized** — text, max 70.
- `description`**localized** — textarea, max 160.
- `ogImage`**shared** — upload.
- `canonical`**shared** — text, optional.
- `noIndex`**shared** — checkbox, admin-only, default false.
### Revalidation
Every collection that renders on the public site triggers on-demand revalidation of the affected route paths in its `afterChange` hook.
---
## Collections
### 1. Product Categories
Slug: `productCategories`
- `slug`**shared** — text, required, URL-safe, unique.
- `name`**localized** — text, required.
- `description`**localized** — rich text.
- `heroImage`**shared** — upload.
- `order`**shared** — number, default 0.
- `seo` — group (see SEO group).
#### Validation
- `slug` unique.
- `name` required per locale if that locale is published.
#### Admin UI Tabs
1. `Overview`: slug, name, description, order.
2. `Media`: heroImage.
3. `SEO`: seo.
---
### 2. FAQ
Slug: `faqs`
- `group`**shared** — select, required. Suggested values: `setup | streaming | connectivity | hardware | warranty | other`. Editable at admin level.
- `question`**localized** — text, required.
- `answer`**localized** — rich text, required.
- `relatedProducts`**shared** — relationship to `products`, multi-select, optional.
- `relatedDownloads`**shared** — relationship to `downloads`, multi-select, optional.
- `order`**shared** — number, default 0.
- `status`**shared** — select (see status workflow).
#### Listing
- Grouped by `group`, ordered by `order` ascending.
- Support page shows curated groups; dedicated FAQ page shows all published entries.
#### Validation
- `question` and `answer` required for any locale being published.
---
### 3. Downloads
Slug: `downloads`
- `title`**localized** — text, required.
- `type`**shared** — select, required. Values: `firmware | manual | software | other`.
- `product`**shared** — relationship to `products`, required.
- `version`**shared** — text, optional.
- `releaseDate`**shared** — date, optional.
- `file`**shared** — upload, required.
- `checksum`**shared** — text, optional.
- `changelog`**localized** — rich text, optional.
- `notes`**localized** — rich text, optional.
- `visibility` — group.
- `showInProductPage`**shared** — checkbox, default true.
- `showInDownloadsCenter`**shared** — checkbox, default true.
- `status`**shared** — select (see status workflow).
#### Rules
- Firmware display on product pages also requires the product's `firmware.showOnProductPage` toggle to be on.
- Firmware display in the Downloads center also requires the product's `firmware.showInDownloadsCenter` toggle to be on.
- `showInProductPage` and `showInDownloadsCenter` are download-level overrides: they can hide a specific file even when the product-level toggle is on.
#### Validation
- `title` required per published locale.
- `file` required.
- `product` required.
- `type` required.
#### Admin UI Tabs
1. `Overview`: title, type, product, version, releaseDate, status.
2. `File`: file, checksum.
3. `Content`: changelog, notes.
4. `Visibility`: visibility group.
---
### 4. Product Videos
Slug: `productVideos`
- `title`**shared** — text, required.
- `product`**shared** — relationship to `products`, required.
- `provider`**shared** — select, required. Values: `youtube | vimeo | bilibili | other`.
- `videoUrl`**shared** — text, required.
- `embedUrl`**shared** — text, optional.
- `thumbnail`**shared** — relationship to `media`, optional.
- `description`**localized** — rich text, optional.
- `publishedAt`**shared** — date, optional.
- `sortOrder`**shared** — number, default 0.
- `legacySourceUrl`**shared** — text, optional.
- `status`**shared** — select (see status workflow).
#### Rules
- Product detail pages render all published videos related to the current product, ordered by `sortOrder`, then newest first.
- Seed import may create draft records first; editors can refine descriptions later.
---
### 5. Product Reviews
Slug: `productReviews`
- `title`**shared** — text, required.
- `product`**shared** — relationship to `products`, required.
- `sourceName`**shared** — text, optional.
- `reviewUrl`**shared** — text, required.
- `thumbnail`**shared** — relationship to `media`, optional.
- `excerpt`**localized** — text, optional.
- `quote`**localized** — text, optional.
- `publishedAt`**shared** — date, optional.
- `sortOrder`**shared** — number, default 0.
- `legacySourceUrl`**shared** — text, optional.
- `status`**shared** — select (see status workflow).
#### Rules
- Product detail pages render all published reviews related to the current product, ordered by `sortOrder`, then newest first.
- Reviews may be imported from the legacy site with minimal metadata and enriched later in CMS.
---
### 6. Dealers
Slug: `dealers`
- `name`**shared** — text, required.
- `region`**shared** — select, required. Values mirror the Dealers page region filter.
- `country`**shared** — text, required.
- `city`**shared** — text, optional.
- `address`**localized** — textarea, optional.
- `email`**shared** — email, optional.
- `phone`**shared** — text, optional.
- `website`**shared** — URL, optional.
- `logo`**shared** — upload, optional.
- `isAuthorized`**shared** — checkbox, default true.
- `order`**shared** — number, default 0.
- `status`**shared** — select (see status workflow).
#### Listing
- Grouped by region, then country, then name.
- Only `isAuthorized = true` are shown in public lists.
---
### 7. News Articles
Slug: `news`
- `slug`**localized** — text, required, unique per locale.
- `category`**shared** — select, required. Values: `announcement | press | review | event`.
- `title`**localized** — text, required.
- `excerpt`**localized** — textarea, optional.
- `coverImage`**shared** — upload, required.
- `body`**localized** — rich text, required.
- `author`**shared** — text, optional.
- `source`**shared** — text, optional (for press / review entries).
- `sourceUrl`**shared** — URL, optional.
- `publishedAt`**shared** — date, required on publish.
- `relatedProducts`**shared** — relationship to `products`, multi-select, optional.
- `status`**shared** — select (see status workflow).
- `seo` — group.
#### Listing Rules
- News list: all published, newest first.
- Homepage news highlights: manually selected via Homepage global.
- Articles may exist in a single locale; the UI surfaces only locales with published content.
---
### 8. Media
Slug: `media`
Generic upload collection for images used across the site.
- `file` — upload, required.
- `alt`**localized** — text, required.
- `caption`**localized** — text, optional.
- `credit`**shared** — text, optional.
- `tags`**shared** — array of text.
#### Usage
Every image field in other collections references `media`. Editors upload once, reuse everywhere.
---
### 9. Videos
Slug: `videos`
Dedicated upload collection for video assets (hero videos, product showcase).
- `file` — upload, required.
- `poster` — relationship to `media`, required.
- `durationSeconds`**shared** — number, optional.
- `alt`**localized** — text, required.
- `tags`**shared** — array of text.
---
### 10. Files
Slug: `files`
Upload collection for firmware, manuals, software binaries, and other downloadable files. Used as the `file` reference on the `downloads` collection.
- `file` — upload, required.
- `sizeBytes`**shared** — number (auto).
- `mimeType`**shared** — text (auto).
---
### 11. Redirects
Slug: `redirects`
Source of truth for 301 redirects from the legacy site, including the entries documented in `REDIRECTS.md`.
- `from`**shared** — text, required. Matches a path or pattern on the legacy URL space.
- `to`**shared** — text, required. Destination path on the new site, locale-prefixed.
- `statusCode`**shared** — select, required. Values: `301 | 302 | 307 | 308`. Default `301`.
- `matchType`**shared** — select, required. Values: `exact | prefix | regex`. Default `exact`.
- `locale`**shared** — select, optional. Values: `any | en | zh`. Controls whether the redirect applies only to a locale-scoped target.
- `notes`**shared** — text, optional.
- `enabled`**shared** — checkbox, default true.
#### Rules
- Redirects are resolved at the edge in priority order: `exact` > `prefix` > `regex`.
- External links (Amazon, JD, Tmall, forum.zidoo, shop.zidoo, blog.eversolo) are not managed here.
- The APP header link points directly to `https://www.eversolo.com/controlapp/index.html` and is not stored as a redirect.
---
## Globals
### 1. Homepage
Slug: `homepage`
- `hero` — group.
- `mode`**shared** — select, required. Values: `image | video`. Default `image`.
- `image`**shared** — relationship to `media`, required when `mode = image`.
- `video`**shared** — relationship to `videos`, required when `mode = video`.
- `headline`**localized** — text, required.
- `supportingLine`**localized** — text, optional.
- `primaryCta` — group.
- `label`**localized** — text.
- `href`**shared** — text (internal path or URL).
- `secondaryCta` — group.
- `label`**localized** — text.
- `href`**shared** — text.
- `featuredProducts`**shared** — relationship to `products`, required, exactly 4.
- `statement` — group.
- `title`**localized** — text.
- `body`**localized** — rich text.
- `image`**shared** — relationship to `media`.
- `cta` — optional group of `{ label, href }`.
- `supportShortcuts` — array, 3 to 4 items.
- `label`**localized** — text, required.
- `description`**localized** — text.
- `href`**shared** — text, required.
- `recognition` — group.
- `awards`**shared** — array of `{ logo: media, label (localized), year, url }`.
- `reviews`**shared** — array of `{ sourceLogo: media, sourceName (localized), quote (localized), url }`.
- `newsHighlights`**shared** — relationship to `news`, up to 3, optional.
- `seo` — group.
#### Validation
- `featuredProducts` length must equal 4.
- `recognition.awards` should contain at least 1 item if the module is shown; otherwise leave empty.
---
### 2. Support Page
Slug: `supportPage`
- `intro` — group.
- `title`**localized** — text.
- `body`**localized** — rich text.
- `primaryEntries` — array, required, exactly 3.
- `key`**shared** — select, required. Values: `faq | warranty | contact`.
- `label`**localized** — text, required.
- `description`**localized** — text.
- `href`**shared** — text, required.
- `secondaryEntries` — array, 0 to 3 items.
- `key`**shared** — select. Values: `downloads | manuals | firmware`.
- `label`**localized** — text, required.
- `description`**localized** — text.
- `href`**shared** — text, required.
- `seo` — group.
---
### 3. Warranty Page
Slug: `warrantyPage`
- `intro` — group.
- `title`**localized** — text.
- `body`**localized** — rich text.
- `policyBody`**localized** — rich text, required.
- `regionalNotes` — array.
- `region`**shared** — select.
- `body`**localized** — rich text.
- `registrationCta` — optional group of `{ label, href }`.
- `seo` — group.
---
### 4. Contact Page
Slug: `contactPage`
- `intro` — group.
- `title`**localized** — text.
- `body`**localized** — rich text.
- `regions` — array.
- `region`**shared** — select.
- `email`**shared** — email.
- `phone`**shared** — text.
- `address`**localized** — textarea.
- `hours`**localized** — text.
- `formEnabled`**shared** — checkbox, default true.
- `formSuccessMessage`**localized** — rich text.
- `seo` — group.
---
### 5. About Page
Slug: `aboutPage`
- `intro` — group.
- `title`**localized** — text.
- `body`**localized** — rich text.
- `brandStory`**localized** — rich text.
- `philosophy`**localized** — rich text.
- `milestones` — array.
- `year`**shared** — number.
- `title`**localized** — text.
- `description`**localized** — rich text.
- `image`**shared** — relationship to `media`, optional.
- `seo` — group.
---
### 6. Global Settings
Slug: `globalSettings`
- `site` — group.
- `name`**localized** — text.
- `logoLight`**shared** — relationship to `media`.
- `logoDark`**shared** — relationship to `media`.
- `favicon`**shared** — relationship to `media`.
- `navigation` — group.
- `primary` — array, required. Each item:
- `label`**localized** — text.
- `href`**shared** — text.
- `external`**shared** — checkbox, default false.
- `openInNewTab`**shared** — checkbox, default false.
- `iconKey`**shared** — text, optional (for future icon support).
- `app` — group (singleton inside navigation).
- `label`**localized** — text, default `APP`.
- `href`**shared** — text, required, default `https://www.eversolo.com/controlapp/index.html`.
- `openInNewTab`**shared** — checkbox, default true.
- `showOnDesktop`**shared** — checkbox, default true.
- `showOnMobile`**shared** — checkbox, default true.
- `footer` — group.
- `columns` — array.
- `title`**localized** — text.
- `items` — array of `{ label (localized), href, external, openInNewTab }`.
- `legalLinks` — array of `{ label (localized), href }`.
- `copyright`**localized** — text.
- `social` — array of `{ platform, url, iconKey }`.
- `languageSwitcher` — group.
- `labels` — per-locale `{ en: "English", zh: "简体中文" }`.
- `analytics` — group.
- `provider` — select: `plausible | ga4 | none`.
- `domain` — text.
- `measurementId` — text.
- `seoDefaults` — group.
- `titleSuffix`**localized** — text.
- `description`**localized** — textarea.
- `ogImage`**shared** — relationship to `media`.
- `cookieBanner` — group.
- `enabled`**shared** — checkbox, default true.
- `body`**localized** — rich text.
- `acceptLabel`**localized** — text.
- `declineLabel`**localized** — text.
#### Notes
- The header APP entry is driven by `navigation.app` so editors can update the label, URL, and visibility without a code change.
- `openInNewTab` defaults to true for external items.
---
## Hooks (cross-collection)
- `afterChange` on any publishable document:
- Revalidate affected public routes.
- Revalidate Homepage if the document is referenced in Homepage fields.
- `beforeValidate` on any slug field:
- Normalize (lowercase, trim, dashes, ASCII fallback).
- `beforeChange` on `status`:
- Set `publishedAt` on first transition to `published`.
## Admin UX Principles
- Use tabs per collection to separate structural, content, media, and SEO fields.
- Globals use grouped sections rather than tabs to stay editor-friendly.
- Every relationship field is labeled with its expected content type and any filters applied.
- Locale selector is persistent across the admin UI.
## Open Items
- Whether Redirects are managed in CMS or in a versioned file; current plan: CMS-managed for editor control.
- Whether News articles should support per-locale `status` separately.
- Whether the Dealers region list should be a CMS-managed enum or hardcoded.
- Whether the Homepage `recognition` module should allow a layout choice (logo wall vs quote strip) per locale.