Files
WooNooW/PROJECT_SOP.md

991 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🧭 WooNooW — Single Source of Truth (S.O.P.)
This document defines the **Standard Operating Procedure** for developing, maintaining, and collaborating on the **WooNooW** project — ensuring every AI Agent or human collaborator follows the same workflow and conventions.
---
## 1. 🎯 Project Intent
WooNooW modernizes WooCommerce **without migration**, delivering a Hybrid + SPA experience for both **storefront** and **admin**, while keeping compatibility with legacy WooCommerce addons.
> **Goal:** “Reimagine WooCommerce for now — faster, modern, reversible.”
---
## 1.1 📝 Documentation Standards
### Progress & Testing Documentation
**All progress notes and reports MUST be added to:**
- `PROGRESS_NOTE.md` - Consolidated progress tracking with timestamps
**All test checklists MUST be added to:**
- `TESTING_CHECKLIST.md` - Comprehensive testing requirements
**Feature-specific documentation:**
- Create dedicated `.md` files for major features (e.g., `PAYMENT_GATEWAY_INTEGRATION.md`)
- Link to these files from `PROGRESS_NOTE.md`
- Include implementation details, code examples, and testing steps
**Documentation Rules:**
1. ✅ Update `PROGRESS_NOTE.md` after completing any major feature
2. ✅ Add test cases to `TESTING_CHECKLIST.md` before implementation
3. ✅ Use consistent formatting (emojis, headings, code blocks)
4. ✅ Include "Last synced" timestamp in GMT+7
5. ✅ Reference file paths and line numbers for code changes
---
## 2. 🧱 Core Principles
1. **Zero Data Migration** — All data remains in WooCommerces database schema.
2. **Safe Activation/Deactivation** — Deactivating WooNooW restores vanilla Woo instantly.
3. **HPOS-First Architecture** — Mandatory use of WooCommerce HPOS.
4. **Hybrid by Default** — SSR + React SPA islands for Cart, Checkout, and MyAccount.
5. **Full SPA Option** — Optional React-only mode for performance-critical sites.
6. **Compat Layer** — HookBridge & SlotRenderer preserve legacy addon behavior.
7. **Async System** — MailQueue & async actions replace blocking PHP tasks.
---
## 3. ⚙️ Tech Stack Reference
| Layer | Technology |
|-------|-------------|
| Backend | PHP 8.2+, WordPress, WooCommerce (HPOS), Action Scheduler |
| Frontend | React 18 + TypeScript, Vite, React Query, Tailwind CSS + Shadcn UI, Recharts |
| Architecture | Modular PSR4 autoload, RESTdriven logic, SPA hydration islands |
| Build | Composer + NPM + ESM scripts |
| Packaging | `scripts/package-zip.mjs` |
| Deployment | LocalWP for dev, Coolify for staging |
---
## 4. 🧩 Folder Structure
```
woonoow/
├─ woonoow.php # main plugin file (WordPress entry)
├─ includes/ # PSR4 classes
│ ├─ Core/ # Bootstrap, Datastores, Mail, Hooks
│ ├─ Api/ # REST endpoints
│ ├─ Admin/ # Menus, asset loaders
│ ├─ Compat/ # Compatibility shims & hook mirrors
│ └─ …
├─ admin-spa/ # React admin interface
├─ customer-spa/ # React customer interface
├─ scripts/ # automation scripts
│ └─ package-zip.mjs
├─ dist/ # build output
├─ composer.json
├─ package.json
├─ README.md
└─ PROJECT_SOP.md # this file
```
---
## 5. 🧰 Development Workflow
### 5.1 Environment Setup
1. Use **LocalWP** or **Docker** (PHP 8.2+, MySQL 8, Redis optional).
2. Clone or mount `woonoow` folder into `/wp-content/plugins/`.
3. Ensure WooCommerce is installed and active.
4. Activate WooNooW in wp-admin → “Plugins.”
### 5.2 Build & Test Commands
```bash
npm run build # build both admin & customer SPAs
npm run pack # create woonoow.zip for release
composer dump-autoload
```
### 5.3 Plugin Packaging
- The release ZIP must contain only:
```
woonoow.php
includes/
admin-spa/dist/
customer-spa/dist/
composer.json
package.json
phpcs.xml
README.md
```
- Build ZIP using:
```bash
node scripts/package-zip.mjs
```
### 5.4 Commit Convention
Use conventional commits:
```
feat(api): add checkout quote endpoint
fix(core): prevent duplicate email send on async queue
refactor(admin): improve SPA routing
```
### 5.5 Branching
- `main` — stable, production-ready
- `dev` — development staging
- `feature/*` — specific features or fixes
### 5.6 Admin SPA Template Pattern
The WooNooW Admin SPA follows a consistent layout structure ensuring a predictable UI across all routes:
**Structure**
```
Admin-SPA
├── App Bar [Branding | Version | Server Connectivity | Global Buttons (Fullscreen)]
├── Menu Bar (Main Menu) [Normal (Tabbed Overflow-X-Auto)] [Fullscreen (Sidebar)]
├── Submenu Bar (Tabbed Overflow-X-Auto, context-sensitive)
└── Page Template
├── Page Tool Bar (Page filters, CRUD buttons, Back button)
└── Page Content (Data tables, cards, forms)
```
**Behavioral Notes**
- `App Bar`: Persistent across all routes; contains global controls (fullscreen, server, user menu).
- `Menu Bar`: Primary navigation for main sections (Dashboard, Orders, Products, etc.); sticky with overflow-x scroll.
- `Submenu Bar`: Context-sensitive secondary tabs under the main menu.
- `Page Tool Bar`: Contains functional filters and actions relevant to the current page.
- `Page Content`: Hosts the page body—tables, analytics, and CRUD forms.
- In Fullscreen mode, `Menu Bar` becomes a collapsible sidebar while all others remain visible.
- Sticky layout rules ensure `App Bar` and `Menu Bar` remain fixed while content scrolls independently.
### 5.7 Mobile Responsiveness & UI Controls
WooNooW enforces a mobilefirst responsive standard across all SPA interfaces to ensure usability on small screens.
**Control Sizing Standard (`.ui-ctrl`)**
- All interactive controls — input, select, button, and dropdown options — must include the `.ui-ctrl` class or equivalent utility for consistent sizing.
- Default height: `h-11` (mobile), `md:h-9` (desktop).
- This sizing improves tap area accessibility and maintains visual alignment between mobile and desktop.
**Responsive Layout Rules**
- On mobile view, even in fullscreen mode, the layout uses **Topbar navigation** instead of Sidebar for better reachability.
- The Sidebar layout is applied **only** in desktop fullscreen mode.
- Sticky top layers (`App Bar`, `Menu Bar`) remain visible while subcontent scrolls independently.
- Tables and grids must support horizontal scroll (`overflow-x-auto`) and collapse to cards when screen width < 640px.
**Tokens & Global Styles**
- File: `admin-spa/src/ui/tokens.css` defines base CSS variables for control sizing.
- File: `admin-spa/src/index.css` imports `./ui/tokens.css` and applies the `.ui-ctrl` rules globally.
These rules ensure consistent UX across device classes while maintaining WooNooWs design hierarchy.
### 5.8 Error Handling & User Notifications
WooNooW implements a centralized, user-friendly error handling system that ensures consistent UX across all features.
**Core Principles**
1. **Never expose technical details** to end users (no "API 500", stack traces, or raw error codes)
2. **Use appropriate notification types** based on context
3. **Provide actionable feedback** with clear next steps
4. **Maintain consistency** across all pages and features
**Notification Types**
| Context | Component | Use Case | Example |
|---------|-----------|----------|---------|
| **Page Load Errors** | `<ErrorCard>` | Query failures, data fetch errors | "Failed to load orders" with retry button |
| **Action Errors** | `toast.error()` | Mutation failures, form submissions | "Failed to create order. Please check all required fields." |
| **Action Success** | `toast.success()` | Successful mutations | "Order created successfully" |
| **Inline Validation** | `<ErrorMessage>` | Form field errors | "Email address is required" |
**Implementation**
```typescript
// For mutations (create, update, delete)
import { showErrorToast, showSuccessToast } from '@/lib/errorHandling';
const mutation = useMutation({
mutationFn: OrdersApi.create,
onSuccess: (data) => {
showSuccessToast('Order created successfully', `Order #${data.number} created`);
},
onError: (error) => {
showErrorToast(error); // Automatically extracts user-friendly message
}
});
// For queries (page loads)
import { ErrorCard } from '@/components/ErrorCard';
import { getPageLoadErrorMessage } from '@/lib/errorHandling';
if (query.isError) {
return <ErrorCard
title="Failed to load data"
message={getPageLoadErrorMessage(query.error)}
onRetry={() => query.refetch()}
/>;
}
```
**Error Message Mapping**
Backend errors are mapped to user-friendly messages in `lib/errorHandling.ts`:
```typescript
const friendlyMessages = {
'no_items': 'Please add at least one product to the order',
'create_failed': 'Failed to create order. Please check all required fields.',
'update_failed': 'Failed to update order. Please check all fields.',
'not_found': 'The requested item was not found',
'forbidden': 'You do not have permission to perform this action',
};
```
**Toast Configuration**
- **Position:** Bottom-right
- **Duration:** 4s (success), 6s (errors)
- **Theme:** Light mode with colored backgrounds
- **Colors:** Green (success), Red (error), Amber (warning), Blue (info)
**Files**
- `admin-spa/src/lib/errorHandling.ts` — Centralized error utilities
- `admin-spa/src/components/ErrorCard.tsx` — Page load error component
- `admin-spa/src/components/ui/sonner.tsx` — Toast configuration
### 5.9 Data Validation & Required Fields
WooNooW enforces strict validation rules to ensure data integrity and provide clear feedback to users.
**Order Creation Validation**
All orders must include:
| Field | Requirement | Error Message |
|-------|-------------|---------------|
| **Products** | At least 1 product | "At least one product is required" |
| **Billing First Name** | Required | "Billing first name is required" |
| **Billing Last Name** | Required | "Billing last name is required" |
| **Billing Email** | Required & valid format | "Billing email is required" / "Billing email is not valid" |
| **Billing Address** | Required | "Billing address is required" |
| **Billing City** | Required | "Billing city is required" |
| **Billing Postcode** | Required | "Billing postcode is required" |
| **Billing Country** | Required | "Billing country is required" |
**Backend Validation Response**
When validation fails, the API returns:
```json
{
"error": "validation_failed",
"message": "Please complete all required fields",
"fields": [
"Billing first name is required",
"Billing email is required",
"Billing address is required"
]
}
```
**Frontend Display**
The error handling utility automatically formats field errors as a bulleted list:
```
❌ Please complete all required fields
• Billing first name is required
• Billing email is required
• Billing address is required
• Billing city is required
• Billing postcode is required
```
Each field error appears as a bullet point on its own line, making it easy for users to scan and see exactly what needs to be fixed.
**Implementation Location**
- Backend validation: `includes/Api/OrdersController.php` create() method
- Frontend handling: `admin-spa/src/lib/errorHandling.ts` getErrorMessage()
### 5.10 Internationalization (i18n)
WooNooW follows WordPress translation standards to ensure all user-facing strings are translatable.
**Text Domain:** `woonoow`
**Backend (PHP)**
Use WordPress translation functions:
```php
// Simple translation
__( 'Billing first name', 'woonoow' )
// Translation with sprintf
sprintf( __( '%s is required', 'woonoow' ), $field_label )
// Translators comment for context
/* translators: %s: field label */
sprintf( __( '%s is required', 'woonoow' ), $label )
```
**Frontend (TypeScript/React)**
Use the i18n utility wrapper:
```typescript
import { __, sprintf } from '@/lib/i18n';
// Simple translation
__('Failed to load data')
// Translation with sprintf (placeholders)
sprintf(__('Order #%s created'), orderNumber)
sprintf(__('Edit Order #%s'), orderId)
// In components
<button>{__('Try again')}</button>
<h2>{sprintf(__('Order #%s'), order.number)}</h2>
// In error messages
const title = __('Please complete all required fields');
const message = sprintf(__('Order #%s has been created'), data.number);
```
**Translation Files**
- Backend strings: Extracted to `languages/woonoow.pot`
- Frontend strings: Loaded via `wp.i18n` (WordPress handles this)
- Translation utilities: `admin-spa/src/lib/i18n.ts`
**Best Practices**
1. **Never hardcode user-facing strings** - Always use translation functions
2. **Use translators comments** for context when using placeholders
3. **Keep strings simple** - Avoid complex concatenation
4. **Test in English first** - Ensure strings make sense before translation
---
## 5.11 Loading States
WooNooW provides a **consistent loading UI system** across the application to ensure a polished user experience.
**Component:** `admin-spa/src/components/LoadingState.tsx`
### Loading Components
**1. LoadingState (Default)**a
```typescript
import { LoadingState } from '@/components/LoadingState';
// Default loading
<LoadingState />
// Custom message
<LoadingState message={__('Loading order...')} />
// Different sizes
<LoadingState size="sm" message={__('Saving...')} />
<LoadingState size="md" message={__('Loading...')} /> // default
<LoadingState size="lg" message={__('Processing...')} />
// Full screen overlay
<LoadingState fullScreen message={__('Loading...')} />
```
**2. PageLoadingState**
```typescript
import { PageLoadingState } from '@/components/LoadingState';
// For full page loads
if (isLoading) {
return <PageLoadingState message={__('Loading order...')} />;
}
```
**3. InlineLoadingState**
```typescript
import { InlineLoadingState } from '@/components/LoadingState';
// For inline loading within components
{isLoading && <InlineLoadingState message={__('Loading...')} />}
```
**4. CardLoadingSkeleton**
```typescript
import { CardLoadingSkeleton } from '@/components/LoadingState';
// For loading card content
{isLoading && <CardLoadingSkeleton />}
```
**5. TableLoadingSkeleton**
```typescript
import { TableLoadingSkeleton } from '@/components/LoadingState';
// For loading table rows
{isLoading && <TableLoadingSkeleton rows={10} />}
```
### Usage Guidelines
**Page-Level Loading:**
```typescript
// ✅ Good - Use PageLoadingState for full page loads
if (orderQ.isLoading || countriesQ.isLoading) {
return <PageLoadingState message={sprintf(__('Loading order #%s...'), orderId)} />;
}
// ❌ Bad - Don't use plain text
if (isLoading) {
return <div>Loading...</div>;
}
```
**Inline Loading:**
```typescript
// ✅ Good - Use InlineLoadingState for partial loads
{q.isLoading && <InlineLoadingState message={__('Loading order...')} />}
// ❌ Bad - Don't use custom spinners
{q.isLoading && <div><Loader2 className="animate-spin" /> Loading...</div>}
```
**Table Loading:**
```typescript
// ✅ Good - Use TableLoadingSkeleton for tables
{q.isLoading && <TableLoadingSkeleton rows={10} />}
// ❌ Bad - Don't show empty state while loading
{q.isLoading && <div>Loading data...</div>}
```
### Best Practices
1. **Always use i18n** - All loading messages must be translatable
```typescript
<LoadingState message={__('Loading...')} />
```
2. **Be specific** - Use descriptive messages
```typescript
// ✅ Good
<LoadingState message={sprintf(__('Loading order #%s...'), orderId)} />
// ❌ Bad
<LoadingState message="Loading..." />
```
3. **Choose appropriate size** - Match the context
- `sm` - Inline, buttons, small components
- `md` - Default, cards, sections
- `lg` - Full page, important actions
4. **Use skeletons for lists** - Better UX than spinners
```typescript
{isLoading ? <TableLoadingSkeleton rows={5} /> : <Table data={data} />}
```
5. **Responsive design** - Loading states work on all screen sizes
- Mobile: Optimized spacing and sizing
- Desktop: Full layout preserved
### Pattern Examples
**Order Edit Page:**
```typescript
export default function OrdersEdit() {
const orderQ = useQuery({ ... });
if (orderQ.isLoading) {
return <LoadingState message={sprintf(__('Loading order #%s...'), orderId)} />;
}
return <OrderForm ... />;
}
```
**Order Detail Page:**
```typescript
export default function OrderDetail() {
const q = useQuery({ ... });
return (
<div>
<h1>{__('Order Details')}</h1>
{q.isLoading && <InlineLoadingState message={__('Loading order...')} />}
{q.data && <OrderContent order={q.data} />}
</div>
);
}
```
**Orders List:**
```typescript
export default function OrdersList() {
const q = useQuery({ ... });
return (
<table>
<thead>...</thead>
<tbody>
{q.isLoading && <TableLoadingSkeleton rows={10} />}
{q.data?.map(order => <OrderRow key={order.id} order={order} />)}
</tbody>
</table>
);
}
```
---
## 6. 🔌 Addon Development Standards
### 6.1 Addon Injection System
WooNooW provides a **filter-based addon injection system** that allows third-party plugins to integrate seamlessly with the SPA without modifying core files.
**Core Principle:** All modules that can accept external injection MUST provide filter hooks following the standard naming convention.
### 6.2 Hook Naming Convention
All WooNooW hooks follow this structure:
```
woonoow/{category}/{action}[/{subcategory}]
```
**Examples:**
- `woonoow/addon_registry` - Register addon metadata
- `woonoow/spa_routes` - Register SPA routes
- `woonoow/nav_tree` - Modify navigation tree
- `woonoow/nav_tree/products/children` - Inject into Products submenu
- `woonoow/dashboard/widgets` - Add dashboard widgets (future)
- `woonoow/order/detail/panels` - Add order detail panels (future)
**Rules:**
1. Always prefix with `woonoow/`
2. Use lowercase with underscores
3. Use singular nouns for registries (`addon_registry`, not `addons_registry`)
4. Use hierarchical structure for nested items
5. Use descriptive names that indicate purpose
### 6.3 Filter Template Pattern
When creating a new module that accepts external injection, follow this template:
#### **Backend (PHP)**
```php
<?php
namespace WooNooW\Compat;
class MyModuleRegistry {
const OPTION_KEY = 'wnw_my_module_data';
const VERSION = '1.0.0';
public static function init() {
add_action('plugins_loaded', [__CLASS__, 'collect_data'], 30);
add_action('activated_plugin', [__CLASS__, 'flush']);
add_action('deactivated_plugin', [__CLASS__, 'flush']);
}
public static function collect_data() {
$data = [];
/**
* Filter: woonoow/my_module/items
*
* Allows addons to register items with this module.
*
* @param array $data Array of item configurations
*
* Example:
* add_filter('woonoow/my_module/items', function($data) {
* $data['my-item'] = [
* 'id' => 'my-item',
* 'label' => 'My Item',
* 'value' => 'something',
* ];
* return $data;
* });
*/
$data = apply_filters('woonoow/my_module/items', $data);
// Validate and store
$validated = self::validate_items($data);
update_option(self::OPTION_KEY, [
'version' => self::VERSION,
'items' => $validated,
'updated' => time(),
], false);
}
private static function validate_items(array $items): array {
// Validation logic
return $items;
}
public static function get_items(): array {
$data = get_option(self::OPTION_KEY, []);
return $data['items'] ?? [];
}
public static function flush() {
delete_option(self::OPTION_KEY);
}
public static function get_frontend_data(): array {
// Return sanitized data for frontend
return self::get_items();
}
}
```
#### **Expose to Frontend (Assets.php)**
```php
// In localize_runtime() method
wp_localize_script($handle, 'WNW_MY_MODULE', MyModuleRegistry::get_frontend_data());
wp_add_inline_script($handle, 'window.WNW_MY_MODULE = window.WNW_MY_MODULE || WNW_MY_MODULE;', 'after');
```
#### **Frontend (TypeScript)**
```typescript
// Read from window
const moduleData = (window as any).WNW_MY_MODULE || [];
// Use in component
function MyComponent() {
const items = (window as any).WNW_MY_MODULE || [];
return (
<div>
{items.map(item => (
<div key={item.id}>{item.label}</div>
))}
</div>
);
}
```
### 6.4 Documentation Requirements
When adding a new filter hook, you MUST:
1. **Add to Hook Registry** (see section 6.5)
2. **Document in code** with PHPDoc
3. **Add example** in ADDON_INJECTION_GUIDE.md
4. **Update** ADDONS_ADMIN_UI_REQUIREMENTS.md
### 6.5 Hook Registry
See `HOOKS_REGISTRY.md` for complete list of available hooks and filters.
### 6.6 Non-React Addon Development
**Question:** Can developers build addons without React?
**Answer:** **YES!** WooNooW supports multiple addon approaches:
#### **Approach 1: PHP + HTML/CSS/JS (No React)**
Traditional WordPress addon development works perfectly:
```php
<?php
/**
* Plugin Name: My Traditional Addon
*/
// Register addon
add_filter('woonoow/addon_registry', function($addons) {
$addons['my-addon'] = [
'id' => 'my-addon',
'name' => 'My Addon',
'version' => '1.0.0',
];
return $addons;
});
// Add navigation item that links to classic admin page
add_filter('woonoow/nav_tree', function($tree) {
$tree[] = [
'key' => 'my-addon',
'label' => 'My Addon',
'path' => '/my-addon-classic', // Will redirect to admin page
'icon' => 'puzzle',
'children' => [],
];
return $tree;
});
// Register classic admin page
add_action('admin_menu', function() {
add_menu_page(
'My Addon',
'My Addon',
'manage_options',
'my-addon-page',
'my_addon_render_page',
'dashicons-admin-generic',
30
);
});
function my_addon_render_page() {
?>
<div class="wrap">
<h1>My Traditional Addon</h1>
<p>Built with PHP, HTML, CSS, and vanilla JS!</p>
<script>
// Vanilla JavaScript works fine
document.addEventListener('DOMContentLoaded', function() {
console.log('My addon loaded!');
});
</script>
</div>
<?php
}
```
**This approach:**
- ✅ Works with WooNooW navigation
- ✅ No React knowledge required
- ✅ Uses standard WordPress admin pages
- ✅ Can use WordPress admin styles
- ✅ Can enqueue own CSS/JS
- ⚠️ Opens in separate page (not SPA)
#### **Approach 2: Vanilla JS Component (No React)**
For developers who want SPA integration without React:
```javascript
// dist/MyAddon.js - Vanilla JS module
export default function MyAddonPage(props) {
const container = document.createElement('div');
container.className = 'p-6';
container.innerHTML = `
<div class="rounded-lg border border-border p-6 bg-card">
<h2 class="text-xl font-semibold mb-2">My Addon</h2>
<p class="text-sm opacity-70">Built with vanilla JavaScript!</p>
<button id="my-button" class="px-4 py-2 bg-blue-500 text-white rounded">
Click Me
</button>
</div>
`;
// Add event listeners
setTimeout(() => {
const button = container.querySelector('#my-button');
button.addEventListener('click', () => {
alert('Vanilla JS works!');
});
}, 0);
return container;
}
```
**This approach:**
- ✅ Integrates with SPA
- ✅ No React required
- ✅ Can use Tailwind classes
- ✅ Can fetch from REST API
- ⚠️ Must return DOM element
- ⚠️ Manual state management
#### **Approach 3: React Component (Full SPA)**
For developers comfortable with React:
```typescript
// dist/MyAddon.tsx - React component
import React from 'react';
export default function MyAddonPage() {
const [count, setCount] = React.useState(0);
return (
<div className="p-6">
<div className="rounded-lg border border-border p-6 bg-card">
<h2 className="text-xl font-semibold mb-2">My Addon</h2>
<p className="text-sm opacity-70">Built with React!</p>
<button
onClick={() => setCount(count + 1)}
className="px-4 py-2 bg-blue-500 text-white rounded"
>
Clicked {count} times
</button>
</div>
</div>
);
}
```
**This approach:**
- ✅ Full SPA integration
- ✅ React state management
- ✅ Can use React Query
- ✅ Can use WooNooW components
- ✅ Best UX
- ⚠️ Requires React knowledge
### 6.7 Addon Development Checklist
When creating a module that accepts addons:
- [ ] Create Registry class (e.g., `MyModuleRegistry.php`)
- [ ] Add filter hook with `woonoow/` prefix
- [ ] Document filter in PHPDoc with example
- [ ] Expose data to frontend via `Assets.php`
- [ ] Add to `HOOKS_REGISTRY.md`
- [ ] Add example to `ADDON_INJECTION_GUIDE.md`
- [ ] Test with example addon
- [ ] Update `ADDONS_ADMIN_UI_REQUIREMENTS.md`
### 6.8 Orders Module as Reference
The **Orders module** is the reference implementation:
- No external injection (by design)
- Clean route structure
- Type-safe components
- Proper error handling
- Mobile responsive
- i18n complete
Use Orders as the template for building new core modules.
---
## 7. 🎨 Admin Interface Modes
WooNooW provides **three distinct admin interface modes** to accommodate different workflows and user preferences:
### **1. Normal Mode (wp-admin)**
- **Access:** `/wp-admin/admin.php?page=woonoow`
- **Layout:** Traditional WordPress admin with WooNooW SPA in content area
- **Use Case:** Standard WordPress admin workflow
- **Features:**
- WordPress admin bar and sidebar visible
- Full WordPress admin functionality
- WooNooW SPA integrated seamlessly
- Settings submenu hidden (use WooCommerce settings)
- **When to use:** When you need access to other WordPress admin features alongside WooNooW
### **2. Fullscreen Mode**
- **Access:** Toggle button in WooNooW header
- **Layout:** WooNooW SPA only (no WordPress chrome)
- **Use Case:** Focused work sessions, order processing
- **Features:**
- Maximized workspace
- Distraction-free interface
- All WooNooW features accessible
- Settings submenu hidden
- **When to use:** When you want to focus exclusively on WooNooW tasks
### **3. Standalone Mode** ✨
- **Access:** `https://yoursite.com/admin`
- **Layout:** Complete standalone application with custom login
- **Use Case:** Quick daily access, mobile-friendly, bookmark-able
- **Features:**
- Custom login page (`/admin#/login`)
- WordPress authentication integration
- Settings submenu visible (SPA settings pages)
- "WordPress" button to access wp-admin
- "Logout" button in header
- Admin bar link in wp-admin to standalone
- Session persistence across modes
- **When to use:** As your primary WooNooW interface, especially on mobile or for quick access
### **Mode Switching**
- **From wp-admin to Standalone:** Click "WooNooW" in admin bar
- **From Standalone to wp-admin:** Click "WordPress" button in header
- **To Fullscreen:** Click fullscreen toggle in any mode
- **Session persistence:** Login state is shared across all modes
### **Settings Submenu Behavior**
- **Normal Mode:** No settings submenu (use WooCommerce settings in wp-admin)
- **Fullscreen Mode:** No settings submenu
- **Standalone Mode:** Full settings submenu visible with SPA pages
**Implementation:** Settings submenu uses dynamic getter in `admin-spa/src/nav/tree.ts`:
```typescript
get children() {
const isStandalone = (window as any).WNW_CONFIG?.standaloneMode;
if (!isStandalone) return [];
return [ /* settings items */ ];
}
```
---
## 8. 🤖 AI Agent Collaboration Rules
When using an AI IDE agent (ChatGPT, Claude, etc.):
### Step 1: Context Injection
Always load:
- `README.md`
- `PROJECT_SOP.md`
- The specific file(s) being edited
### Step 2: Editing Rules
1. All AI edits must be **idempotent** — never break structure or naming conventions.
2. Always follow PSR12 PHP standard and React code conventions.
3. When unsure about a design decision, **refer back to this S.O.P.** before guessing.
4. New files must be registered in the correct namespace path.
5. When editing React components, ensure build compatibility with Vite.
### Step 3: Communication
AI agents must:
- Explain each patch clearly.
- Never autoremove code without reason.
- Maintain English for all code comments, Markdown for docs.
---
## 7. 📦 Release Steps
1. Run all builds:
```bash
npm run build && npm run pack
```
2. Test in LocalWP with a sample Woo store.
3. Validate HPOS compatibility and order creation flow.
4. Push final `woonoow.zip` to release channel (Sejoli, member.dwindi.com, or manual upload).
5. Tag version using semantic versioning (e.g. `v0.2.0-beta`).
---
## 8. 🧭 Decision Hierarchy
| Category | Decision Reference |
|-----------|--------------------|
| Code Style | Follow PSR12 (PHP) & Airbnb/React rules |
| Architecture | PSR4 + modular single responsibility |
| UI/UX | Modern minimal style, standardized using Tailwind + Shadcn UI. Recharts for data visualization. |
| Icons | Use lucide-react via npm i lucide-react. Icons should match Shadcn UI guidelines. Always import directly (e.g. import { Package } from 'lucide-react'). Maintain consistent size (1620px) and stroke width (1.5px). Use Tailwind classes for color states. |
| **Navigation Pattern** | **CRUD pages MUST follow consistent back button navigation: New Order: Index ← New. Edit Order: Index ← Detail ← Edit. Back button always goes to parent page, not index. Use ArrowLeft icon from lucide-react. Toolbar format: `<button onClick={() => nav('/parent/path')}><ArrowLeft /> Back</button> <h2>Page Title</h2>`** |
| Compatibility | Must preserve Woo hooks unless explicitly replaced |
| Performance | Async-first, no blocking mail or sync jobs |
| **Email Policy** | **ALL `wp_mail()` calls MUST be delayed by 15+ seconds using Action Scheduler or wp-cron. Never send emails synchronously during API requests (create, update, status change). Use `OrdersController::schedule_order_email()` pattern.** |
| Deployment | LocalWP → Coolify → Production |
---
## 9. 🧩 Future Extensions
- **Addon Manager** (JSON feed + licensing integration).
- **Admin Insights** (charts, sales analytics with React).
- **Storefront SPA Theme Override** (optional full React mode).
- **Developer SDK** for 3rd-party addon compatibility.
---
## 10. 📜 License & Ownership
All rights reserved to **Dwindi (dewe.dev)**.
The WooNooW project may include GPL-compatible code portions for WordPress compliance.
Redistribution without written consent is prohibited outside official licensing channels.
---