chore: complete M1.1 runtime QA and release packaging

This commit is contained in:
XShop
2026-09-13 19:04:41 +03:30
commit f11e1d650d
66 changed files with 3094 additions and 0 deletions
+80
View File
@@ -0,0 +1,80 @@
# XShop – Database Model
## 1. Philosophy
Reuse WP/WC primitives. No custom tables in v1.0 – revisit via ADR if query scale warrants. Document every key.
## 2. WordPress-Owned
- **Users** (`wp_users`, `wp_usermeta`): native. XShop adds: `xshop_wishlist` (array of product IDs), `xshop_compare` (array), `xshop_recently_viewed` (capped list).
- **Posts/Pages** (`wp_posts`, `wp_postmeta`): native.
- **Media** (`wp_posts` attachment): native.
- **Menus** (`wp_terms` nav_menu): native.
- **Comments/Reviews**: WC reviews = WP comments on `product` post type. XShop Q&A moderation hooks onto comment moderation flow where applicable – but primary store is custom (below).
## 3. WooCommerce-Owned
- **Products** (`wp_posts` post_type `product` + `wp_postmeta` + `wp_wc_*` where HPOS enabled). Variations are `product_variation` children.
- **Orders/Customers/Coupons/Shipping/Payment/Taxes/Cart/Checkout**: WC owned (HPOS tables if enabled). XShop never writes directly to WC order tables except via WC APIs.
## 4. XShop-Core Custom Data
### 4.1 Banners – CPT `xshop_banner`
- `post_type = xshop_banner` (non-public, `show_ui` true under XShop menu).
- Meta:
- `_xshop_banner_image` (attachment ID, int)
- `_xshop_banner_mobile_image` (attachment ID, int, nullable)
- `_xshop_banner_link` (url, esc_url_raw)
- `_xshop_banner_cta` (string)
- `_xshop_banner_position` (enum: `home_hero`, `home_strip`, `shop_top`, `product_sidebar`, etc.)
- `_xshop_banner_active` (`1`|`0`)
- `_xshop_banner_start` / `_xshop_banner_end` (datetime Y-m-d H:i:s, UTC)
- `_xshop_banner_order` (int)
- Scheduling checked on render (skip if outside window or inactive).
### 4.2 Questions & Answers – CPT `xshop_qa`
Decision: CPT (not comments) for cleaner moderation + threading without polluting reviews.
- `post_type = xshop_qa`, `post_parent` = product ID (or meta `_xshop_qa_product_id` for query flexibility – both stored, parent is canonical).
- Post fields: `post_title` empty, `post_content` = question body, `post_status` = `pending`|`publish`|`trash`, `post_author` = asker.
- Meta:
- `_xshop_qa_product_id` (int, indexed via meta query)
- `_xshop_qa_answer` (string, nullable – single answer for v1; extension to multiple answers uses child `xshop_qa` rows with `post_parent` = question ID in v1.1)
- `_xshop_qa_answered_by` (int user ID)
- `_xshop_qa_answered_at` (datetime)
- Alternative for multiple answers (future): child posts `post_type=xshop_qa`, `post_parent=question ID`.
- Spam: honeypot + nonce + rate limit (transient per IP/user, 60s).
### 4.3 Wishlist & Compare
- **Logged-in**: `wp_usermeta` keys `xshop_wishlist`, `xshop_compare` (serialized array of ints, capped: wishlist 200, compare 4).
- **Guest**: cookie `xshop_wishlist` / `xshop_compare` (JSON, HttpOnly false for JS count, SameSite Lax, 30 days) + optional transient `xshop_guest_<token>`.
- On login: merge cookie → user meta (union, cap), clear cookie.
- Counts exposed via REST and localized script data.
### 4.4 Recently Viewed
- Cookie `xshop_recently_viewed` (JSON array of product IDs, capped 20, 30 days). No DB write for guests. Logged-in also stored in `xshop_recently_viewed` user meta for cross-device.
## 5. Options
- Single option `xshop_settings` (array) – all Theme Options. Autoload `yes`. Individual mods also mirrored via `theme_mod` for Customizer preview where needed, but source of truth is `xshop_settings`.
- Option `xshop_settings_backup` (for import/export).
- Transient `xshop_search_cache_<hash>` (5 min) for AJAX search results.
- Transient `xshop_filter_counts_<hash>` (5 min) for filter counts.
Do NOT scatter random options.
## 6. Indexes & Query Patterns
- Banners: query by `post_type` + meta `position`+`active`+date range → meta query; small cardinality.
- Q&A: `WP_Query` by `post_type=xshop_qa` + `post_parent=product_id` + `post_status=publish` (index on `post_parent` + `post_type` already exists).
- Wishlist/Compare: user meta single-row lookup – O(1).
- Search: `WP_Query` with `s` + `post_type=product` + `tax_query` for category, `meta_query` for SKU (`_sku`), limited to 8 suggestions, `no_found_rows` true, `fields=ids` then prime caches.
## 7. Migrations & Compatibility
- HPOS: use `wc_get_products()` / CRUD, not direct `wp_postmeta` writes for product data.
- On plugin deactivate: data retained (no destructive cleanup). Uninstall hook offered to purge (`uninstall.php` with confirmation).