Files
igny8/igny8-wp-plugin/docs/Plan-based-on-audit.md
2025-12-01 11:02:51 +05:00

830 lines
25 KiB
Markdown

# Strategic Analysis & Implementation Plan
## Current State Assessment
### What Works Well
- **Unidirectional flow**: IGNY8 → WordPress (correct approach)
- **Comprehensive data mapping**: All fields documented
- **Multiple trigger points**: Manual + scheduled
- **API authentication**: Solid security model
- **Retry mechanism**: Celery handles failures
### What's Actually Broken/Missing
---
## Critical Gaps (Real Functional Issues)
### **GAP 1: Incomplete Data Transfer**
**Problem**: The audit shows fields are mapped, but doesn't confirm ALL data actually transfers in one atomic operation.
**Current Risk**:
- Featured image might fail → rest of content publishes anyway
- Gallery images fail → content published without visuals
- SEO meta fails → content has no SEO optimization
- Categories fail to create → content published orphaned
- Sectors/clusters fail → no IGNY8 relationship tracking
**What's Missing**:
- **Pre-flight validation** before starting publish
- **Atomic transaction pattern** (all-or-nothing)
- **Dependency chain verification** (e.g., author must exist before publishing)
- **Rollback on partial failure**
---
### **GAP 2: No Publish Count Tracking Back to IGNY8**
**Problem**: You stated requirement #4 isn't implemented anywhere in the audit.
**What's Missing**:
- After successful WordPress publish, WordPress must call IGNY8 API to increment:
- `post_publish_count` for posts
- `page_publish_count` for pages
- `product_publish_count` for products
- `taxonomy_sync_count` for categories/tags/sectors/clusters
**Current State**:
- WordPress reports back `assigned_post_id` and `post_url`
- WordPress does NOT report back publish counts or content type statistics
**Impact**: IGNY8 dashboard shows incomplete/wrong statistics
---
### **GAP 3: Taxonomy Sync Doesn't Track Changes**
**Problem**: You need to track if categories/tags/clusters change in WordPress, but current system doesn't.
**Current Flow**:
1. IGNY8 sends: `categories: ["SEO", "Marketing"]`
2. WordPress creates/assigns these
3. **If user later adds "Content Strategy" in WordPress** → IGNY8 never knows
4. **If user removes "Marketing"** → IGNY8 never knows
**What's Missing**:
- WordPress hook to detect taxonomy changes on IGNY8-managed posts
- API call to IGNY8 to update taxonomy associations
- Endpoint in IGNY8 to receive taxonomy change notifications
---
### **GAP 4: Cluster/Sector/Keyword Changes Not Synced**
**Problem**: Similar to taxonomy gap but for IGNY8-specific relationships.
**Scenario**:
- Content published with `cluster_id: 12`
- User changes in WordPress to `cluster_id: 15` via custom field
- IGNY8 still thinks content belongs to cluster 12
- Cluster 12 shows wrong content count
- Cluster 15 missing content in its list
**What's Missing**:
- Detection mechanism for meta field changes on `_igny8_cluster_id`, `_igny8_sector_id`, `_igny8_keyword_ids`
- Sync back to IGNY8 to update relationships
- IGNY8 API endpoints to handle relationship updates
---
### **GAP 5: Manual vs Auto-Publish Flow Not Distinguished**
**Problem**: Both flows use same code path, but they need different handling.
**Manual Publish (Button Click)**:
- Should publish **immediately**
- User expects instant feedback
- Should override any scheduling
- Should force re-publish if already published
**Auto-Publish/Schedule**:
- Should respect `published_at` timestamp
- Should not override manual edits in WordPress
- Should skip if already published (idempotent)
- Should handle timezone conversions
**What's Missing**:
- `publish_mode` flag in API payload (`manual` vs `scheduled`)
- Different retry strategies for each mode
- Different status reporting for each mode
- Override logic for manual re-publish
---
### **GAP 6: No Verification After Publish**
**Problem**: WordPress reports "success" but doesn't verify the content is actually viewable/accessible.
**Failure Scenarios Not Caught**:
- Post published but permalink returns 404 (rewrite rules not flushed)
- Featured image attached but file doesn't exist (upload failed silently)
- Categories created but not assigned (database transaction partial commit)
- SEO meta saved but plugin not active (meta stored but not used)
**What's Missing**:
- Post-publish verification step
- Check permalink returns 200
- Verify featured image URL accessible
- Verify taxonomies actually assigned (count > 0)
- Report verification results to IGNY8
---
### **GAP 7: Schedule Publishing Timezone Issues**
**Problem**: IGNY8 sends UTC timestamp, WordPress stores in site timezone, confusion inevitable.
**Scenario**:
- IGNY8 schedules for "2025-12-01 10:00:00 UTC"
- WordPress site timezone is "America/New_York" (UTC-5)
- WordPress interprets as 10:00 AM New York time
- Content publishes 5 hours later than intended
**What's Missing**:
- Explicit timezone handling in payload
- Timezone conversion logic in WordPress
- Verification that scheduled time matches intent
---
### **GAP 8: All-or-Nothing Guarantees Missing**
**Problem**: Content can be half-published (post exists but missing images/meta).
**Current Flow**:
```
1. wp_insert_post() → Success (post ID 1842)
2. Download featured image → FAILS
3. Assign categories → Success
4. Store SEO meta → Success
5. Report success to IGNY8 ✓
Result: Post published without featured image
IGNY8 thinks everything succeeded
```
**What's Missing**:
- Transaction wrapper around entire publish operation
- Failure detection for each sub-operation
- Rollback mechanism if any step fails
- Detailed error reporting (which step failed)
---
### **GAP 9: No Re-Publish Protection**
**Problem**: If publish button clicked twice or Celery task runs twice, content duplicates.
**Scenario**:
1. User clicks "Publish" in IGNY8
2. Celery task queued
3. User clicks "Publish" again (impatient)
4. Second Celery task queued
5. Both tasks run → **2 WordPress posts created for same content**
**What's Missing**:
- Task deduplication based on `content_id` + `site_integration_id`
- Lock mechanism during publish
- WordPress duplicate detection by `_igny8_content_id` before creating new post
- Return existing post if already published (idempotent operation)
---
### **GAP 10: Publish Count Statistics Incomplete**
**Problem**: You need counts by content type, but current system doesn't track this granularly.
**What IGNY8 Needs**:
```python
class SiteIntegration(models.Model):
# Current (missing):
posts_published_count = models.IntegerField(default=0)
pages_published_count = models.IntegerField(default=0)
products_published_count = models.IntegerField(default=0)
# Also need:
categories_synced_count = models.IntegerField(default=0)
tags_synced_count = models.IntegerField(default=0)
sectors_synced_count = models.IntegerField(default=0)
clusters_synced_count = models.IntegerField(default=0)
last_publish_at = models.DateTimeField(null=True)
total_sync_operations = models.IntegerField(default=0)
```
**What's Missing**:
- WordPress needs to detect content type (post/page/product) and report it
- WordPress needs to count new vs updated taxonomies and report
- IGNY8 needs endpoints to receive these counts
- Dashboard needs to display these statistics
---
### **GAP 11: Auto-Publish Scheduling Mechanism Unclear**
**Problem**: Audit shows Celery runs every 5 minutes, but doesn't explain how scheduled publishing works.
**Questions Unanswered**:
- If `published_at` is in future, does Celery skip it?
- How does Celery know when to publish scheduled content?
- Is there a separate queue for scheduled vs immediate?
- What if scheduled time is missed (server down)?
**What's Likely Missing**:
- Scheduled content query filter in Celery task
- Time-based condition: `published_at <= now()`
- Missed schedule handler (publish immediately if past due)
- Different retry logic for scheduled vs immediate
---
### **GAP 12: Taxonomy Creation vs Assignment Not Clear**
**Problem**: If category "Digital Marketing" doesn't exist in WordPress, what happens?
**Scenario 1: Auto-Create** (probably current):
- WordPress creates category "Digital Marketing"
- Assigns to post
- **Problem**: Might create duplicates if slug differs ("digital-marketing" vs "digitalmarketing")
**Scenario 2: Map to Existing**:
- WordPress looks up by name
- If not found, uses fallback category
- **Problem**: User needs to pre-create all categories
**What's Missing**:
- Clear taxonomy reconciliation strategy
- Slug normalization rules
- Duplicate prevention logic
- Fallback category configuration
---
### **GAP 13: Keywords Not Actually Published**
**Problem**: Audit shows `focus_keywords` stored in meta, but WordPress doesn't use this field natively.
**Current State**:
- IGNY8 sends: `focus_keywords: ["SEO 2025", "ranking factors"]`
- WordPress stores: `_igny8_focus_keywords` meta
- **Nobody reads this field** (unless custom code added)
**What's Missing**:
- Integration with actual keyword tracking plugins (Yoast, RankMath, AIOSEO)
- Mapping to plugin-specific meta fields
- Fallback if no SEO plugin installed
---
### **GAP 14: Gallery Images Limit Arbitrary**
**Problem**: Audit mentions "5 images max" for gallery but doesn't explain why or what happens to 6th image.
**Questions**:
- Is this IGNY8 limit or WordPress plugin limit?
- What happens if IGNY8 sends 10 images?
- Are they silently dropped? Error thrown?
- How does user know some images were skipped?
**What's Missing**:
- Configurable gallery size limit
- Clear error message if limit exceeded
- Option to create separate gallery post/page for overflow
---
## Implementation Plan (No Code)
### **Phase 1: Fix Critical Data Integrity Issues** (Week 1-2)
#### 1.1 Implement Atomic Transaction Pattern
- Wrap entire publish operation in WordPress transaction
- If ANY step fails → rollback everything
- Delete post if created but subsequent operations failed
- Report detailed failure info to IGNY8 (which step failed)
#### 1.2 Add Pre-Flight Validation
Before attempting publish:
- Verify author exists (by email)
- Verify all image URLs accessible (HTTP HEAD request)
- Verify required fields present (title, content)
- Verify post type enabled in WordPress plugin settings
- Return validation errors BEFORE creating anything
#### 1.3 Implement Duplicate Prevention
- Check if post with `_igny8_content_id` already exists
- If exists → update instead of create (unless manual re-publish)
- Add unique constraint in IGNY8: `(content_id, site_integration_id)` → only one publish task active at a time
- Celery task deduplication by task signature
#### 1.4 Add Post-Publish Verification
After WordPress reports "success":
- Wait 5 seconds (let WordPress flush rewrites)
- HTTP GET the permalink → expect 200
- HTTP HEAD the featured image URL → expect 200
- Query taxonomies assigned → expect count > 0
- If verification fails → mark as "published_with_issues" status
- Report verification results to IGNY8
---
### **Phase 2: Implement Publish Count Tracking** (Week 2-3)
#### 2.1 Extend IGNY8 Models
Add to `SiteIntegration`:
- `posts_published_count`
- `pages_published_count`
- `products_published_count`
- `categories_synced_count`
- `tags_synced_count`
- `sectors_synced_count`
- `clusters_synced_count`
- `last_publish_at`
- `total_sync_operations`
#### 2.2 Create IGNY8 Stats Endpoint
```
PUT /integrations/{site_id}/stats/increment/
Payload: {
"content_type": "post", // or "page", "product"
"taxonomies_created": {
"categories": 2,
"tags": 5,
"sectors": 1,
"clusters": 1
},
"taxonomies_updated": {
"categories": 0,
"tags": 1,
"sectors": 0,
"clusters": 0
},
"published_at": "2025-11-29T10:15:30Z"
}
```
#### 2.3 Update WordPress Plugin Response
After successful publish, WordPress must:
- Detect post type (post/page/product)
- Count new categories created vs existing assigned
- Count new tags created vs existing assigned
- Count new sectors created vs existing assigned
- Count new clusters created vs existing assigned
- Call IGNY8 stats endpoint with all counts
- IGNY8 increments counters atomically
---
### **Phase 3: Implement Taxonomy Change Tracking** (Week 3-4)
#### 3.1 Add WordPress Hooks
Hook into:
- `set_object_terms` (when taxonomies assigned/changed)
- `update_post_meta` (when cluster/sector/keyword meta changed)
- Filter by: post has `_igny8_task_id` meta (only track IGNY8-managed posts)
#### 3.2 Create IGNY8 Taxonomy Update Endpoint
```
PUT /writer/tasks/{task_id}/taxonomies/
Payload: {
"categories": [1, 2, 3], // WordPress term IDs
"tags": [5, 8, 12],
"sectors": [2],
"clusters": [7, 9],
"updated_by": "wordpress_user_123",
"updated_at": "2025-11-29T11:00:00Z"
}
```
#### 3.3 Create IGNY8 Relationships Update Endpoint
```
PUT /writer/tasks/{task_id}/relationships/
Payload: {
"cluster_id": 15, // changed from 12
"sector_id": 5, // unchanged
"keyword_ids": [1, 2, 3, 8], // added keyword 8
"updated_by": "wordpress_user_123",
"updated_at": "2025-11-29T11:00:00Z"
}
```
#### 3.4 Implement Debouncing
- Don't sync every single taxonomy change immediately
- Batch changes over 30-second window
- Send one API call with all changes
- Reduce API call volume by 95%
---
### **Phase 4: Separate Manual vs Auto-Publish Flows** (Week 4-5)
#### 4.1 Add `publish_mode` to API Payload
IGNY8 must send:
```json
{
"content_id": 42,
"publish_mode": "manual", // or "scheduled"
"published_at": "2025-12-01T10:00:00Z",
...
}
```
#### 4.2 Implement Different Logic
**Manual Mode**:
- Ignore `published_at` timestamp (publish NOW)
- If post already exists → force update (don't skip)
- Return immediate feedback (synchronous within 5 seconds)
- Retry aggressively (3 retries, 10 seconds apart)
- Show user real-time progress
**Scheduled Mode**:
- Respect `published_at` timestamp
- If post already exists → skip (idempotent)
- Queue for future execution
- Retry conservatively (3 retries, 1 hour apart)
- Don't notify user of each retry
#### 4.3 Update Celery Task Query
```python
# Current: publishes everything with status='completed'
pending_content = ContentPost.objects.filter(
wordpress_sync_status='pending',
published_at__isnull=False
)
# New: separate scheduled from immediate
immediate_content = ContentPost.objects.filter(
wordpress_sync_status='pending',
publish_mode='manual',
published_at__isnull=False
)
scheduled_content = ContentPost.objects.filter(
wordpress_sync_status='pending',
publish_mode='scheduled',
published_at__lte=now(), # only if scheduled time reached
published_at__isnull=False
)
```
---
### **Phase 5: Timezone Handling** (Week 5)
#### 5.1 Standardize on UTC Everywhere
- IGNY8 always sends timestamps in UTC with explicit timezone: `"2025-12-01T10:00:00Z"`
- WordPress plugin converts to site timezone for `post_date`
- WordPress converts back to UTC when reporting to IGNY8
- Never rely on implied timezones
#### 5.2 Add Timezone to WordPress Response
```json
{
"success": true,
"data": {
"post_id": 1842,
"post_date_utc": "2025-11-29T10:15:30Z",
"post_date_site": "2025-11-29T05:15:30-05:00",
"site_timezone": "America/New_York"
}
}
```
#### 5.3 Scheduled Publish Verification
- IGNY8 stores: "Scheduled for 2025-12-01 10:00 UTC"
- WordPress publishes at: "2025-12-01 05:00 EST" (correct)
- WordPress reports back: "Published at 2025-12-01T10:00:00Z" (UTC)
- IGNY8 verifies timestamp matches expected
---
### **Phase 6: Enhanced Error Reporting** (Week 6)
#### 6.1 Add Detailed Error Structure
```json
{
"success": false,
"error": {
"code": "FEATURED_IMAGE_DOWNLOAD_FAILED",
"message": "Failed to download featured image",
"step": "media_processing",
"step_number": 3,
"total_steps": 7,
"details": {
"image_url": "https://example.com/image.jpg",
"http_status": 404,
"error": "Not Found"
},
"recoverable": true,
"retry_recommended": true
}
}
```
#### 6.2 Add Progress Reporting for Manual Publish
For manual publish, send progress updates:
```
POST /integrations/{site_id}/publish-progress/
{
"task_id": 15,
"step": "creating_post",
"progress": 30,
"message": "Creating WordPress post..."
}
```
Frontend shows real-time progress bar.
---
### **Phase 7: Taxonomy Reconciliation Strategy** (Week 6-7)
#### 7.1 Add Taxonomy Mapping Configuration
WordPress plugin settings:
- **Auto-create missing taxonomies**: ON/OFF
- **Slug normalization**: lowercase + hyphens
- **Duplicate detection**: by slug (not name)
- **Fallback category**: "Uncategorized" (if auto-create OFF and category not found)
#### 7.2 Taxonomy Reconciliation Algorithm
```
For each category in IGNY8 payload:
1. Normalize slug: "Digital Marketing" → "digital-marketing"
2. Query WordPress by slug (not name)
3. If found → use existing term ID
4. If not found:
a. If auto-create ON → create new term
b. If auto-create OFF → use fallback category
5. Assign term to post
```
#### 7.3 Report Taxonomy Changes to IGNY8
```json
{
"taxonomies_processed": {
"categories": {
"requested": ["Digital Marketing", "SEO"],
"created": ["SEO"],
"existing": ["Digital Marketing"],
"assigned": [1, 5]
},
"tags": {
"requested": ["seo", "ranking"],
"created": [],
"existing": ["seo", "ranking"],
"assigned": [8, 12]
}
}
}
```
---
### **Phase 8: SEO Plugin Integration** (Week 7-8)
#### 8.1 Detect Active SEO Plugin
WordPress plugin detects:
- Yoast SEO
- Rank Math
- All in One SEO
- SEOPress
- (or none)
#### 8.2 Map Focus Keywords to Plugin Fields
**Yoast SEO**:
- `_yoast_wpseo_focuskw` = first keyword
- `_yoast_wpseo_keywordsynonyms` = remaining keywords (comma-separated)
**Rank Math**:
- `rank_math_focus_keyword` = first keyword
- Additional keywords stored in JSON meta
**All in One SEO**:
- `_aioseo_keywords` = comma-separated list
**No Plugin**:
- Store in `_igny8_focus_keywords` (current behavior)
- Optional: Generate simple meta keywords tag
#### 8.3 Report SEO Plugin Status to IGNY8
```json
{
"seo_plugin": {
"active": "yoast",
"version": "22.0",
"keywords_supported": true,
"focus_keyword_set": true
}
}
```
---
### **Phase 9: Gallery Image Handling** (Week 8)
#### 9.1 Make Gallery Limit Configurable
WordPress plugin settings:
- **Max gallery images**: 5 (default)
- **Overflow behavior**:
- "Skip extra images" (current)
- "Create separate gallery post"
- "Add to post content as image grid"
#### 9.2 Handle Overflow Images
If IGNY8 sends 10 images but limit is 5:
**Option A: Skip**:
- Use first 5
- Report to IGNY8: `"gallery_images_skipped": 5`
**Option B: Create Separate Post**:
- Create new post: "{Original Title} - Gallery"
- Attach images 6-10
- Link from original post
- Report to IGNY8: `"gallery_overflow_post_id": 1843`
**Option C: Inline Grid**:
- Append HTML grid to post content
- All 10 images in post body
- Report to IGNY8: `"gallery_images_inline": 10`
---
### **Phase 10: Monitoring & Dashboard** (Week 9)
#### 10.1 IGNY8 Dashboard Enhancements
Display per site:
- **Total Published**: Posts (X) | Pages (Y) | Products (Z)
- **Taxonomies Synced**: Categories (A) | Tags (B) | Sectors (C) | Clusters (D)
- **Last Published**: 2 hours ago
- **Publish Success Rate**: 98.5% (last 30 days)
- **Average Publish Time**: 3.2 seconds
- **Pending**: 5 scheduled for today
#### 10.2 WordPress Plugin Dashboard
Display:
- **IGNY8 Posts**: 142 published | 5 pending
- **Last Sync**: 10 minutes ago
- **Connection Status**: Connected ✓
- **Recent Activity**:
- 10:15 AM - Published "SEO Guide 2025" (post)
- 10:05 AM - Published "About Us" (page)
- 09:50 AM - Synced 3 categories
#### 10.3 Add Health Check Endpoint
```
GET /wp-json/igny8/v1/health
Response:
{
"status": "healthy",
"checks": {
"api_connection": "ok",
"database": "ok",
"media_uploads": "ok",
"taxonomy_creation": "ok"
},
"stats": {
"posts_managed": 142,
"last_publish": "2025-11-29T10:15:30Z",
"disk_space": "15GB free"
}
}
```
Call from IGNY8 every 5 minutes to detect issues early.
---
## Summary: What Actually Needs to Change
### **Backend (IGNY8 Django)** Changes:
1. **Add Models Fields**:
- `publish_mode` to ContentPost ('manual' or 'scheduled')
- Publish count fields to SiteIntegration
- Taxonomy sync count fields
2. **Add API Endpoints**:
- `PUT /integrations/{id}/stats/increment/` (receive counts from WP)
- `PUT /writer/tasks/{id}/taxonomies/` (receive taxonomy changes from WP)
- `PUT /writer/tasks/{id}/relationships/` (receive cluster/sector changes from WP)
3. **Update Celery Task**:
- Add pre-flight validation
- Separate scheduled vs manual queries
- Add duplicate prevention
- Add timezone handling
- Improve error reporting
4. **Update API Call to WordPress**:
- Send `publish_mode` flag
- Send explicit UTC timezone
- Handle detailed error responses
- Process verification results
---
### **Frontend (IGNY8 Vue/React)** Changes:
1. **Manual Publish Button**:
- Show real-time progress (if WordPress sends updates)
- Show detailed success message with link to WP post
- Show detailed error message if fails (which step failed)
2. **Dashboard Stats**:
- Display publish counts by content type
- Display taxonomy sync counts
- Display last publish timestamp
- Display success rate graph
3. **Scheduled Publish UI**:
- Datetime picker with timezone display
- "Schedule for: Dec 1, 2025 10:00 AM UTC (5:00 AM your time)"
- List of scheduled publications
- Ability to cancel scheduled publish
---
### **WordPress Plugin** Changes:
1. **Core Publish Function**:
- Wrap in transaction (all-or-nothing)
- Add pre-flight validation
- Add duplicate detection
- Add post-publish verification
- Handle `publish_mode` flag differently
2. **Add Taxonomy Hooks**:
- Detect changes to categories/tags/sectors/clusters
- Batch changes over 30 seconds
- Call IGNY8 API to sync changes
3. **Add Stats Tracking**:
- Count content types published
- Count taxonomies created vs assigned
- Call IGNY8 stats endpoint after each publish
4. **Settings Page**:
- Taxonomy auto-create ON/OFF
- Taxonomy fallback category selector
- Gallery image limit (slider: 1-20)
- Gallery overflow behavior (dropdown)
- SEO plugin integration status
5. **Response Format**:
- Add verification results
- Add taxonomy processing details
- Add publish counts
- Add timezone info
---
## Testing Strategy
### 1. **Atomic Transaction Tests**
- Publish with invalid image URL → entire operation should fail, no post created
- Publish with invalid author → entire operation should fail
- Publish with SEO plugin disabled → post created, SEO meta stored anyway
### 2. **Duplicate Prevention Tests**
- Click publish button twice rapidly → only 1 post created
- Celery task runs while manual publish in progress → only 1 post created
- Re-publish same content → update existing post, don't create new
### 3. **Timezone Tests**
- Schedule for "Dec 1, 2025 10:00 UTC" from timezone UTC+5 → publishes at correct time
- WordPress in timezone "America/New_York" → post_date stored correctly in local time
- IGNY8 receives post_date_utc → matches scheduled time exactly
### 4. **Taxonomy Sync Tests**
- Add category in WordPress → IGNY8 receives update within 30 seconds
- Remove tag in WordPress → IGNY8 receives update
- Change cluster via custom field → IGNY8 receives update
- Change multiple taxonomies at once → IGNY8 receives 1 batched update
### 5. **Count Tracking Tests**
- Publish 1 post → SiteIntegration.posts_published_count increments by 1
- Publish 1 page → SiteIntegration.pages_published_count increments by 1
- Create 2 new categories → SiteIntegration.categories_synced_count increments by 2
- Update post (no new taxonomies) → counts don't change
### 6. **Manual vs Scheduled Tests**
- Manual publish → immediate execution, ignores published_at
- Scheduled publish → waits until published_at time
- Manual re-publish of scheduled content → publishes immediately, overrides schedule
---
## Implementation Priority
### **Critical (Do First)**:
1. Atomic transactions (Phase 1.1)
2. Duplicate prevention (Phase 1.3)
3. Publish count tracking (Phase 2)
4. Manual vs scheduled separation (Phase 4)
### **High Priority**:
5. Timezone handling (Phase 5)
6. Taxonomy change tracking (Phase 3)
7. Enhanced error reporting (Phase 6)
### **Medium Priority**:
8. Taxonomy reconciliation (Phase 7)
9. SEO plugin integration (Phase 8)
10. Gallery improvements (Phase 9)
### **Low Priority**:
11. Dashboard enhancements (Phase 10)
---
This plan focuses on **real functional gaps** that affect data integrity, user experience, and system reliability. No cosmetics, just critical infrastructure improvements.