automation and ai and some planning and fixes adn docs reorg
This commit is contained in:
@@ -1,936 +0,0 @@
|
|||||||
# IGNY8 Comprehensive UX Audit & Recommendations
|
|
||||||
|
|
||||||
**Date:** December 27, 2025
|
|
||||||
**Scope:** Complete application audit for optimal user experience
|
|
||||||
**Note:** Plans, billing, credits, usage sections excluded - will be done in separate phase
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
|
|
||||||
1. [Site & Sector Selector Placement](#1-site--sector-selector-placement)
|
|
||||||
2. [Table Action Row Metrics - Tooltip Improvements](#2-table-action-row-metrics---tooltip-improvements)
|
|
||||||
3. [Footer Metrics - 3-Widget Layout](#3-footer-metrics---3-widget-layout)
|
|
||||||
4. [Progress Modal Steps Audit](#4-progress-modal-steps-audit)
|
|
||||||
5. [Dashboard Redesign Plan](#5-dashboard-redesign-plan)
|
|
||||||
6. [Site Setup Checklist Implementation](#6-site-setup-checklist-implementation)
|
|
||||||
7. [To-Do-s Completion Audit](#7-to-do-s-completion-audit)
|
|
||||||
8. [Notification System Plan](#8-notification-system-plan)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. Site & Sector Selector Placement
|
|
||||||
|
|
||||||
### Rationale
|
|
||||||
- **Site Selector**: Required when data is scoped to a specific site
|
|
||||||
- **Sector Selector**: Required when data can be further filtered by content category/niche
|
|
||||||
- **Both**: When user needs precise data filtering at granular level
|
|
||||||
- **None**: When page is not site-specific or shows account-level data
|
|
||||||
|
|
||||||
### Recommendations by Page
|
|
||||||
|
|
||||||
| Page | Site Selector | Sector Selector | Reason |
|
|
||||||
|------|:-------------:|:---------------:|--------|
|
|
||||||
| **DASHBOARD** |
|
|
||||||
| Home | ✅ All Sites option | ❌ | Overview across sites - sector too granular for dashboard |
|
|
||||||
| **SETUP** |
|
|
||||||
| Add Keywords | ✅ | ✅ | Keywords are site+sector specific |
|
|
||||||
| Content Settings | ✅ | ❌ | Settings are site-level, not sector-level |
|
|
||||||
| Sites List | ❌ | ❌ | Managing sites themselves |
|
|
||||||
| Site Dashboard | ❌ (context) | ❌ | Already in specific site context |
|
|
||||||
| Site Settings tabs | ❌ (context) | ❌ | Already in specific site context |
|
|
||||||
| **PLANNER** |
|
|
||||||
| Keywords | ✅ | ✅ | Keywords organized by site+sector |
|
|
||||||
| Clusters | ✅ | ✅ | Clusters organized by site+sector |
|
|
||||||
| Cluster Detail | ❌ (context) | ❌ (context) | Already in cluster context |
|
|
||||||
| Ideas | ✅ | ✅ | Ideas organized by site+sector |
|
|
||||||
| **WRITER** |
|
|
||||||
| Tasks/Queue | ✅ | ✅ | Tasks organized by site+sector |
|
|
||||||
| Content/Drafts | ✅ | ✅ | Content organized by site+sector |
|
|
||||||
| Content View | ❌ (context) | ❌ (context) | Viewing specific content |
|
|
||||||
| Images | ✅ | ✅ | Images tied to content by site+sector |
|
|
||||||
| Review | ✅ | ✅ | Review queue by site+sector |
|
|
||||||
| Published | ✅ | ✅ | Published content by site+sector |
|
|
||||||
| **AUTOMATION** |
|
|
||||||
| Automation | ✅ | ❌ | Automation runs at site level |
|
|
||||||
| **LINKER** (if enabled) |
|
|
||||||
| Content List | ✅ | ✅ | Linking is content-specific |
|
|
||||||
| **OPTIMIZER** (if enabled) |
|
|
||||||
| Content Selector | ✅ | ✅ | Optimization is content-specific |
|
|
||||||
| Analysis Preview | ❌ (context) | ❌ (context) | Already in analysis context |
|
|
||||||
| **THINKER** (Admin) |
|
|
||||||
| All Thinker pages | ❌ | ❌ | System-wide prompts/profiles |
|
|
||||||
| **BILLING** |
|
|
||||||
| All Billing pages | ❌ | ❌ | Account-level billing data |
|
|
||||||
| **ACCOUNT** |
|
|
||||||
| Account Settings | ❌ | ❌ | Account-level settings |
|
|
||||||
| Profile | ❌ | ❌ | User profile |
|
|
||||||
| Team | ❌ | ❌ | Account-wide team |
|
|
||||||
| Plans | ❌ | ❌ | Account-level plans |
|
|
||||||
| Usage | ❌ | ❌ | Account-level usage |
|
|
||||||
| **HELP** |
|
|
||||||
| Help Page | ❌ | ❌ | Documentation |
|
|
||||||
|
|
||||||
### Implementation Priority
|
|
||||||
1. **High**: Ensure Planner & Writer pages show both selectors
|
|
||||||
2. **Medium**: Automation shows site only
|
|
||||||
3. **Low**: Account/Billing/Thinker show none
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Table Action Row Metrics - Tooltip Improvements
|
|
||||||
|
|
||||||
### Current State
|
|
||||||
The metrics in the table action row are already implemented (as shown in screenshot):
|
|
||||||
- Keywords page: `Keywords 46 | Clustered 10 | Unmapped 0 | Volume 13.6K`
|
|
||||||
|
|
||||||
**NO additional metrics should be added to the App Header** - only Credits remains there.
|
|
||||||
|
|
||||||
### Improvement: Better Actionable Tooltips
|
|
||||||
|
|
||||||
The current tooltips are basic. Improve them with **actionable context and next-step guidance**:
|
|
||||||
|
|
||||||
#### Keywords Page Metrics Tooltips
|
|
||||||
|
|
||||||
| Metric | Current Tooltip | Improved Tooltip |
|
|
||||||
|--------|----------------|------------------|
|
|
||||||
| **Keywords** | "Total keywords" | "46 keywords ready for clustering. Select unclustered keywords and click 'Auto Cluster' to organize them into topic groups." |
|
|
||||||
| **Clustered** | "Keywords in clusters" | "10 clusters created. Clusters with 3-7 keywords are optimal. Click on a cluster to generate content ideas from it." |
|
|
||||||
| **Unmapped** | "Unclustered keywords" | "All keywords are clustered! New keywords you add will appear here until clustered." |
|
|
||||||
| **Volume** | "Total search volume" | "13.6K combined monthly searches. Higher volume keywords should be prioritized for content creation." |
|
|
||||||
|
|
||||||
#### Clusters Page Metrics Tooltips
|
|
||||||
|
|
||||||
| Metric | Current Tooltip | Improved Tooltip |
|
|
||||||
|--------|----------------|------------------|
|
|
||||||
| **Clusters** | "Total clusters" | "12 topic clusters available. Each cluster groups related keywords for focused content creation." |
|
|
||||||
| **With Ideas** | "Clusters with ideas" | "8 clusters have content ideas. Click 'Generate Ideas' on clusters without ideas to plan new content." |
|
|
||||||
| **Keywords** | "Total keywords" | "46 keywords organized across clusters. Well-balanced clusters have 3-7 keywords each." |
|
|
||||||
| **Ready** | "Ready for ideas" | "4 clusters are ready for idea generation. Select them and click 'Generate Ideas' to create content outlines." |
|
|
||||||
|
|
||||||
#### Ideas Page Metrics Tooltips
|
|
||||||
|
|
||||||
| Metric | Current Tooltip | Improved Tooltip |
|
|
||||||
|--------|----------------|------------------|
|
|
||||||
| **Ideas** | "Total ideas" | "34 content ideas generated. Review each idea's outline, then click 'Create Task' to begin content generation." |
|
|
||||||
| **Pending** | "Not yet tasks" | "12 ideas haven't been converted to tasks yet. Convert ideas to tasks to start the content writing process." |
|
|
||||||
| **In Tasks** | "Converted to tasks" | "22 ideas are now writing tasks. View their progress in Writer → Tasks queue." |
|
|
||||||
|
|
||||||
#### Tasks Page Metrics Tooltips
|
|
||||||
|
|
||||||
| Metric | Current Tooltip | Improved Tooltip |
|
|
||||||
|--------|----------------|------------------|
|
|
||||||
| **Queue** | "Pending tasks" | "15 tasks waiting for content generation. Select tasks and click 'Generate Content' to write articles." |
|
|
||||||
| **Processing** | "In progress" | "2 tasks are being written by AI. Content will appear in Drafts when complete (~2-3 min each)." |
|
|
||||||
| **Complete** | "Finished tasks" | "28 tasks have generated content. Review articles in Writer → Content before publishing." |
|
|
||||||
|
|
||||||
#### Content Page Metrics Tooltips
|
|
||||||
|
|
||||||
| Metric | Current Tooltip | Improved Tooltip |
|
|
||||||
|--------|----------------|------------------|
|
|
||||||
| **Drafts** | "Draft articles" | "25 articles in draft status. Add images and review before sending to the approval queue." |
|
|
||||||
| **Has Images** | "With images" | "17 articles have images attached. Articles with images get 94% more engagement." |
|
|
||||||
| **Needs Images** | "Missing images" | "8 articles need images. Select them and click 'Generate Images' to create featured & in-article visuals." |
|
|
||||||
|
|
||||||
#### Images Page Metrics Tooltips
|
|
||||||
|
|
||||||
| Metric | Current Tooltip | Improved Tooltip |
|
|
||||||
|--------|----------------|------------------|
|
|
||||||
| **Total** | "Total images" | "127 images in your library. Each article can have 1 featured image + multiple in-article images." |
|
|
||||||
| **Generated** | "AI generated" | "112 images created by AI. Review generated images and regenerate any that don't match your brand." |
|
|
||||||
| **Pending** | "Awaiting generation" | "15 image prompts ready. Click 'Generate Images' to create visuals from your approved prompts." |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Footer Metrics - 3-Widget Layout
|
|
||||||
|
|
||||||
### Design: Three-Column Widget Layout
|
|
||||||
|
|
||||||
Replace current single metric cards with a **3-widget horizontal layout** (33.3% each):
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────────────────────────────────┐
|
|
||||||
│ WIDGET 1: PAGE METRICS │ WIDGET 2: MODULE STATS │ WIDGET 3: COMPLETION │
|
|
||||||
│ (Current Page Progress) │ (Full Module Overview) │ (Both Modules Stats) │
|
|
||||||
│ ~33.3% width │ ~33.3% width │ ~33.3% width │
|
|
||||||
└─────────────────────────────────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Widget 1: Current Page Metrics (with Combined Progress Bar)
|
|
||||||
|
|
||||||
Shows metrics specific to the current page with a single combined progress bar.
|
|
||||||
|
|
||||||
#### Keywords Page - Widget 1
|
|
||||||
```
|
|
||||||
┌──────────────────────────────────────────────────┐
|
|
||||||
│ PAGE PROGRESS │
|
|
||||||
│ │
|
|
||||||
│ Keywords 46 Clustered 42 (91%) │
|
|
||||||
│ Unmapped 4 Volume 13.6K │
|
|
||||||
│ │
|
|
||||||
│ ████████████████████░░░ 91% Clustered │
|
|
||||||
│ │
|
|
||||||
│ 💡 4 keywords ready to cluster │
|
|
||||||
└──────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Clusters Page - Widget 1
|
|
||||||
```
|
|
||||||
┌──────────────────────────────────────────────────┐
|
|
||||||
│ PAGE PROGRESS │
|
|
||||||
│ │
|
|
||||||
│ Clusters 12 With Ideas 8 (67%) │
|
|
||||||
│ Keywords 46 Ready 4 │
|
|
||||||
│ │
|
|
||||||
│ ██████████████░░░░░░░ 67% Have Ideas │
|
|
||||||
│ │
|
|
||||||
│ 💡 4 clusters ready for idea generation │
|
|
||||||
└──────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Ideas Page - Widget 1
|
|
||||||
```
|
|
||||||
┌──────────────────────────────────────────────────┐
|
|
||||||
│ PAGE PROGRESS │
|
|
||||||
│ │
|
|
||||||
│ Ideas 34 In Tasks 22 (65%) │
|
|
||||||
│ Pending 12 From Clusters 8 │
|
|
||||||
│ │
|
|
||||||
│ █████████████░░░░░░░░ 65% Converted │
|
|
||||||
│ │
|
|
||||||
│ 💡 12 ideas ready to become tasks │
|
|
||||||
└──────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Tasks Page - Widget 1
|
|
||||||
```
|
|
||||||
┌──────────────────────────────────────────────────┐
|
|
||||||
│ PAGE PROGRESS │
|
|
||||||
│ │
|
|
||||||
│ Total 45 Complete 28 (62%) │
|
|
||||||
│ Queue 15 Processing 2 │
|
|
||||||
│ │
|
|
||||||
│ ████████████░░░░░░░░░ 62% Generated │
|
|
||||||
│ │
|
|
||||||
│ 💡 15 tasks in queue for content generation │
|
|
||||||
└──────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Content Page - Widget 1
|
|
||||||
```
|
|
||||||
┌──────────────────────────────────────────────────┐
|
|
||||||
│ PAGE PROGRESS │
|
|
||||||
│ │
|
|
||||||
│ Drafts 25 Has Images 17 (68%) │
|
|
||||||
│ Total Words 12.5K Ready 17 │
|
|
||||||
│ │
|
|
||||||
│ █████████████░░░░░░░░ 68% Have Images │
|
|
||||||
│ │
|
|
||||||
│ 💡 8 drafts need images before review │
|
|
||||||
└──────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Widget 2: Module Stats (Same Widget Across Module Pages)
|
|
||||||
|
|
||||||
Shows the **complete module overview** with actionable links. Same widget appears on all pages within a module.
|
|
||||||
|
|
||||||
#### Planner Module - Widget 2 (shown on Keywords, Clusters, Ideas pages)
|
|
||||||
```
|
|
||||||
┌──────────────────────────────────────────────────┐
|
|
||||||
│ PLANNER MODULE │
|
|
||||||
│ │
|
|
||||||
│ Keywords ─────────────────────────────► Clusters │
|
|
||||||
│ 46 Auto Cluster 12 │
|
|
||||||
│ ████████████████████░░░ 91% │
|
|
||||||
│ │
|
|
||||||
│ Clusters ─────────────────────────────► Ideas │
|
|
||||||
│ 12 Generate Ideas 34 │
|
|
||||||
│ █████████████░░░░░░░░░ 67% │
|
|
||||||
│ │
|
|
||||||
│ Ideas ────────────────────────────────► Tasks │
|
|
||||||
│ 34 Create Tasks 22 │
|
|
||||||
│ █████████████░░░░░░░░░ 65% │
|
|
||||||
│ │
|
|
||||||
│ [→ Keywords] [→ Clusters] [→ Ideas] │
|
|
||||||
└──────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Writer Module - Widget 2 (shown on Tasks, Content, Images, Review, Published pages)
|
|
||||||
```
|
|
||||||
┌──────────────────────────────────────────────────┐
|
|
||||||
│ WRITER MODULE │
|
|
||||||
│ │
|
|
||||||
│ Tasks ───────────────────────────────► Drafts │
|
|
||||||
│ 45 Generate Content 28 │
|
|
||||||
│ ████████████░░░░░░░░░ 62% │
|
|
||||||
│ │
|
|
||||||
│ Drafts ──────────────────────────────► Images │
|
|
||||||
│ 28 Generate Images 17 │
|
|
||||||
│ █████████████░░░░░░░░ 68% │
|
|
||||||
│ │
|
|
||||||
│ Ready ───────────────────────────────► Published │
|
|
||||||
│ 17 Review & Publish 45 │
|
|
||||||
│ ████████████████░░░░ 73% │
|
|
||||||
│ │
|
|
||||||
│ [→ Tasks] [→ Content] [→ Images] [→ Published] │
|
|
||||||
└──────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Widget 3: Both Modules Completion Stats
|
|
||||||
|
|
||||||
Shows **completed items from both Planner and Writer** with time filter (7/30/90 days).
|
|
||||||
|
|
||||||
```
|
|
||||||
┌──────────────────────────────────────────────────┐
|
|
||||||
│ WORKFLOW COMPLETION [7d] [30d] [90d] │
|
|
||||||
│ │
|
|
||||||
│ PLANNER │
|
|
||||||
│ ├─ Keywords Clustered 42 ████████ │
|
|
||||||
│ ├─ Clusters Created 12 ███ │
|
|
||||||
│ └─ Ideas Generated 34 ███████ │
|
|
||||||
│ │
|
|
||||||
│ WRITER │
|
|
||||||
│ ├─ Content Generated 28 ██████ │
|
|
||||||
│ ├─ Images Created 127 █████████ │
|
|
||||||
│ └─ Articles Published 45 █████████ │
|
|
||||||
│ │
|
|
||||||
│ Credits Used: 2,450 │ Operations: 156 │
|
|
||||||
│ │
|
|
||||||
│ [View Full Analytics →] │
|
|
||||||
└──────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Implementation Notes
|
|
||||||
|
|
||||||
- Use existing `Card` component from `components/ui/card`
|
|
||||||
- Use existing `ProgressBar` component from `components/ui/progress`
|
|
||||||
- Use standard CSS tokens from `styles/tokens.css`:
|
|
||||||
- `--color-primary` for primary progress bars
|
|
||||||
- `--color-success` for completion indicators
|
|
||||||
- `--color-warning` for attention items
|
|
||||||
- Grid layout: `grid grid-cols-1 lg:grid-cols-3 gap-4`
|
|
||||||
- Compact padding: `p-4` instead of `p-6`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Progress Modal Steps Audit
|
|
||||||
|
|
||||||
### Current Issues
|
|
||||||
- Generic messages lacking context
|
|
||||||
- Missing counts where data is available
|
|
||||||
- Inconsistent terminology
|
|
||||||
- Not professional/polished
|
|
||||||
|
|
||||||
### Recommended Progress Step Text
|
|
||||||
|
|
||||||
#### Auto Cluster Keywords
|
|
||||||
|
|
||||||
| Phase | Current | Recommended |
|
|
||||||
|-------|---------|-------------|
|
|
||||||
| INIT | Validating keywords | Validating {count} keywords for clustering |
|
|
||||||
| PREP | Loading keyword data | Analyzing keyword relationships |
|
|
||||||
| AI_CALL | Generating clusters with Igny8 Semantic SEO Model | Grouping keywords by search intent ({count} keywords) |
|
|
||||||
| PARSE | Organizing clusters | Organizing {cluster_count} semantic clusters |
|
|
||||||
| SAVE | Saving clusters | Saving {cluster_count} clusters with {keyword_count} keywords |
|
|
||||||
| DONE | Clustering complete! | ✓ Created {cluster_count} clusters from {keyword_count} keywords |
|
|
||||||
|
|
||||||
#### Generate Ideas
|
|
||||||
|
|
||||||
| Phase | Current | Recommended |
|
|
||||||
|-------|---------|-------------|
|
|
||||||
| INIT | Verifying cluster integrity | Analyzing {count} clusters for content opportunities |
|
|
||||||
| PREP | Loading cluster keywords | Mapping {keyword_count} keywords to topic briefs |
|
|
||||||
| AI_CALL | Generating ideas with Igny8 Semantic AI | Generating content ideas for {cluster_count} clusters |
|
|
||||||
| PARSE | High-opportunity ideas generated | Structuring {idea_count} article outlines |
|
|
||||||
| SAVE | Content Outline for Ideas generated | Saving {idea_count} content ideas with outlines |
|
|
||||||
| DONE | Ideas generated! | ✓ Generated {idea_count} content ideas from {cluster_count} clusters |
|
|
||||||
|
|
||||||
#### Generate Content
|
|
||||||
|
|
||||||
| Phase | Current | Recommended |
|
|
||||||
|-------|---------|-------------|
|
|
||||||
| INIT | Validating task | Preparing {count} article{s} for generation |
|
|
||||||
| PREP | Preparing content idea | Building content brief with {keyword_count} target keywords |
|
|
||||||
| AI_CALL | Writing article with Igny8 Semantic AI | Writing {count} article{s} (~{word_target} words each) |
|
|
||||||
| PARSE | Formatting content | Formatting HTML content and metadata |
|
|
||||||
| SAVE | Saving article | Saving {count} article{s} ({total_words} words) |
|
|
||||||
| DONE | Content generated! | ✓ {count} article{s} generated ({total_words} words total) |
|
|
||||||
|
|
||||||
#### Generate Image Prompts
|
|
||||||
|
|
||||||
| Phase | Current | Recommended |
|
|
||||||
|-------|---------|-------------|
|
|
||||||
| INIT | Checking content and image slots | Analyzing content for {count} image opportunities |
|
|
||||||
| PREP | Mapping content for image prompts | Identifying featured image and {in_article_count} in-article image slots |
|
|
||||||
| AI_CALL | Writing Featured Image Prompts | Creating optimized prompts for {count} images |
|
|
||||||
| PARSE | Writing In‑article Image Prompts | Refining {in_article_count} contextual image descriptions |
|
|
||||||
| SAVE | Assigning Prompts to Dedicated Slots | Assigning {count} prompts to image slots |
|
|
||||||
| DONE | Prompts generated! | ✓ {count} image prompts ready (1 featured + {in_article_count} in-article) |
|
|
||||||
|
|
||||||
#### Generate Images from Prompts
|
|
||||||
|
|
||||||
| Phase | Current | Recommended |
|
|
||||||
|-------|---------|-------------|
|
|
||||||
| INIT | Validating image prompts | Queuing {count} images for generation |
|
|
||||||
| PREP | Preparing image generation queue | Preparing AI image generation ({count} images) |
|
|
||||||
| AI_CALL | Generating images with AI | Generating image {current}/{count}... |
|
|
||||||
| PARSE | Processing image URLs | Processing {count} generated images |
|
|
||||||
| SAVE | Saving image URLs | Uploading {count} images to media library |
|
|
||||||
| DONE | Images generated! | ✓ {count} images generated and saved |
|
|
||||||
|
|
||||||
### Success Message Templates (with counts)
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Clustering
|
|
||||||
`✓ Organized ${keywordCount} keywords into ${clusterCount} semantic clusters`
|
|
||||||
|
|
||||||
// Ideas
|
|
||||||
`✓ Created ${ideaCount} content ideas with detailed outlines`
|
|
||||||
|
|
||||||
// Content
|
|
||||||
`✓ Generated ${articleCount} articles (${totalWords.toLocaleString()} words)`
|
|
||||||
|
|
||||||
// Image Prompts
|
|
||||||
`✓ Created prompts for ${imageCount} images (1 featured + ${inArticleCount} in-article)`
|
|
||||||
|
|
||||||
// Image Generation
|
|
||||||
`✓ Generated and saved ${imageCount} AI images`
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. Dashboard Redesign Plan
|
|
||||||
|
|
||||||
### Current Issues
|
|
||||||
- Too much whitespace and large headings
|
|
||||||
- Repeating same counts/metrics without different dimensions
|
|
||||||
- Missing actionable insights
|
|
||||||
- No AI operations analytics
|
|
||||||
- Missing "needs attention" items
|
|
||||||
|
|
||||||
### New Dashboard Design: Multi-Dimension Compact Widgets
|
|
||||||
|
|
||||||
Based on Django admin reports analysis, the dashboard should show **different data dimensions** instead of repeating counts:
|
|
||||||
|
|
||||||
### Dashboard Layout (Compact, Information-Dense)
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────────────────────────────────┐
|
|
||||||
│ ⚠ NEEDS ATTENTION (collapsible, only shows if items exist) │
|
|
||||||
│ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐ │
|
|
||||||
│ │ 3 pending review │ │ WP sync failed │ │ Setup incomplete │ │
|
|
||||||
│ │ [Review →] │ │ [Retry] [Fix →] │ │ [Complete →] │ │
|
|
||||||
│ └────────────────────┘ └────────────────────┘ └────────────────────┘ │
|
|
||||||
├─────────────────────────────────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ ┌─────────────────────────────────┐ ┌─────────────────────────────────────────┐ │
|
|
||||||
│ │ WORKFLOW PIPELINE │ │ QUICK ACTIONS │ │
|
|
||||||
│ │ │ │ │ │
|
|
||||||
│ │ Sites → KWs → Clusters → Ideas │ │ [+ Keywords] [⚡ Cluster] [📝 Content] │ │
|
|
||||||
│ │ 2 156 23 67 │ │ [🖼 Images] [✓ Review] [🚀 Publish] │ │
|
|
||||||
│ │ ↓ │ │ │ │
|
|
||||||
│ │ Tasks → Drafts → Published │ │ WORKFLOW GUIDE │ │
|
|
||||||
│ │ 45 28 45 │ │ 1. Add Keywords 5. Generate Content │ │
|
|
||||||
│ │ │ │ 2. Auto Cluster 6. Generate Images │ │
|
|
||||||
│ │ ████████████░░░ 72% Complete │ │ 3. Generate Ideas 7. Review & Approve │ │
|
|
||||||
│ │ │ │ 4. Create Tasks 8. Publish to WP │ │
|
|
||||||
│ └─────────────────────────────────┘ │ [Full Help →] │ │
|
|
||||||
│ └─────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
├─────────────────────────────────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ ┌─────────────────────────────────┐ ┌─────────────────────────────────────────┐ │
|
|
||||||
│ │ AI OPERATIONS (7d) [▼ 30d] │ │ RECENT ACTIVITY │ │
|
|
||||||
│ │ │ │ │ │
|
|
||||||
│ │ Operation Count Credits │ │ • Clustered 45 keywords → 8 clusters │ │
|
|
||||||
│ │ ───────────────────────────────│ │ 2 hours ago │ │
|
|
||||||
│ │ Clustering 8 80 │ │ • Generated 5 articles (4.2K words) │ │
|
|
||||||
│ │ Ideas 12 24 │ │ 4 hours ago │ │
|
|
||||||
│ │ Content 28 1,400 │ │ • Created 15 image prompts │ │
|
|
||||||
│ │ Images 45 225 │ │ Yesterday │ │
|
|
||||||
│ │ ───────────────────────────────│ │ • Published "Best Running Shoes" to WP │ │
|
|
||||||
│ │ Total 93 1,729 │ │ Yesterday │ │
|
|
||||||
│ │ │ │ • Added 23 keywords from seed DB │ │
|
|
||||||
│ │ Success Rate: 98.5% │ │ 2 days ago │ │
|
|
||||||
│ │ Avg Credits/Op: 18.6 │ │ │ │
|
|
||||||
│ └─────────────────────────────────┘ │ [View All Activity →] │ │
|
|
||||||
│ └─────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
├─────────────────────────────────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ ┌─────────────────────────────────┐ ┌─────────────────────────────────────────┐ │
|
|
||||||
│ │ CONTENT VELOCITY │ │ AUTOMATION STATUS │ │
|
|
||||||
│ │ │ │ │ │
|
|
||||||
│ │ This Week This Month Total │ │ ● Active │ Schedule: Daily 9 AM │ │
|
|
||||||
│ │ │ │ │ │
|
|
||||||
│ │ Articles 5 28 156 │ │ Last Run: Dec 27, 7:00 AM │ │
|
|
||||||
│ │ Words 4.2K 24K 156K │ │ ├─ Clustered: 12 keywords │ │
|
|
||||||
│ │ Images 12 67 340 │ │ ├─ Ideas: 8 generated │ │
|
|
||||||
│ │ │ │ ├─ Content: 5 articles │ │
|
|
||||||
│ │ 📈 +23% vs last week │ │ └─ Images: 15 created │ │
|
|
||||||
│ │ │ │ │ │
|
|
||||||
│ │ [View Analytics →] │ │ Next Run: Dec 28, 9:00 AM │ │
|
|
||||||
│ └─────────────────────────────────┘ │ [Configure →] [Run Now →] │ │
|
|
||||||
│ └─────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Widget Specifications
|
|
||||||
|
|
||||||
#### 1. Needs Attention Bar
|
|
||||||
- Collapsible, only visible when items exist
|
|
||||||
- Types: `pending_review`, `sync_failed`, `setup_incomplete`, `automation_failed`
|
|
||||||
- Compact horizontal cards with action buttons
|
|
||||||
|
|
||||||
#### 2. Workflow Pipeline Widget
|
|
||||||
- Visual flow: Sites → Keywords → Clusters → Ideas → Tasks → Drafts → Published
|
|
||||||
- Shows counts at each stage
|
|
||||||
- Single progress bar for overall completion
|
|
||||||
- Clickable stage names link to respective pages
|
|
||||||
|
|
||||||
#### 3. Quick Actions + Workflow Guide Widget
|
|
||||||
- 2x3 grid of action buttons (use existing icons)
|
|
||||||
- Compact numbered workflow guide (1-8 steps)
|
|
||||||
- "Full Help" link to help page
|
|
||||||
|
|
||||||
#### 4. AI Operations Widget (NEW - from Django Admin Reports)
|
|
||||||
Shows data from `CreditUsageLog` model:
|
|
||||||
```typescript
|
|
||||||
interface AIOperationsData {
|
|
||||||
period: '7d' | '30d' | '90d';
|
|
||||||
operations: Array<{
|
|
||||||
type: 'clustering' | 'ideas' | 'content' | 'images';
|
|
||||||
count: number;
|
|
||||||
credits: number;
|
|
||||||
}>;
|
|
||||||
totals: {
|
|
||||||
count: number;
|
|
||||||
credits: number;
|
|
||||||
success_rate: number;
|
|
||||||
avg_credits_per_op: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- Time period filter (7d/30d/90d dropdown)
|
|
||||||
- Table with operation type, count, credits
|
|
||||||
- Success rate percentage
|
|
||||||
- Average credits per operation
|
|
||||||
|
|
||||||
#### 5. Recent Activity Widget
|
|
||||||
Shows data from `AITaskLog` and `CreditUsageLog`:
|
|
||||||
- Last 5 significant operations
|
|
||||||
- Timestamp relative (2 hours ago, Yesterday)
|
|
||||||
- Clickable to navigate to relevant content
|
|
||||||
- "View All Activity" link
|
|
||||||
|
|
||||||
#### 6. Content Velocity Widget (NEW)
|
|
||||||
Shows content production rates:
|
|
||||||
```typescript
|
|
||||||
interface ContentVelocityData {
|
|
||||||
this_week: { articles: number; words: number; images: number };
|
|
||||||
this_month: { articles: number; words: number; images: number };
|
|
||||||
total: { articles: number; words: number; images: number };
|
|
||||||
trend: number; // percentage vs previous period
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- Three time columns: This Week, This Month, Total
|
|
||||||
- Rows: Articles, Words, Images
|
|
||||||
- Trend indicator vs previous period
|
|
||||||
|
|
||||||
#### 7. Automation Status Widget
|
|
||||||
Shows automation run status:
|
|
||||||
- Current status indicator (Active/Paused/Failed)
|
|
||||||
- Schedule display
|
|
||||||
- Last run details with stage breakdown
|
|
||||||
- Next scheduled run
|
|
||||||
- Configure and Run Now buttons
|
|
||||||
|
|
||||||
### API Endpoint Required
|
|
||||||
|
|
||||||
```python
|
|
||||||
# GET /api/v1/dashboard/summary/
|
|
||||||
{
|
|
||||||
"needs_attention": [...],
|
|
||||||
"pipeline": {
|
|
||||||
"sites": 2, "keywords": 156, "clusters": 23,
|
|
||||||
"ideas": 67, "tasks": 45, "drafts": 28, "published": 45,
|
|
||||||
"completion_percentage": 72
|
|
||||||
},
|
|
||||||
"ai_operations": {
|
|
||||||
"period": "7d",
|
|
||||||
"operations": [...],
|
|
||||||
"totals": {...}
|
|
||||||
},
|
|
||||||
"recent_activity": [...],
|
|
||||||
"content_velocity": {...},
|
|
||||||
"automation": {...}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Implementation Notes
|
|
||||||
|
|
||||||
- Use existing components from `components/ui/`
|
|
||||||
- Use CSS tokens from `styles/tokens.css`
|
|
||||||
- Grid layout: `grid grid-cols-1 lg:grid-cols-2 gap-4`
|
|
||||||
- Compact widget padding: `p-4`
|
|
||||||
- No large headings - use subtle section labels
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. Site Setup Checklist Implementation
|
|
||||||
|
|
||||||
### Current Status
|
|
||||||
- ✅ `SiteSetupChecklist.tsx` component EXISTS
|
|
||||||
- ✅ Integrated in `Site Dashboard` page (full mode)
|
|
||||||
- ❌ **NOT integrated in `SiteCard.tsx`** (compact mode not used)
|
|
||||||
|
|
||||||
### Missing Implementation
|
|
||||||
|
|
||||||
The component has a `compact` prop but is not used in the site cards list.
|
|
||||||
|
|
||||||
### Recommended Fix
|
|
||||||
|
|
||||||
**File:** `frontend/src/components/sites/SiteCard.tsx`
|
|
||||||
|
|
||||||
Add compact checklist to each site card:
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
// In SiteCard component, add after the status badges:
|
|
||||||
<SiteSetupChecklist
|
|
||||||
siteId={site.id}
|
|
||||||
siteName={site.name}
|
|
||||||
hasIndustry={!!site.industry}
|
|
||||||
hasSectors={site.sectors_count > 0}
|
|
||||||
hasWordPressIntegration={!!site.wordpress_site_url}
|
|
||||||
hasKeywords={site.keywords_count > 0}
|
|
||||||
compact={true}
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Visual Result:**
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────┐
|
|
||||||
│ My Website [Active] │
|
|
||||||
│ example.com │
|
|
||||||
│ Industry: Tech │ 3 Sectors │
|
|
||||||
│ ●●●○ 3/4 Setup Steps Complete │ ← NEW compact checklist
|
|
||||||
│ [Manage →] │
|
|
||||||
└─────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. To-Do-s Completion Audit
|
|
||||||
|
|
||||||
### Summary by Section
|
|
||||||
|
|
||||||
| Section | File | Status | Remaining Items |
|
|
||||||
|---------|------|--------|-----------------|
|
|
||||||
| Section 1 | `dashboard_mods.md` | 📋 Planned (do LAST) | Dashboard revamp, aggregated API |
|
|
||||||
| Section 2 | `SECTION_2_FINAL_MODS.md` | ✅ Done | - |
|
|
||||||
| Section 3 | `SECTION_3_FINAL_MODS.md` | ✅ Done | - |
|
|
||||||
| Section 4 | `SECTION_4_FINAL_MODS.md` | ✅ Done | - |
|
|
||||||
| Section 5 | `SECTION_5_FINAL_MODS.md` | ✅ Done | - |
|
|
||||||
| Section 6 | `SECTION_6_FINAL_MODS.md` | ✅ Done | - |
|
|
||||||
|
|
||||||
**Note:** Plans, billing, credits, usage improvements moved to separate phase.
|
|
||||||
|
|
||||||
### Remaining Items Detail
|
|
||||||
|
|
||||||
#### Dashboard (Section 1) - Major Work
|
|
||||||
- [ ] Aggregated API endpoint `/v1/dashboard/summary/`
|
|
||||||
- [ ] NeedsAttention widget
|
|
||||||
- [ ] Real Recent Activity log (replace hardcoded)
|
|
||||||
- [ ] AI Operations widget (from CreditUsageLog)
|
|
||||||
- [ ] Content Velocity widget
|
|
||||||
- [ ] Automation Status display
|
|
||||||
- [ ] Contextual Quick Actions
|
|
||||||
|
|
||||||
#### Cross-Module
|
|
||||||
- [ ] Notification bell dropdown with AI run logging
|
|
||||||
- [ ] 3-widget footer layout for Planner/Writer pages
|
|
||||||
- [ ] Improved tooltips for table action row metrics
|
|
||||||
- [ ] Site Setup Checklist on site cards (compact mode)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. Notification System Plan
|
|
||||||
|
|
||||||
### Current State
|
|
||||||
- Bell icon exists with placeholder/mock notifications
|
|
||||||
- No real notification system or API
|
|
||||||
- No notification persistence
|
|
||||||
|
|
||||||
### Comprehensive Notification System Design
|
|
||||||
|
|
||||||
#### A. Notification Data Model
|
|
||||||
|
|
||||||
```python
|
|
||||||
# backend/igny8_core/business/notifications/models.py
|
|
||||||
|
|
||||||
class Notification(BaseModel):
|
|
||||||
account = models.ForeignKey('Account', on_delete=models.CASCADE)
|
|
||||||
user = models.ForeignKey('User', on_delete=models.CASCADE, null=True) # null = all users
|
|
||||||
|
|
||||||
# Notification content
|
|
||||||
type = models.CharField(max_length=50, choices=NOTIFICATION_TYPES)
|
|
||||||
title = models.CharField(max_length=200)
|
|
||||||
message = models.TextField()
|
|
||||||
severity = models.CharField(max_length=20, choices=SEVERITY_CHOICES)
|
|
||||||
|
|
||||||
# Related objects
|
|
||||||
site = models.ForeignKey('Site', null=True, on_delete=models.CASCADE)
|
|
||||||
content_type = models.ForeignKey(ContentType, null=True)
|
|
||||||
object_id = models.PositiveIntegerField(null=True)
|
|
||||||
content_object = GenericForeignKey()
|
|
||||||
|
|
||||||
# Action
|
|
||||||
action_url = models.CharField(max_length=500, null=True)
|
|
||||||
action_label = models.CharField(max_length=50, null=True)
|
|
||||||
|
|
||||||
# Status
|
|
||||||
is_read = models.BooleanField(default=False)
|
|
||||||
read_at = models.DateTimeField(null=True)
|
|
||||||
|
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
|
||||||
|
|
||||||
NOTIFICATION_TYPES = [
|
|
||||||
# AI Operations
|
|
||||||
('ai_cluster_complete', 'Clustering Complete'),
|
|
||||||
('ai_cluster_failed', 'Clustering Failed'),
|
|
||||||
('ai_ideas_complete', 'Ideas Generated'),
|
|
||||||
('ai_ideas_failed', 'Idea Generation Failed'),
|
|
||||||
('ai_content_complete', 'Content Generated'),
|
|
||||||
('ai_content_failed', 'Content Generation Failed'),
|
|
||||||
('ai_images_complete', 'Images Generated'),
|
|
||||||
('ai_images_failed', 'Image Generation Failed'),
|
|
||||||
|
|
||||||
# Workflow
|
|
||||||
('content_ready_review', 'Content Ready for Review'),
|
|
||||||
('content_published', 'Content Published'),
|
|
||||||
('content_publish_failed', 'Publishing Failed'),
|
|
||||||
|
|
||||||
# WordPress Sync
|
|
||||||
('wordpress_sync_success', 'WordPress Sync Complete'),
|
|
||||||
('wordpress_sync_failed', 'WordPress Sync Failed'),
|
|
||||||
|
|
||||||
# Credits/Billing
|
|
||||||
('credits_low', 'Credits Running Low'),
|
|
||||||
('credits_depleted', 'Credits Depleted'),
|
|
||||||
('plan_upgraded', 'Plan Upgraded'),
|
|
||||||
|
|
||||||
# Setup
|
|
||||||
('site_setup_complete', 'Site Setup Complete'),
|
|
||||||
('keywords_imported', 'Keywords Imported'),
|
|
||||||
]
|
|
||||||
|
|
||||||
SEVERITY_CHOICES = [
|
|
||||||
('info', 'Info'),
|
|
||||||
('success', 'Success'),
|
|
||||||
('warning', 'Warning'),
|
|
||||||
('error', 'Error'),
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
#### B. Notification Creation Points
|
|
||||||
|
|
||||||
| Trigger Event | Notification Type | Severity | Title | Message Template |
|
|
||||||
|---------------|-------------------|----------|-------|------------------|
|
|
||||||
| Clustering completes | `ai_cluster_complete` | success | Clustering Complete | Created {count} clusters from {keyword_count} keywords |
|
|
||||||
| Clustering fails | `ai_cluster_failed` | error | Clustering Failed | Failed to cluster keywords: {error} |
|
|
||||||
| Ideas generated | `ai_ideas_complete` | success | Ideas Generated | Generated {count} content ideas from {cluster_count} clusters |
|
|
||||||
| Ideas failed | `ai_ideas_failed` | error | Idea Generation Failed | Failed to generate ideas: {error} |
|
|
||||||
| Content generated | `ai_content_complete` | success | Content Generated | Generated {count} articles ({word_count} words) |
|
|
||||||
| Content failed | `ai_content_failed` | error | Content Generation Failed | Failed to generate content: {error} |
|
|
||||||
| Images generated | `ai_images_complete` | success | Images Generated | Generated {count} images for your content |
|
|
||||||
| Images failed | `ai_images_failed` | error | Image Generation Failed | Failed to generate {count} images: {error} |
|
|
||||||
| Content published | `content_published` | success | Content Published | "{title}" published to {site_name} |
|
|
||||||
| Publish failed | `content_publish_failed` | error | Publishing Failed | Failed to publish "{title}": {error} |
|
|
||||||
| WP sync success | `wordpress_sync_success` | success | WordPress Synced | Synced {count} items with {site_name} |
|
|
||||||
| WP sync failed | `wordpress_sync_failed` | error | Sync Failed | WordPress sync failed for {site_name}: {error} |
|
|
||||||
| Credits at 80% | `credits_low` | warning | Credits Running Low | You've used 80% of your credits. Consider upgrading. |
|
|
||||||
| Credits at 90% | `credits_low` | warning | Credits Almost Depleted | Only 10% of credits remaining. Upgrade to continue. |
|
|
||||||
| Credits depleted | `credits_depleted` | error | Credits Depleted | Your credits are exhausted. Upgrade to continue. |
|
|
||||||
| Site setup done | `site_setup_complete` | success | Site Ready | {site_name} is fully configured and ready! |
|
|
||||||
| Keywords imported | `keywords_imported` | info | Keywords Imported | Added {count} keywords to {site_name} |
|
|
||||||
|
|
||||||
#### C. API Endpoints
|
|
||||||
|
|
||||||
```python
|
|
||||||
# GET /api/v1/notifications/
|
|
||||||
# Returns paginated list, most recent first
|
|
||||||
{
|
|
||||||
"count": 45,
|
|
||||||
"unread_count": 3,
|
|
||||||
"results": [
|
|
||||||
{
|
|
||||||
"id": 123,
|
|
||||||
"type": "ai_content_complete",
|
|
||||||
"title": "Content Generated",
|
|
||||||
"message": "Generated 5 articles (4,500 words)",
|
|
||||||
"severity": "success",
|
|
||||||
"site": {"id": 1, "name": "My Blog"},
|
|
||||||
"action_url": "/writer/content",
|
|
||||||
"action_label": "View Content",
|
|
||||||
"is_read": false,
|
|
||||||
"created_at": "2025-12-27T10:30:00Z"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
# POST /api/v1/notifications/{id}/read/
|
|
||||||
# Mark single notification as read
|
|
||||||
|
|
||||||
# POST /api/v1/notifications/read-all/
|
|
||||||
# Mark all notifications as read
|
|
||||||
|
|
||||||
# DELETE /api/v1/notifications/{id}/
|
|
||||||
# Delete notification
|
|
||||||
```
|
|
||||||
|
|
||||||
#### D. Frontend Integration
|
|
||||||
|
|
||||||
##### NotificationDropdown Component Updates
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
// frontend/src/components/header/NotificationDropdown.tsx
|
|
||||||
|
|
||||||
interface Notification {
|
|
||||||
id: number;
|
|
||||||
type: string;
|
|
||||||
title: string;
|
|
||||||
message: string;
|
|
||||||
severity: 'info' | 'success' | 'warning' | 'error';
|
|
||||||
site?: { id: number; name: string };
|
|
||||||
action_url?: string;
|
|
||||||
action_label?: string;
|
|
||||||
is_read: boolean;
|
|
||||||
created_at: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Features:
|
|
||||||
// - Fetch real notifications on mount
|
|
||||||
// - Poll every 30 seconds for new notifications
|
|
||||||
// - Show unread count badge on bell icon
|
|
||||||
// - Mark as read on click
|
|
||||||
// - Navigate to action_url on click
|
|
||||||
// - "Mark all read" button
|
|
||||||
// - "View all" link to full notifications page
|
|
||||||
```
|
|
||||||
|
|
||||||
##### Full Notifications Page
|
|
||||||
|
|
||||||
Create `/account/notifications` page with:
|
|
||||||
- Full list of all notifications (paginated)
|
|
||||||
- Filter by type, severity, site
|
|
||||||
- Bulk actions (mark read, delete)
|
|
||||||
- Date range filtering
|
|
||||||
|
|
||||||
#### E. Implementation Priority
|
|
||||||
|
|
||||||
**Phase 1 (Core):**
|
|
||||||
1. Create Notification model
|
|
||||||
2. Create API endpoints
|
|
||||||
3. Hook AI functions to create notifications on complete/fail
|
|
||||||
4. Update NotificationDropdown to fetch real data
|
|
||||||
|
|
||||||
**Phase 2 (Enhanced):**
|
|
||||||
1. Credit threshold notifications
|
|
||||||
2. WordPress sync notifications
|
|
||||||
3. Full notifications page
|
|
||||||
4. Email notifications (optional)
|
|
||||||
|
|
||||||
**Phase 3 (Polish):**
|
|
||||||
1. Notification preferences
|
|
||||||
2. Push notifications
|
|
||||||
3. Real-time updates (WebSocket)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Implementation Roadmap
|
|
||||||
|
|
||||||
### Priority Order
|
|
||||||
|
|
||||||
1. **Site Setup Checklist on Cards** - Quick win, already built
|
|
||||||
2. **Table Action Row Tooltip Improvements** - Quick improvement
|
|
||||||
3. **Footer 3-Widget Layout** - Better workflow visibility
|
|
||||||
4. **Notification System** - High user value
|
|
||||||
5. **Progress Modal Text** - Polish
|
|
||||||
6. **Dashboard Redesign** - Major effort, do last
|
|
||||||
|
|
||||||
### Estimated Effort
|
|
||||||
|
|
||||||
| Item | Backend | Frontend | Total |
|
|
||||||
|------|---------|----------|-------|
|
|
||||||
| Site checklist on cards | 0h | 2h | 2h |
|
|
||||||
| Tooltip improvements | 0h | 4h | 4h |
|
|
||||||
| Footer 3-widget layout | 2h | 12h | 14h |
|
|
||||||
| Notification system | 8h | 8h | 16h |
|
|
||||||
| Progress modal text | 4h | 4h | 8h |
|
|
||||||
| Dashboard redesign | 8h | 16h | 24h |
|
|
||||||
| **Total** | **22h** | **46h** | **68h** |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Appendix: Current vs Recommended Comparison
|
|
||||||
|
|
||||||
### Table Action Row Metrics (Already Implemented)
|
|
||||||
|
|
||||||
**Current:** Shows metrics in table action row
|
|
||||||
```
|
|
||||||
| Keywords 46 | Clustered 10 | Unmapped 0 | Volume 13.6K |
|
|
||||||
```
|
|
||||||
|
|
||||||
**Improvement:** Better actionable tooltips with guidance on next steps
|
|
||||||
|
|
||||||
### Footer Metrics Example (Keywords Page)
|
|
||||||
|
|
||||||
**Current:** Large cards with minimal info
|
|
||||||
|
|
||||||
**Recommended:** 3-widget layout:
|
|
||||||
- Widget 1: Page metrics with combined progress bar
|
|
||||||
- Widget 2: Full Planner module stats with links
|
|
||||||
- Widget 3: Both modules completion stats with 7/30/90d filter
|
|
||||||
|
|
||||||
### Dashboard Example
|
|
||||||
|
|
||||||
**Current:** Hero banner + large sections + much whitespace + repeating counts
|
|
||||||
|
|
||||||
**Recommended:** Compact info-dense layout with:
|
|
||||||
- Needs Attention bar (only if items exist)
|
|
||||||
- Workflow Pipeline + Quick Actions/Guide (2 columns)
|
|
||||||
- AI Operations stats + Recent Activity (2 columns)
|
|
||||||
- Content Velocity + Automation Status (2 columns)
|
|
||||||
- All visible without scrolling, different data dimensions
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Technical Notes
|
|
||||||
|
|
||||||
### Standard Components to Use
|
|
||||||
|
|
||||||
From existing codebase:
|
|
||||||
- `components/ui/card` - Card component
|
|
||||||
- `components/ui/progress` - ProgressBar component
|
|
||||||
- `components/ui/button/Button` - Button component
|
|
||||||
- `components/ui/tooltip/Tooltip` - Tooltip component
|
|
||||||
- `components/ui/dropdown/Dropdown` - Dropdown component
|
|
||||||
|
|
||||||
### Standard CSS Tokens
|
|
||||||
|
|
||||||
From `styles/tokens.css`:
|
|
||||||
```css
|
|
||||||
--color-primary: #0693e3; /* Primary brand blue */
|
|
||||||
--color-success: #0bbf87; /* Success green */
|
|
||||||
--color-warning: #ff7a00; /* Warning orange */
|
|
||||||
--color-danger: #ef4444; /* Danger red */
|
|
||||||
--color-purple: #5d4ae3; /* Purple accent */
|
|
||||||
```
|
|
||||||
|
|
||||||
### Do NOT Create
|
|
||||||
|
|
||||||
- Inline duplicate styles
|
|
||||||
- New color variables outside tokens.css
|
|
||||||
- Duplicate component implementations
|
|
||||||
- Styles in igny8-colors.css (use tokens.css)
|
|
||||||
@@ -87,13 +87,13 @@ class AICore:
|
|||||||
response_format: Optional[Dict] = None,
|
response_format: Optional[Dict] = None,
|
||||||
api_key: Optional[str] = None,
|
api_key: Optional[str] = None,
|
||||||
function_name: str = 'ai_request',
|
function_name: str = 'ai_request',
|
||||||
function_id: Optional[str] = None,
|
prompt_prefix: Optional[str] = None,
|
||||||
tracker: Optional[ConsoleStepTracker] = None
|
tracker: Optional[ConsoleStepTracker] = None
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Centralized AI request handler with console logging.
|
Centralized AI request handler with console logging.
|
||||||
All AI text generation requests go through this method.
|
All AI text generation requests go through this method.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
prompt: Prompt text
|
prompt: Prompt text
|
||||||
model: Model name (required - must be provided from IntegrationSettings)
|
model: Model name (required - must be provided from IntegrationSettings)
|
||||||
@@ -102,12 +102,13 @@ class AICore:
|
|||||||
response_format: Optional response format dict (for JSON mode)
|
response_format: Optional response format dict (for JSON mode)
|
||||||
api_key: Optional API key override
|
api_key: Optional API key override
|
||||||
function_name: Function name for logging (e.g., 'cluster_keywords')
|
function_name: Function name for logging (e.g., 'cluster_keywords')
|
||||||
|
prompt_prefix: Optional prefix to add before prompt (e.g., '##GP01-Clustering')
|
||||||
tracker: Optional ConsoleStepTracker instance for logging
|
tracker: Optional ConsoleStepTracker instance for logging
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict with 'content', 'input_tokens', 'output_tokens', 'total_tokens',
|
Dict with 'content', 'input_tokens', 'output_tokens', 'total_tokens',
|
||||||
'model', 'cost', 'error', 'api_id'
|
'model', 'cost', 'error', 'api_id'
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: If model is not provided
|
ValueError: If model is not provided
|
||||||
"""
|
"""
|
||||||
@@ -184,16 +185,16 @@ class AICore:
|
|||||||
else:
|
else:
|
||||||
tracker.ai_call("Using text response format")
|
tracker.ai_call("Using text response format")
|
||||||
|
|
||||||
# Step 4: Validate prompt length and add function_id
|
# Step 4: Validate prompt length and add prompt_prefix
|
||||||
prompt_length = len(prompt)
|
prompt_length = len(prompt)
|
||||||
tracker.ai_call(f"Prompt length: {prompt_length} characters")
|
tracker.ai_call(f"Prompt length: {prompt_length} characters")
|
||||||
|
|
||||||
# Add function_id to prompt if provided (for tracking)
|
# Add prompt_prefix to prompt if provided (for tracking)
|
||||||
|
# Format: ##GP01-Clustering or ##CP01-Clustering
|
||||||
final_prompt = prompt
|
final_prompt = prompt
|
||||||
if function_id:
|
if prompt_prefix:
|
||||||
function_id_prefix = f'function_id: "{function_id}"\n\n'
|
final_prompt = f'{prompt_prefix}\n\n{prompt}'
|
||||||
final_prompt = function_id_prefix + prompt
|
tracker.ai_call(f"Added prompt prefix: {prompt_prefix}")
|
||||||
tracker.ai_call(f"Added function_id to prompt: {function_id}")
|
|
||||||
|
|
||||||
# Step 5: Build request payload
|
# Step 5: Build request payload
|
||||||
url = 'https://api.openai.com/v1/chat/completions'
|
url = 'https://api.openai.com/v1/chat/completions'
|
||||||
|
|||||||
@@ -306,12 +306,13 @@ class AIEngine:
|
|||||||
|
|
||||||
ai_core = AICore(account=self.account)
|
ai_core = AICore(account=self.account)
|
||||||
function_name = fn.get_name()
|
function_name = fn.get_name()
|
||||||
|
|
||||||
# Generate function_id for tracking (ai-{function_name}-01)
|
# Generate prompt prefix for tracking (e.g., ##GP01-Clustering or ##CP01-Clustering)
|
||||||
# Normalize underscores to hyphens to match frontend tracking IDs
|
# This replaces function_id and indicates whether prompt is global or custom
|
||||||
function_id_base = function_name.replace('_', '-')
|
from igny8_core.ai.prompts import get_prompt_prefix_for_function
|
||||||
function_id = f"ai-{function_id_base}-01-desktop"
|
prompt_prefix = get_prompt_prefix_for_function(function_name, account=self.account)
|
||||||
|
logger.info(f"[AIEngine] Using prompt prefix: {prompt_prefix}")
|
||||||
|
|
||||||
# Get model config from settings (requires account)
|
# Get model config from settings (requires account)
|
||||||
# This will raise ValueError if IntegrationSettings not configured
|
# This will raise ValueError if IntegrationSettings not configured
|
||||||
try:
|
try:
|
||||||
@@ -349,7 +350,7 @@ class AIEngine:
|
|||||||
temperature=model_config.get('temperature'),
|
temperature=model_config.get('temperature'),
|
||||||
response_format=model_config.get('response_format'),
|
response_format=model_config.get('response_format'),
|
||||||
function_name=function_name,
|
function_name=function_name,
|
||||||
function_id=function_id # Pass function_id for tracking
|
prompt_prefix=prompt_prefix # Pass prompt prefix for tracking (replaces function_id)
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_msg = f"AI call failed: {str(e)}"
|
error_msg = f"AI call failed: {str(e)}"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ Prompt Registry - Centralized prompt management with override hierarchy
|
|||||||
Supports: task-level overrides → DB prompts → GlobalAIPrompt (REQUIRED)
|
Supports: task-level overrides → DB prompts → GlobalAIPrompt (REQUIRED)
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
from typing import Dict, Any, Optional
|
from typing import Dict, Any, Optional, Tuple
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -16,10 +16,10 @@ class PromptRegistry:
|
|||||||
2. DB prompt for (account, function)
|
2. DB prompt for (account, function)
|
||||||
3. GlobalAIPrompt (REQUIRED - no hardcoded fallbacks)
|
3. GlobalAIPrompt (REQUIRED - no hardcoded fallbacks)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Removed ALL hardcoded prompts - GlobalAIPrompt is now the ONLY source of default prompts
|
# Removed ALL hardcoded prompts - GlobalAIPrompt is now the ONLY source of default prompts
|
||||||
# To add/modify prompts, use Django admin: /admin/system/globalaiprompt/
|
# To add/modify prompts, use Django admin: /admin/system/globalaiprompt/
|
||||||
|
|
||||||
# Mapping from function names to prompt types
|
# Mapping from function names to prompt types
|
||||||
FUNCTION_TO_PROMPT_TYPE = {
|
FUNCTION_TO_PROMPT_TYPE = {
|
||||||
'auto_cluster': 'clustering',
|
'auto_cluster': 'clustering',
|
||||||
@@ -35,7 +35,114 @@ class PromptRegistry:
|
|||||||
'generate_service_page': 'service_generation',
|
'generate_service_page': 'service_generation',
|
||||||
'generate_taxonomy': 'taxonomy_generation',
|
'generate_taxonomy': 'taxonomy_generation',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Mapping of prompt types to their prefix numbers and display names
|
||||||
|
# Format: {prompt_type: (number, display_name)}
|
||||||
|
# GP = Global Prompt, CP = Custom Prompt
|
||||||
|
PROMPT_PREFIX_MAP = {
|
||||||
|
'clustering': ('01', 'Clustering'),
|
||||||
|
'ideas': ('02', 'Ideas'),
|
||||||
|
'content_generation': ('03', 'ContentGen'),
|
||||||
|
'image_prompt_extraction': ('04', 'ImagePrompts'),
|
||||||
|
'site_structure_generation': ('05', 'SiteStructure'),
|
||||||
|
'optimize_content': ('06', 'OptimizeContent'),
|
||||||
|
'product_generation': ('07', 'ProductGen'),
|
||||||
|
'service_generation': ('08', 'ServiceGen'),
|
||||||
|
'taxonomy_generation': ('09', 'TaxonomyGen'),
|
||||||
|
'image_prompt_template': ('10', 'ImageTemplate'),
|
||||||
|
'negative_prompt': ('11', 'NegativePrompt'),
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_prompt_prefix(cls, prompt_type: str, is_custom: bool) -> str:
|
||||||
|
"""
|
||||||
|
Generate prompt prefix for tracking.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prompt_type: The prompt type (e.g., 'clustering', 'ideas')
|
||||||
|
is_custom: True if using custom/account-specific prompt, False if global
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Prefix string like "##GP01-Clustering" or "##CP01-Clustering"
|
||||||
|
"""
|
||||||
|
prefix_info = cls.PROMPT_PREFIX_MAP.get(prompt_type, ('00', prompt_type.title()))
|
||||||
|
number, display_name = prefix_info
|
||||||
|
prefix_type = 'CP' if is_custom else 'GP'
|
||||||
|
return f"##{prefix_type}{number}-{display_name}"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_prompt_with_metadata(
|
||||||
|
cls,
|
||||||
|
function_name: str,
|
||||||
|
account: Optional[Any] = None,
|
||||||
|
task: Optional[Any] = None,
|
||||||
|
context: Optional[Dict[str, Any]] = None
|
||||||
|
) -> Tuple[str, bool, str]:
|
||||||
|
"""
|
||||||
|
Get prompt for a function with metadata about source.
|
||||||
|
|
||||||
|
Priority:
|
||||||
|
1. task.prompt_override (if task provided and has override)
|
||||||
|
2. DB prompt for (account, function) - marked as custom if is_customized=True
|
||||||
|
3. GlobalAIPrompt (REQUIRED - no hardcoded fallbacks)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
function_name: AI function name (e.g., 'auto_cluster', 'generate_ideas')
|
||||||
|
account: Account object (optional)
|
||||||
|
task: Task object with optional prompt_override (optional)
|
||||||
|
context: Additional context for prompt rendering (optional)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple of (prompt_string, is_custom, prompt_type)
|
||||||
|
- prompt_string: The rendered prompt
|
||||||
|
- is_custom: True if using custom/account prompt, False if global
|
||||||
|
- prompt_type: The prompt type identifier
|
||||||
|
"""
|
||||||
|
# Step 1: Get prompt type
|
||||||
|
prompt_type = cls.FUNCTION_TO_PROMPT_TYPE.get(function_name, function_name)
|
||||||
|
|
||||||
|
# Step 2: Check task-level override (always considered custom)
|
||||||
|
if task and hasattr(task, 'prompt_override') and task.prompt_override:
|
||||||
|
logger.info(f"Using task-level prompt override for {function_name}")
|
||||||
|
prompt = task.prompt_override
|
||||||
|
return cls._render_prompt(prompt, context or {}), True, prompt_type
|
||||||
|
|
||||||
|
# Step 3: Try DB prompt (account-specific)
|
||||||
|
if account:
|
||||||
|
try:
|
||||||
|
from igny8_core.modules.system.models import AIPrompt
|
||||||
|
db_prompt = AIPrompt.objects.get(
|
||||||
|
account=account,
|
||||||
|
prompt_type=prompt_type,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
# Check if prompt is customized
|
||||||
|
is_custom = db_prompt.is_customized
|
||||||
|
logger.info(f"Using {'customized' if is_custom else 'default'} account prompt for {function_name} (account {account.id})")
|
||||||
|
prompt = db_prompt.prompt_value
|
||||||
|
return cls._render_prompt(prompt, context or {}), is_custom, prompt_type
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"No account-specific prompt found for {function_name}: {e}")
|
||||||
|
|
||||||
|
# Step 4: Try GlobalAIPrompt (platform-wide default) - REQUIRED
|
||||||
|
try:
|
||||||
|
from igny8_core.modules.system.global_settings_models import GlobalAIPrompt
|
||||||
|
global_prompt = GlobalAIPrompt.objects.get(
|
||||||
|
prompt_type=prompt_type,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
logger.info(f"Using global default prompt for {function_name} from GlobalAIPrompt")
|
||||||
|
prompt = global_prompt.prompt_value
|
||||||
|
return cls._render_prompt(prompt, context or {}), False, prompt_type
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = (
|
||||||
|
f"ERROR: Global prompt '{prompt_type}' not found for function '{function_name}'. "
|
||||||
|
f"Please configure it in Django admin at: /admin/system/globalaiprompt/. "
|
||||||
|
f"Error: {e}"
|
||||||
|
)
|
||||||
|
logger.error(error_msg)
|
||||||
|
raise ValueError(error_msg)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_prompt(
|
def get_prompt(
|
||||||
cls,
|
cls,
|
||||||
@@ -46,63 +153,23 @@ class PromptRegistry:
|
|||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Get prompt for a function with hierarchical resolution.
|
Get prompt for a function with hierarchical resolution.
|
||||||
|
|
||||||
Priority:
|
Priority:
|
||||||
1. task.prompt_override (if task provided and has override)
|
1. task.prompt_override (if task provided and has override)
|
||||||
2. DB prompt for (account, function)
|
2. DB prompt for (account, function)
|
||||||
3. GlobalAIPrompt (REQUIRED - no hardcoded fallbacks)
|
3. GlobalAIPrompt (REQUIRED - no hardcoded fallbacks)
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
function_name: AI function name (e.g., 'auto_cluster', 'generate_ideas')
|
function_name: AI function name (e.g., 'auto_cluster', 'generate_ideas')
|
||||||
account: Account object (optional)
|
account: Account object (optional)
|
||||||
task: Task object with optional prompt_override (optional)
|
task: Task object with optional prompt_override (optional)
|
||||||
context: Additional context for prompt rendering (optional)
|
context: Additional context for prompt rendering (optional)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Prompt string ready for formatting
|
Prompt string ready for formatting
|
||||||
"""
|
"""
|
||||||
# Step 1: Check task-level override
|
prompt, _, _ = cls.get_prompt_with_metadata(function_name, account, task, context)
|
||||||
if task and hasattr(task, 'prompt_override') and task.prompt_override:
|
return prompt
|
||||||
logger.info(f"Using task-level prompt override for {function_name}")
|
|
||||||
prompt = task.prompt_override
|
|
||||||
return cls._render_prompt(prompt, context or {})
|
|
||||||
|
|
||||||
# Step 2: Get prompt type
|
|
||||||
prompt_type = cls.FUNCTION_TO_PROMPT_TYPE.get(function_name, function_name)
|
|
||||||
|
|
||||||
# Step 3: Try DB prompt (account-specific)
|
|
||||||
if account:
|
|
||||||
try:
|
|
||||||
from igny8_core.modules.system.models import AIPrompt
|
|
||||||
db_prompt = AIPrompt.objects.get(
|
|
||||||
account=account,
|
|
||||||
prompt_type=prompt_type,
|
|
||||||
is_active=True
|
|
||||||
)
|
|
||||||
logger.info(f"Using account-specific prompt for {function_name} (account {account.id})")
|
|
||||||
prompt = db_prompt.prompt_value
|
|
||||||
return cls._render_prompt(prompt, context or {})
|
|
||||||
except Exception as e:
|
|
||||||
logger.debug(f"No account-specific prompt found for {function_name}: {e}")
|
|
||||||
|
|
||||||
# Step 4: Try GlobalAIPrompt (platform-wide default) - REQUIRED
|
|
||||||
try:
|
|
||||||
from igny8_core.modules.system.global_settings_models import GlobalAIPrompt
|
|
||||||
global_prompt = GlobalAIPrompt.objects.get(
|
|
||||||
prompt_type=prompt_type,
|
|
||||||
is_active=True
|
|
||||||
)
|
|
||||||
logger.info(f"Using global default prompt for {function_name} from GlobalAIPrompt")
|
|
||||||
prompt = global_prompt.prompt_value
|
|
||||||
return cls._render_prompt(prompt, context or {})
|
|
||||||
except Exception as e:
|
|
||||||
error_msg = (
|
|
||||||
f"ERROR: Global prompt '{prompt_type}' not found for function '{function_name}'. "
|
|
||||||
f"Please configure it in Django admin at: /admin/system/globalaiprompt/. "
|
|
||||||
f"Error: {e}"
|
|
||||||
)
|
|
||||||
logger.error(error_msg)
|
|
||||||
raise ValueError(error_msg)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _render_prompt(cls, prompt_template: str, context: Dict[str, Any]) -> str:
|
def _render_prompt(cls, prompt_template: str, context: Dict[str, Any]) -> str:
|
||||||
@@ -219,3 +286,61 @@ def get_prompt(function_name: str, account=None, task=None, context=None) -> str
|
|||||||
"""Get prompt using registry"""
|
"""Get prompt using registry"""
|
||||||
return PromptRegistry.get_prompt(function_name, account=account, task=task, context=context)
|
return PromptRegistry.get_prompt(function_name, account=account, task=task, context=context)
|
||||||
|
|
||||||
|
|
||||||
|
def get_prompt_with_prefix(function_name: str, account=None, task=None, context=None) -> Tuple[str, str]:
|
||||||
|
"""
|
||||||
|
Get prompt with its tracking prefix.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
function_name: AI function name
|
||||||
|
account: Account object (optional)
|
||||||
|
task: Task object with optional prompt_override (optional)
|
||||||
|
context: Additional context for prompt rendering (optional)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple of (prompt_string, prefix_string)
|
||||||
|
- prompt_string: The rendered prompt
|
||||||
|
- prefix_string: The tracking prefix (e.g., '##GP01-Clustering' or '##CP01-Clustering')
|
||||||
|
"""
|
||||||
|
prompt, is_custom, prompt_type = PromptRegistry.get_prompt_with_metadata(
|
||||||
|
function_name, account=account, task=task, context=context
|
||||||
|
)
|
||||||
|
prefix = PromptRegistry.get_prompt_prefix(prompt_type, is_custom)
|
||||||
|
return prompt, prefix
|
||||||
|
|
||||||
|
|
||||||
|
def get_prompt_prefix_for_function(function_name: str, account=None, task=None) -> str:
|
||||||
|
"""
|
||||||
|
Get just the prefix for a function without fetching the full prompt.
|
||||||
|
Useful when the prompt was already fetched elsewhere.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
function_name: AI function name
|
||||||
|
account: Account object (optional)
|
||||||
|
task: Task object with optional prompt_override (optional)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The tracking prefix (e.g., '##GP01-Clustering' or '##CP01-Clustering')
|
||||||
|
"""
|
||||||
|
prompt_type = PromptRegistry.FUNCTION_TO_PROMPT_TYPE.get(function_name, function_name)
|
||||||
|
|
||||||
|
# Check for task-level override (always custom)
|
||||||
|
if task and hasattr(task, 'prompt_override') and task.prompt_override:
|
||||||
|
return PromptRegistry.get_prompt_prefix(prompt_type, is_custom=True)
|
||||||
|
|
||||||
|
# Check for account-specific prompt
|
||||||
|
if account:
|
||||||
|
try:
|
||||||
|
from igny8_core.modules.system.models import AIPrompt
|
||||||
|
db_prompt = AIPrompt.objects.get(
|
||||||
|
account=account,
|
||||||
|
prompt_type=prompt_type,
|
||||||
|
is_active=True
|
||||||
|
)
|
||||||
|
return PromptRegistry.get_prompt_prefix(prompt_type, is_custom=db_prompt.is_customized)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Fallback to global (not custom)
|
||||||
|
return PromptRegistry.get_prompt_prefix(prompt_type, is_custom=False)
|
||||||
|
|
||||||
|
|||||||
@@ -119,10 +119,40 @@ class Tasks(SoftDeletableModel, SiteSectorBaseModel):
|
|||||||
|
|
||||||
objects = SoftDeleteManager()
|
objects = SoftDeleteManager()
|
||||||
all_objects = models.Manager()
|
all_objects = models.Manager()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
|
def soft_delete(self, user=None, reason=None, retention_days=None):
|
||||||
|
"""
|
||||||
|
Override soft_delete to cascade to related models.
|
||||||
|
This ensures Images and ContentClusterMap are also deleted when a Task is deleted.
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Soft-delete related Images (which are also SoftDeletable)
|
||||||
|
related_images = self.images.filter(is_deleted=False)
|
||||||
|
images_count = related_images.count()
|
||||||
|
for image in related_images:
|
||||||
|
image.soft_delete(user=user, reason=f"Parent task deleted: {reason or 'No reason'}")
|
||||||
|
|
||||||
|
# Hard-delete ContentClusterMap (not soft-deletable)
|
||||||
|
cluster_maps_count = self.cluster_mappings.count()
|
||||||
|
self.cluster_mappings.all().delete()
|
||||||
|
|
||||||
|
# Hard-delete ContentAttribute (not soft-deletable)
|
||||||
|
attributes_count = self.attribute_mappings.count()
|
||||||
|
self.attribute_mappings.all().delete()
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"[Tasks.soft_delete] Task {self.id} '{self.title}' cascade delete: "
|
||||||
|
f"{images_count} images, {cluster_maps_count} cluster maps, {attributes_count} attributes"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Call parent soft_delete
|
||||||
|
super().soft_delete(user=user, reason=reason, retention_days=retention_days)
|
||||||
|
|
||||||
|
|
||||||
class ContentTaxonomyRelation(models.Model):
|
class ContentTaxonomyRelation(models.Model):
|
||||||
"""Through model for Content-Taxonomy many-to-many relationship"""
|
"""Through model for Content-Taxonomy many-to-many relationship"""
|
||||||
@@ -326,6 +356,61 @@ class Content(SoftDeletableModel, SiteSectorBaseModel):
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logger.error(f"Error incrementing word usage for content {self.id}: {str(e)}")
|
logger.error(f"Error incrementing word usage for content {self.id}: {str(e)}")
|
||||||
|
|
||||||
|
def soft_delete(self, user=None, reason=None, retention_days=None):
|
||||||
|
"""
|
||||||
|
Override soft_delete to cascade to related models.
|
||||||
|
This ensures Images, ContentClusterMap, ContentAttribute are also deleted.
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Soft-delete related Images (which are also SoftDeletable)
|
||||||
|
related_images = self.images.filter(is_deleted=False)
|
||||||
|
images_count = related_images.count()
|
||||||
|
for image in related_images:
|
||||||
|
image.soft_delete(user=user, reason=f"Parent content deleted: {reason or 'No reason'}")
|
||||||
|
|
||||||
|
# Hard-delete ContentClusterMap (not soft-deletable)
|
||||||
|
cluster_maps_count = self.cluster_mappings.count()
|
||||||
|
self.cluster_mappings.all().delete()
|
||||||
|
|
||||||
|
# Hard-delete ContentAttribute (not soft-deletable)
|
||||||
|
attributes_count = self.attributes.count()
|
||||||
|
self.attributes.all().delete()
|
||||||
|
|
||||||
|
# Hard-delete ContentTaxonomyRelation (through model for many-to-many)
|
||||||
|
taxonomy_relations_count = ContentTaxonomyRelation.objects.filter(content=self).count()
|
||||||
|
ContentTaxonomyRelation.objects.filter(content=self).delete()
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"[Content.soft_delete] Content {self.id} '{self.title}' cascade delete: "
|
||||||
|
f"{images_count} images, {cluster_maps_count} cluster maps, "
|
||||||
|
f"{attributes_count} attributes, {taxonomy_relations_count} taxonomy relations"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Call parent soft_delete
|
||||||
|
super().soft_delete(user=user, reason=reason, retention_days=retention_days)
|
||||||
|
|
||||||
|
def hard_delete(self, using=None, keep_parents=False):
|
||||||
|
"""
|
||||||
|
Override hard_delete to cascade to related models.
|
||||||
|
Django CASCADE should handle this, but we explicitly clean up for safety.
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Hard-delete related Images (including soft-deleted ones)
|
||||||
|
images_count = Images.all_objects.filter(content=self).count()
|
||||||
|
Images.all_objects.filter(content=self).delete()
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"[Content.hard_delete] Content {self.id} '{self.title}' hard delete: "
|
||||||
|
f"{images_count} images removed"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Call parent hard_delete (Django CASCADE will handle the rest)
|
||||||
|
return super().hard_delete(using=using, keep_parents=keep_parents)
|
||||||
|
|
||||||
|
|
||||||
class ContentTaxonomy(SiteSectorBaseModel):
|
class ContentTaxonomy(SiteSectorBaseModel):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -121,14 +121,14 @@ class AIProcessor:
|
|||||||
temperature: float = 0.7,
|
temperature: float = 0.7,
|
||||||
response_format: Optional[Dict] = None,
|
response_format: Optional[Dict] = None,
|
||||||
api_key: Optional[str] = None,
|
api_key: Optional[str] = None,
|
||||||
function_id: Optional[str] = None,
|
prompt_prefix: Optional[str] = None,
|
||||||
response_steps=None
|
response_steps=None
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Internal method to call OpenAI API.
|
Internal method to call OpenAI API.
|
||||||
EXACT match to reference plugin's igny8_call_openai() function.
|
EXACT match to reference plugin's igny8_call_openai() function.
|
||||||
Endpoint: https://api.openai.com/v1/chat/completions
|
Endpoint: https://api.openai.com/v1/chat/completions
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict with 'content', 'input_tokens', 'output_tokens', 'total_tokens', 'model', 'cost', 'error', 'api_id'
|
Dict with 'content', 'input_tokens', 'output_tokens', 'total_tokens', 'model', 'cost', 'error', 'api_id'
|
||||||
"""
|
"""
|
||||||
@@ -159,12 +159,12 @@ class AIProcessor:
|
|||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add function_id to prompt if provided (for tracking)
|
# Add prompt_prefix to prompt if provided (for tracking)
|
||||||
|
# Format: ##GP01-Clustering or ##CP01-Clustering
|
||||||
final_prompt = prompt
|
final_prompt = prompt
|
||||||
if function_id:
|
if prompt_prefix:
|
||||||
function_id_prefix = f'function_id: "{function_id}"\n\n'
|
final_prompt = f'{prompt_prefix}\n\n{prompt}'
|
||||||
final_prompt = function_id_prefix + prompt
|
logger.info(f"Added prompt prefix: {prompt_prefix}")
|
||||||
logger.info(f"Added function_id to prompt: {function_id}")
|
|
||||||
|
|
||||||
# EXACT request format from reference plugin (openai-api.php line 402-404)
|
# EXACT request format from reference plugin (openai-api.php line 402-404)
|
||||||
body_data = {
|
body_data = {
|
||||||
@@ -463,13 +463,15 @@ class AIProcessor:
|
|||||||
Returns:
|
Returns:
|
||||||
Dict with 'content', 'tokens_used', 'model', 'cost', 'error'
|
Dict with 'content', 'tokens_used', 'model', 'cost', 'error'
|
||||||
"""
|
"""
|
||||||
# Generate function_id for tracking (ai-generate-content-03 for AIProcessor path)
|
# Generate prompt prefix for tracking (e.g., ##GP03-ContentGen or ##CP03-ContentGen)
|
||||||
function_id = "ai-generate-content-03"
|
from igny8_core.ai.prompts import get_prompt_prefix_for_function
|
||||||
|
prompt_prefix = get_prompt_prefix_for_function('generate_content', account=self.account)
|
||||||
|
|
||||||
# Get response_format from settings for generate_content
|
# Get response_format from settings for generate_content
|
||||||
from igny8_core.ai.settings import get_model_config
|
from igny8_core.ai.settings import get_model_config
|
||||||
model_config = get_model_config('generate_content')
|
model_config = get_model_config('generate_content', account=self.account)
|
||||||
response_format = model_config.get('response_format')
|
response_format = model_config.get('response_format')
|
||||||
result = self._call_openai(prompt, model, max_tokens, temperature, response_format=response_format, function_id=function_id)
|
result = self._call_openai(prompt, model, max_tokens, temperature, response_format=response_format, prompt_prefix=prompt_prefix)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'content': result.get('content', ''),
|
'content': result.get('content', ''),
|
||||||
|
|||||||
193
docs/fixes/footer-widget-pagination-fix.md
Normal file
193
docs/fixes/footer-widget-pagination-fix.md
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
# Footer Widget Pagination Fix - Summary
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
All pages with `ThreeWidgetFooter` are calculating metrics using **page-filtered arrays** instead of **total counts** from the API. This causes incorrect metric values when users are viewing paginated results.
|
||||||
|
|
||||||
|
### Example:
|
||||||
|
- If there are 100 total keywords with 10 on the current page
|
||||||
|
- And 5 keywords on the current page don't have a `cluster_id`
|
||||||
|
- The footer shows "Unmapped: 5" instead of the actual total unmapped count
|
||||||
|
|
||||||
|
## Root Cause
|
||||||
|
|
||||||
|
The footer widgets use JavaScript `.filter()` methods on the local `items` array (which only contains the current page's data) instead of making separate API calls to get total counts for each status.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// WRONG - Uses page-filtered array
|
||||||
|
{ label: 'Unmapped', value: keywords.filter(k => !k.cluster_id).length }
|
||||||
|
|
||||||
|
// CORRECT - Uses total count from API
|
||||||
|
{ label: 'Unmapped', value: totalUnmapped }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Solution Pattern
|
||||||
|
|
||||||
|
For each affected page:
|
||||||
|
|
||||||
|
1. **Add state variables for total counts**
|
||||||
|
2. **Create a `loadTotalMetrics()` function** that makes lightweight API calls (page_size=1) filtered by status
|
||||||
|
3. **Call `loadTotalMetrics()` when site/sector changes**
|
||||||
|
4. **Update footer widget** to use the total count state instead of filtering local arrays
|
||||||
|
|
||||||
|
## Files Fixed
|
||||||
|
|
||||||
|
### ✅ 1. Keywords.tsx
|
||||||
|
- Added: `totalClustered`, `totalUnmapped`, `totalVolume` state
|
||||||
|
- Added: `loadTotalMetrics()` function
|
||||||
|
- Updated: Footer widget to use total counts
|
||||||
|
|
||||||
|
### ✅ 2. Clusters.tsx
|
||||||
|
- Added: `totalWithIdeas`, `totalReady` state
|
||||||
|
- Added: `loadTotalMetrics()` function
|
||||||
|
- Updated: Footer widget to use total counts
|
||||||
|
|
||||||
|
### ⏳ 3. Ideas.tsx
|
||||||
|
- **TODO**: Add `totalInTasks`, `totalPending` state
|
||||||
|
- **TODO**: Add `loadTotalMetrics()` function with calls to:
|
||||||
|
- `fetchContentIdeas({ status: 'queued' })` → `totalInTasks`
|
||||||
|
- `fetchContentIdeas({ status: 'new' })` → `totalPending`
|
||||||
|
- **TODO**: Update footer widget metrics
|
||||||
|
|
||||||
|
### ⏳ 4. Tasks.tsx
|
||||||
|
- **TODO**: Add total count state variables
|
||||||
|
- **TODO**: Add `loadTotalMetrics()` function
|
||||||
|
- **TODO**: Update footer widget
|
||||||
|
|
||||||
|
### ⏳ 5. Content.tsx
|
||||||
|
- **TODO**: Add total count state variables for each status (draft, review, approved)
|
||||||
|
- **TODO**: Add `loadTotalMetrics()` function
|
||||||
|
- **TODO**: Update footer widget
|
||||||
|
|
||||||
|
### ⏳ 6. Images.tsx
|
||||||
|
- **TODO**: Add total count state variables
|
||||||
|
- **TODO**: Add `loadTotalMetrics()` function
|
||||||
|
- **TODO**: Update footer widget
|
||||||
|
|
||||||
|
### ⏳ 7. Review.tsx
|
||||||
|
- **TODO**: Add total count state variables
|
||||||
|
- **TODO**: Add `loadTotalMetrics()` function
|
||||||
|
- **TODO**: Update footer widget
|
||||||
|
|
||||||
|
### ⏳ 8. Approved.tsx
|
||||||
|
- **TODO**: Add total count state variables
|
||||||
|
- **TODO**: Add `loadTotalMetrics()` function
|
||||||
|
- **TODO**: Update footer widget
|
||||||
|
|
||||||
|
## Implementation Template
|
||||||
|
|
||||||
|
### Step 1: Add State Variables
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Total counts for footer widget (not page-filtered)
|
||||||
|
const [totalWithStatus1, setTotalWithStatus1] = useState(0);
|
||||||
|
const [totalWithStatus2, setTotalWithStatus2] = useState(0);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Create loadTotalMetrics Function
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Load total metrics for footer widget (not affected by pagination)
|
||||||
|
const loadTotalMetrics = useCallback(async () => {
|
||||||
|
if (!activeSite) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get items with status1
|
||||||
|
const status1Res = await fetchItems({
|
||||||
|
page_size: 1,
|
||||||
|
site_id: activeSite.id,
|
||||||
|
...(activeSector?.id && { sector_id: activeSector.id }),
|
||||||
|
status: 'status1',
|
||||||
|
});
|
||||||
|
setTotalWithStatus1(status1Res.count || 0);
|
||||||
|
|
||||||
|
// Get items with status2
|
||||||
|
const status2Res = await fetchItems({
|
||||||
|
page_size: 1,
|
||||||
|
site_id: activeSite.id,
|
||||||
|
...(activeSector?.id && { sector_id: activeSector.id }),
|
||||||
|
status: 'status2',
|
||||||
|
});
|
||||||
|
setTotalWithStatus2(status2Res.count || 0);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading total metrics:', error);
|
||||||
|
}
|
||||||
|
}, [activeSite, activeSector]);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Call on Mount/Change
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Load total metrics when site/sector changes
|
||||||
|
useEffect(() => {
|
||||||
|
loadTotalMetrics();
|
||||||
|
}, [loadTotalMetrics]);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Update Footer Widget
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
<ThreeWidgetFooter
|
||||||
|
pageProgress={{
|
||||||
|
metrics: [
|
||||||
|
{ label: 'Total', value: totalCount },
|
||||||
|
{ label: 'Status 1', value: totalWithStatus1, percentage: `${totalCount > 0 ? Math.round((totalWithStatus1 / totalCount) * 100) : 0}%` },
|
||||||
|
{ label: 'Status 2', value: totalWithStatus2 },
|
||||||
|
],
|
||||||
|
progress: {
|
||||||
|
value: totalCount > 0 ? Math.round((totalWithStatus1 / totalCount) * 100) : 0,
|
||||||
|
label: 'Processed',
|
||||||
|
color: 'blue',
|
||||||
|
},
|
||||||
|
hint: totalWithStatus2 > 0
|
||||||
|
? `${totalWithStatus2} items ready for processing`
|
||||||
|
: 'All items processed!',
|
||||||
|
}}
|
||||||
|
// ... rest of props
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing Checklist
|
||||||
|
|
||||||
|
For each fixed page, verify:
|
||||||
|
|
||||||
|
- [ ] Footer metrics show correct total counts (not page counts)
|
||||||
|
- [ ] Metrics update when changing sites
|
||||||
|
- [ ] Metrics update when changing sectors
|
||||||
|
- [ ] Metrics are consistent with automation page metrics
|
||||||
|
- [ ] Performance is acceptable (lightweight API calls with page_size=1)
|
||||||
|
|
||||||
|
## Related Files
|
||||||
|
|
||||||
|
- `/frontend/src/components/dashboard/ThreeWidgetFooter.tsx`
|
||||||
|
- `/frontend/src/pages/Automation/AutomationPage.tsx` (reference implementation)
|
||||||
|
- All planner and writer page files
|
||||||
|
|
||||||
|
## API Endpoints Used
|
||||||
|
|
||||||
|
All pages use their respective `fetch*` functions with filters:
|
||||||
|
- `fetchKeywords({ status, page_size: 1 })`
|
||||||
|
- `fetchClusters({ status, page_size: 1 })`
|
||||||
|
- `fetchContentIdeas({ status, page_size: 1 })`
|
||||||
|
- `fetchTasks({ status, page_size: 1 })`
|
||||||
|
- `fetchContent({ status, page_size: 1 })`
|
||||||
|
- `fetchContentImages({ status, page_size: 1 })`
|
||||||
|
|
||||||
|
The `page_size: 1` ensures minimal data transfer while still getting the count.
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
- Each page makes 2-3 additional API calls on load
|
||||||
|
- Calls are lightweight (page_size=1, only count is used)
|
||||||
|
- Calls are cached until site/sector changes
|
||||||
|
- Total overhead: ~100-300ms per page load (acceptable)
|
||||||
|
|
||||||
|
## Automation Page Consistency
|
||||||
|
|
||||||
|
The AutomationPage already uses this pattern correctly:
|
||||||
|
- Lines 99-149: Fetches total counts for all metrics
|
||||||
|
- Uses `fetchKeywords({ status: 'new' })`, `fetchKeywords({ status: 'mapped' })`, etc.
|
||||||
|
- Sets metrics in state: `setMetrics({ keywords: { total, new, mapped } })`
|
||||||
|
- All stage cards and metric cards use these pre-fetched totals
|
||||||
|
|
||||||
|
This fix brings all other pages in line with the Automation page's correct implementation.
|
||||||
311
docs/plans/flexible-model-configuration-plan.md
Normal file
311
docs/plans/flexible-model-configuration-plan.md
Normal file
@@ -0,0 +1,311 @@
|
|||||||
|
# Flexible Model Configuration System Plan
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This plan outlines how to implement a flexible model configuration system that allows:
|
||||||
|
- Adding/removing/activating models dynamically
|
||||||
|
- Configuring rates for each model
|
||||||
|
- Supporting multiple providers (OpenAI, Anthropic, Runware)
|
||||||
|
- Per-account model overrides
|
||||||
|
|
||||||
|
## Current State
|
||||||
|
|
||||||
|
### Model Rates (hardcoded in `ai/constants.py`)
|
||||||
|
```python
|
||||||
|
MODEL_RATES = {
|
||||||
|
'gpt-4.1': {'input': 2.00, 'output': 8.00}, # per 1M tokens
|
||||||
|
'gpt-4o-mini': {'input': 0.15, 'output': 0.60},
|
||||||
|
'gpt-4o': {'input': 2.50, 'output': 10.00},
|
||||||
|
'gpt-5.1': {'input': 1.25, 'output': 10.00},
|
||||||
|
'gpt-5.2': {'input': 1.75, 'output': 14.00},
|
||||||
|
}
|
||||||
|
|
||||||
|
IMAGE_MODEL_RATES = {
|
||||||
|
'dall-e-3': 0.040, # per image
|
||||||
|
'dall-e-2': 0.020,
|
||||||
|
'gpt-image-1': 0.042,
|
||||||
|
'gpt-image-1-mini': 0.011,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Current Settings Architecture
|
||||||
|
- `GlobalIntegrationSettings` (singleton) - Platform-wide API keys and defaults
|
||||||
|
- `IntegrationSettings` (per-account) - Model/parameter overrides
|
||||||
|
- `GlobalAIPrompt` - Platform-wide prompt templates
|
||||||
|
- `AIPrompt` (per-account) - Custom prompt overrides
|
||||||
|
|
||||||
|
## Proposed Changes
|
||||||
|
|
||||||
|
### Phase 1: Database Model for AI Models
|
||||||
|
|
||||||
|
Create a new model `AIModel` to store model configurations:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# backend/igny8_core/modules/system/global_settings_models.py
|
||||||
|
|
||||||
|
class AIModel(models.Model):
|
||||||
|
"""
|
||||||
|
Dynamic AI model configuration.
|
||||||
|
Replaces hardcoded MODEL_RATES and IMAGE_MODEL_RATES.
|
||||||
|
"""
|
||||||
|
PROVIDER_CHOICES = [
|
||||||
|
('openai', 'OpenAI'),
|
||||||
|
('anthropic', 'Anthropic'),
|
||||||
|
('runware', 'Runware'),
|
||||||
|
('google', 'Google AI'),
|
||||||
|
]
|
||||||
|
|
||||||
|
MODEL_TYPE_CHOICES = [
|
||||||
|
('text', 'Text Generation'),
|
||||||
|
('image', 'Image Generation'),
|
||||||
|
('embedding', 'Embedding'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Identification
|
||||||
|
model_id = models.CharField(
|
||||||
|
max_length=100,
|
||||||
|
unique=True,
|
||||||
|
help_text="Model identifier (e.g., 'gpt-4o-mini', 'claude-3-sonnet')"
|
||||||
|
)
|
||||||
|
display_name = models.CharField(
|
||||||
|
max_length=200,
|
||||||
|
help_text="User-friendly name (e.g., 'GPT-4o Mini')"
|
||||||
|
)
|
||||||
|
provider = models.CharField(max_length=50, choices=PROVIDER_CHOICES)
|
||||||
|
model_type = models.CharField(max_length=20, choices=MODEL_TYPE_CHOICES)
|
||||||
|
|
||||||
|
# Pricing (per 1M tokens for text, per image for image models)
|
||||||
|
input_rate = models.DecimalField(
|
||||||
|
max_digits=10,
|
||||||
|
decimal_places=4,
|
||||||
|
default=0,
|
||||||
|
help_text="Cost per 1M input tokens (text) or per request (image)"
|
||||||
|
)
|
||||||
|
output_rate = models.DecimalField(
|
||||||
|
max_digits=10,
|
||||||
|
decimal_places=4,
|
||||||
|
default=0,
|
||||||
|
help_text="Cost per 1M output tokens (text only)"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Capabilities
|
||||||
|
max_tokens = models.IntegerField(
|
||||||
|
default=8192,
|
||||||
|
help_text="Maximum tokens for this model"
|
||||||
|
)
|
||||||
|
supports_json_mode = models.BooleanField(
|
||||||
|
default=True,
|
||||||
|
help_text="Whether model supports JSON response format"
|
||||||
|
)
|
||||||
|
supports_vision = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
help_text="Whether model supports image input"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Status
|
||||||
|
is_active = models.BooleanField(default=True)
|
||||||
|
is_default = models.BooleanField(
|
||||||
|
default=False,
|
||||||
|
help_text="Use as default when no specific model is configured"
|
||||||
|
)
|
||||||
|
sort_order = models.IntegerField(default=0)
|
||||||
|
|
||||||
|
# Metadata
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = 'igny8_ai_models'
|
||||||
|
ordering = ['sort_order', 'display_name']
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.display_name} ({self.model_id})"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 2: Model Registry Service
|
||||||
|
|
||||||
|
Create a service layer to manage models:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# backend/igny8_core/ai/model_registry.py
|
||||||
|
|
||||||
|
class ModelRegistry:
|
||||||
|
"""
|
||||||
|
Central registry for AI model configurations.
|
||||||
|
Provides caching and fallback logic.
|
||||||
|
"""
|
||||||
|
|
||||||
|
_cache = {}
|
||||||
|
_cache_ttl = 300 # 5 minutes
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_model(cls, model_id: str) -> Optional[dict]:
|
||||||
|
"""Get model configuration by ID"""
|
||||||
|
# Check cache first
|
||||||
|
# Fallback to database
|
||||||
|
# Return dict with rates, capabilities, etc.
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_models_by_type(cls, model_type: str) -> List[dict]:
|
||||||
|
"""Get all active models of a type"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_default_model(cls, model_type: str = 'text') -> dict:
|
||||||
|
"""Get default model for a type"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def calculate_cost(
|
||||||
|
cls,
|
||||||
|
model_id: str,
|
||||||
|
input_tokens: int = 0,
|
||||||
|
output_tokens: int = 0,
|
||||||
|
image_count: int = 0
|
||||||
|
) -> float:
|
||||||
|
"""Calculate cost for an operation"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_model_supported(cls, model_id: str) -> bool:
|
||||||
|
"""Check if a model is configured and active"""
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 3: Update AICore to Use Registry
|
||||||
|
|
||||||
|
Modify `ai_core.py` to use the model registry:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# In run_ai_request()
|
||||||
|
from igny8_core.ai.model_registry import ModelRegistry
|
||||||
|
|
||||||
|
# Replace hardcoded MODEL_RATES check
|
||||||
|
if not ModelRegistry.is_model_supported(model):
|
||||||
|
supported = ModelRegistry.get_models_by_type('text')
|
||||||
|
error_msg = f"Model '{model}' is not supported. Available models: {[m['model_id'] for m in supported]}"
|
||||||
|
# ...
|
||||||
|
|
||||||
|
# Replace hardcoded cost calculation
|
||||||
|
model_info = ModelRegistry.get_model(model)
|
||||||
|
if model_info:
|
||||||
|
cost = ModelRegistry.calculate_cost(
|
||||||
|
model_id=model,
|
||||||
|
input_tokens=input_tokens,
|
||||||
|
output_tokens=output_tokens
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 4: Admin Interface
|
||||||
|
|
||||||
|
Add Django admin for managing models:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# backend/igny8_core/modules/system/admin.py
|
||||||
|
|
||||||
|
@admin.register(AIModel)
|
||||||
|
class AIModelAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ['model_id', 'display_name', 'provider', 'model_type', 'input_rate', 'output_rate', 'is_active', 'is_default']
|
||||||
|
list_filter = ['provider', 'model_type', 'is_active', 'is_default']
|
||||||
|
search_fields = ['model_id', 'display_name']
|
||||||
|
ordering = ['sort_order', 'display_name']
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
('Identification', {
|
||||||
|
'fields': ('model_id', 'display_name', 'provider', 'model_type')
|
||||||
|
}),
|
||||||
|
('Pricing', {
|
||||||
|
'fields': ('input_rate', 'output_rate')
|
||||||
|
}),
|
||||||
|
('Capabilities', {
|
||||||
|
'fields': ('max_tokens', 'supports_json_mode', 'supports_vision')
|
||||||
|
}),
|
||||||
|
('Status', {
|
||||||
|
'fields': ('is_active', 'is_default', 'sort_order')
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 5: Data Migration
|
||||||
|
|
||||||
|
Create a migration to seed initial models:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Migration file
|
||||||
|
def seed_initial_models(apps, schema_editor):
|
||||||
|
AIModel = apps.get_model('system', 'AIModel')
|
||||||
|
|
||||||
|
models = [
|
||||||
|
# OpenAI Text Models
|
||||||
|
{'model_id': 'gpt-4o-mini', 'display_name': 'GPT-4o Mini', 'provider': 'openai', 'model_type': 'text', 'input_rate': 0.15, 'output_rate': 0.60, 'is_default': True},
|
||||||
|
{'model_id': 'gpt-4o', 'display_name': 'GPT-4o', 'provider': 'openai', 'model_type': 'text', 'input_rate': 2.50, 'output_rate': 10.00},
|
||||||
|
{'model_id': 'gpt-4.1', 'display_name': 'GPT-4.1', 'provider': 'openai', 'model_type': 'text', 'input_rate': 2.00, 'output_rate': 8.00},
|
||||||
|
{'model_id': 'gpt-5.1', 'display_name': 'GPT-5.1', 'provider': 'openai', 'model_type': 'text', 'input_rate': 1.25, 'output_rate': 10.00, 'max_tokens': 16000},
|
||||||
|
{'model_id': 'gpt-5.2', 'display_name': 'GPT-5.2', 'provider': 'openai', 'model_type': 'text', 'input_rate': 1.75, 'output_rate': 14.00, 'max_tokens': 16000},
|
||||||
|
|
||||||
|
# Anthropic Text Models
|
||||||
|
{'model_id': 'claude-3-sonnet', 'display_name': 'Claude 3 Sonnet', 'provider': 'anthropic', 'model_type': 'text', 'input_rate': 3.00, 'output_rate': 15.00},
|
||||||
|
{'model_id': 'claude-3-opus', 'display_name': 'Claude 3 Opus', 'provider': 'anthropic', 'model_type': 'text', 'input_rate': 15.00, 'output_rate': 75.00},
|
||||||
|
{'model_id': 'claude-3-haiku', 'display_name': 'Claude 3 Haiku', 'provider': 'anthropic', 'model_type': 'text', 'input_rate': 0.25, 'output_rate': 1.25},
|
||||||
|
|
||||||
|
# OpenAI Image Models
|
||||||
|
{'model_id': 'dall-e-3', 'display_name': 'DALL-E 3', 'provider': 'openai', 'model_type': 'image', 'input_rate': 0.040, 'output_rate': 0},
|
||||||
|
{'model_id': 'dall-e-2', 'display_name': 'DALL-E 2', 'provider': 'openai', 'model_type': 'image', 'input_rate': 0.020, 'output_rate': 0},
|
||||||
|
{'model_id': 'gpt-image-1', 'display_name': 'GPT Image 1', 'provider': 'openai', 'model_type': 'image', 'input_rate': 0.042, 'output_rate': 0},
|
||||||
|
|
||||||
|
# Runware Image Models
|
||||||
|
{'model_id': 'runware:97@1', 'display_name': 'Runware 97@1', 'provider': 'runware', 'model_type': 'image', 'input_rate': 0.009, 'output_rate': 0},
|
||||||
|
]
|
||||||
|
|
||||||
|
for i, model in enumerate(models):
|
||||||
|
AIModel.objects.create(sort_order=i, **model)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 6: API Endpoints for Model Management
|
||||||
|
|
||||||
|
Add REST endpoints for managing models:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# GET /api/v1/admin/ai-models/ - List all models
|
||||||
|
# POST /api/v1/admin/ai-models/ - Create new model
|
||||||
|
# PUT /api/v1/admin/ai-models/{id}/ - Update model
|
||||||
|
# DELETE /api/v1/admin/ai-models/{id}/ - Delete model
|
||||||
|
# POST /api/v1/admin/ai-models/{id}/toggle-active/ - Toggle active status
|
||||||
|
# POST /api/v1/admin/ai-models/{id}/set-default/ - Set as default
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 7: Frontend Admin UI
|
||||||
|
|
||||||
|
Create admin UI for model management:
|
||||||
|
- List view with filtering/sorting
|
||||||
|
- Create/Edit form with validation
|
||||||
|
- Quick toggle for active/default status
|
||||||
|
- Price calculator preview
|
||||||
|
|
||||||
|
## Implementation Order
|
||||||
|
|
||||||
|
1. **Week 1**: Create `AIModel` model and migration
|
||||||
|
2. **Week 1**: Create `ModelRegistry` service
|
||||||
|
3. **Week 2**: Update `ai_core.py` to use registry
|
||||||
|
4. **Week 2**: Update `constants.py` to load from database
|
||||||
|
5. **Week 3**: Add Django admin interface
|
||||||
|
6. **Week 3**: Add API endpoints
|
||||||
|
7. **Week 4**: Create frontend admin UI
|
||||||
|
8. **Week 4**: Testing and documentation
|
||||||
|
|
||||||
|
## Backward Compatibility
|
||||||
|
|
||||||
|
- Keep `constants.py` as fallback if database is empty
|
||||||
|
- `ModelRegistry.get_model()` checks DB first, falls back to constants
|
||||||
|
- No changes to existing `GlobalIntegrationSettings` or `IntegrationSettings`
|
||||||
|
- Existing API calls continue to work unchanged
|
||||||
|
|
||||||
|
## Benefits
|
||||||
|
|
||||||
|
1. **No Code Changes for New Models**: Add models via admin UI
|
||||||
|
2. **Easy Price Updates**: Update rates without deployment
|
||||||
|
3. **Provider Flexibility**: Support any provider by adding models
|
||||||
|
4. **Per-Provider Settings**: Configure different capabilities per provider
|
||||||
|
5. **Audit Trail**: Track when models were added/modified
|
||||||
|
6. **A/B Testing**: Easily enable/disable models for testing
|
||||||
@@ -37,7 +37,11 @@ export default function Clusters() {
|
|||||||
// Data state
|
// Data state
|
||||||
const [clusters, setClusters] = useState<Cluster[]>([]);
|
const [clusters, setClusters] = useState<Cluster[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
// Total counts for footer widget (not page-filtered)
|
||||||
|
const [totalWithIdeas, setTotalWithIdeas] = useState(0);
|
||||||
|
const [totalReady, setTotalReady] = useState(0);
|
||||||
|
|
||||||
// Filter state
|
// Filter state
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const [statusFilter, setStatusFilter] = useState('');
|
const [statusFilter, setStatusFilter] = useState('');
|
||||||
@@ -75,6 +79,34 @@ export default function Clusters() {
|
|||||||
const progressModal = useProgressModal();
|
const progressModal = useProgressModal();
|
||||||
const hasReloadedRef = useRef(false);
|
const hasReloadedRef = useRef(false);
|
||||||
|
|
||||||
|
// Load total metrics for footer widget (not affected by pagination)
|
||||||
|
const loadTotalMetrics = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
// Get clusters with status='mapped' (those that have ideas)
|
||||||
|
const mappedRes = await fetchClusters({
|
||||||
|
page_size: 1,
|
||||||
|
...(activeSector?.id && { sector_id: activeSector.id }),
|
||||||
|
status: 'mapped',
|
||||||
|
});
|
||||||
|
setTotalWithIdeas(mappedRes.count || 0);
|
||||||
|
|
||||||
|
// Get clusters with status='new' (those that are ready for ideas)
|
||||||
|
const newRes = await fetchClusters({
|
||||||
|
page_size: 1,
|
||||||
|
...(activeSector?.id && { sector_id: activeSector.id }),
|
||||||
|
status: 'new',
|
||||||
|
});
|
||||||
|
setTotalReady(newRes.count || 0);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading total metrics:', error);
|
||||||
|
}
|
||||||
|
}, [activeSector]);
|
||||||
|
|
||||||
|
// Load total metrics when sector changes
|
||||||
|
useEffect(() => {
|
||||||
|
loadTotalMetrics();
|
||||||
|
}, [loadTotalMetrics]);
|
||||||
|
|
||||||
// Load clusters - wrapped in useCallback to prevent infinite loops
|
// Load clusters - wrapped in useCallback to prevent infinite loops
|
||||||
const loadClusters = useCallback(async () => {
|
const loadClusters = useCallback(async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -494,17 +526,17 @@ export default function Clusters() {
|
|||||||
submoduleColor: 'green',
|
submoduleColor: 'green',
|
||||||
metrics: [
|
metrics: [
|
||||||
{ label: 'Clusters', value: totalCount },
|
{ label: 'Clusters', value: totalCount },
|
||||||
{ label: 'With Ideas', value: clusters.filter(c => (c.ideas_count || 0) > 0).length, percentage: `${totalCount > 0 ? Math.round((clusters.filter(c => (c.ideas_count || 0) > 0).length / totalCount) * 100) : 0}%` },
|
{ label: 'With Ideas', value: totalWithIdeas, percentage: `${totalCount > 0 ? Math.round((totalWithIdeas / totalCount) * 100) : 0}%` },
|
||||||
{ label: 'Keywords', value: clusters.reduce((sum, c) => sum + (c.keywords_count || 0), 0) },
|
{ label: 'Keywords', value: clusters.reduce((sum, c) => sum + (c.keywords_count || 0), 0) },
|
||||||
{ label: 'Ready', value: clusters.filter(c => (c.ideas_count || 0) === 0).length },
|
{ label: 'Ready', value: totalReady },
|
||||||
],
|
],
|
||||||
progress: {
|
progress: {
|
||||||
value: totalCount > 0 ? Math.round((clusters.filter(c => (c.ideas_count || 0) > 0).length / totalCount) * 100) : 0,
|
value: totalCount > 0 ? Math.round((totalWithIdeas / totalCount) * 100) : 0,
|
||||||
label: 'Have Ideas',
|
label: 'Have Ideas',
|
||||||
color: 'green',
|
color: 'green',
|
||||||
},
|
},
|
||||||
hint: clusters.filter(c => (c.ideas_count || 0) === 0).length > 0
|
hint: totalReady > 0
|
||||||
? `${clusters.filter(c => (c.ideas_count || 0) === 0).length} clusters ready for idea generation`
|
? `${totalReady} clusters ready for idea generation`
|
||||||
: 'All clusters have ideas!',
|
: 'All clusters have ideas!',
|
||||||
}}
|
}}
|
||||||
moduleStats={{
|
moduleStats={{
|
||||||
|
|||||||
@@ -40,7 +40,11 @@ export default function Ideas() {
|
|||||||
const [ideas, setIdeas] = useState<ContentIdea[]>([]);
|
const [ideas, setIdeas] = useState<ContentIdea[]>([]);
|
||||||
const [clusters, setClusters] = useState<Cluster[]>([]);
|
const [clusters, setClusters] = useState<Cluster[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
// Total counts for footer widget (not page-filtered)
|
||||||
|
const [totalInTasks, setTotalInTasks] = useState(0);
|
||||||
|
const [totalPending, setTotalPending] = useState(0);
|
||||||
|
|
||||||
// Filter state
|
// Filter state
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const [statusFilter, setStatusFilter] = useState('');
|
const [statusFilter, setStatusFilter] = useState('');
|
||||||
@@ -90,6 +94,39 @@ export default function Ideas() {
|
|||||||
loadClusters();
|
loadClusters();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Load total metrics for footer widget (not affected by pagination)
|
||||||
|
const loadTotalMetrics = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
// Get ideas with status='queued' or 'completed' (those in tasks/writer)
|
||||||
|
const queuedRes = await fetchContentIdeas({
|
||||||
|
page_size: 1,
|
||||||
|
...(activeSector?.id && { sector_id: activeSector.id }),
|
||||||
|
status: 'queued',
|
||||||
|
});
|
||||||
|
const completedRes = await fetchContentIdeas({
|
||||||
|
page_size: 1,
|
||||||
|
...(activeSector?.id && { sector_id: activeSector.id }),
|
||||||
|
status: 'completed',
|
||||||
|
});
|
||||||
|
setTotalInTasks((queuedRes.count || 0) + (completedRes.count || 0));
|
||||||
|
|
||||||
|
// Get ideas with status='new' (those ready to become tasks)
|
||||||
|
const newRes = await fetchContentIdeas({
|
||||||
|
page_size: 1,
|
||||||
|
...(activeSector?.id && { sector_id: activeSector.id }),
|
||||||
|
status: 'new',
|
||||||
|
});
|
||||||
|
setTotalPending(newRes.count || 0);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading total metrics:', error);
|
||||||
|
}
|
||||||
|
}, [activeSector]);
|
||||||
|
|
||||||
|
// Load total metrics when sector changes
|
||||||
|
useEffect(() => {
|
||||||
|
loadTotalMetrics();
|
||||||
|
}, [loadTotalMetrics]);
|
||||||
|
|
||||||
// Load ideas - wrapped in useCallback
|
// Load ideas - wrapped in useCallback
|
||||||
const loadIdeas = useCallback(async () => {
|
const loadIdeas = useCallback(async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -422,17 +459,17 @@ export default function Ideas() {
|
|||||||
submoduleColor: 'amber',
|
submoduleColor: 'amber',
|
||||||
metrics: [
|
metrics: [
|
||||||
{ label: 'Ideas', value: totalCount },
|
{ label: 'Ideas', value: totalCount },
|
||||||
{ label: 'In Tasks', value: ideas.filter(i => i.status === 'queued' || i.status === 'completed').length, percentage: `${totalCount > 0 ? Math.round((ideas.filter(i => i.status === 'queued' || i.status === 'completed').length / totalCount) * 100) : 0}%` },
|
{ label: 'In Tasks', value: totalInTasks, percentage: `${totalCount > 0 ? Math.round((totalInTasks / totalCount) * 100) : 0}%` },
|
||||||
{ label: 'Pending', value: ideas.filter(i => i.status === 'new').length },
|
{ label: 'Pending', value: totalPending },
|
||||||
{ label: 'From Clusters', value: clusters.length },
|
{ label: 'From Clusters', value: clusters.length },
|
||||||
],
|
],
|
||||||
progress: {
|
progress: {
|
||||||
value: totalCount > 0 ? Math.round((ideas.filter(i => i.status === 'queued' || i.status === 'completed').length / totalCount) * 100) : 0,
|
value: totalCount > 0 ? Math.round((totalInTasks / totalCount) * 100) : 0,
|
||||||
label: 'Converted',
|
label: 'Converted',
|
||||||
color: 'amber',
|
color: 'amber',
|
||||||
},
|
},
|
||||||
hint: ideas.filter(i => i.status === 'new').length > 0
|
hint: totalPending > 0
|
||||||
? `${ideas.filter(i => i.status === 'new').length} ideas ready to become tasks`
|
? `${totalPending} ideas ready to become tasks`
|
||||||
: 'All ideas converted!',
|
: 'All ideas converted!',
|
||||||
}}
|
}}
|
||||||
moduleStats={{
|
moduleStats={{
|
||||||
|
|||||||
@@ -45,7 +45,12 @@ export default function Keywords() {
|
|||||||
const [keywords, setKeywords] = useState<Keyword[]>([]);
|
const [keywords, setKeywords] = useState<Keyword[]>([]);
|
||||||
const [clusters, setClusters] = useState<Cluster[]>([]);
|
const [clusters, setClusters] = useState<Cluster[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
// Total counts for footer widget (not page-filtered)
|
||||||
|
const [totalClustered, setTotalClustered] = useState(0);
|
||||||
|
const [totalUnmapped, setTotalUnmapped] = useState(0);
|
||||||
|
const [totalVolume, setTotalVolume] = useState(0);
|
||||||
|
|
||||||
// Filter state - match Keywords.tsx
|
// Filter state - match Keywords.tsx
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const [statusFilter, setStatusFilter] = useState('');
|
const [statusFilter, setStatusFilter] = useState('');
|
||||||
@@ -108,6 +113,44 @@ export default function Keywords() {
|
|||||||
loadClusters();
|
loadClusters();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Load total metrics for footer widget (not affected by pagination)
|
||||||
|
const loadTotalMetrics = useCallback(async () => {
|
||||||
|
if (!activeSite) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get all keywords (total count) - this is already in totalCount from main load
|
||||||
|
// Get keywords with status='mapped' (those that have been mapped to a cluster)
|
||||||
|
const mappedRes = await fetchKeywords({
|
||||||
|
page_size: 1,
|
||||||
|
site_id: activeSite.id,
|
||||||
|
...(activeSector?.id && { sector_id: activeSector.id }),
|
||||||
|
status: 'mapped',
|
||||||
|
});
|
||||||
|
setTotalClustered(mappedRes.count || 0);
|
||||||
|
|
||||||
|
// Get keywords with status='new' (those that are ready to cluster but haven't been yet)
|
||||||
|
const newRes = await fetchKeywords({
|
||||||
|
page_size: 1,
|
||||||
|
site_id: activeSite.id,
|
||||||
|
...(activeSector?.id && { sector_id: activeSector.id }),
|
||||||
|
status: 'new',
|
||||||
|
});
|
||||||
|
setTotalUnmapped(newRes.count || 0);
|
||||||
|
|
||||||
|
// Get total volume across all keywords (we need to fetch all or rely on backend aggregation)
|
||||||
|
// For now, we'll just calculate from current data or set to 0
|
||||||
|
// TODO: Backend should provide total volume as an aggregated metric
|
||||||
|
setTotalVolume(0);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading total metrics:', error);
|
||||||
|
}
|
||||||
|
}, [activeSite, activeSector]);
|
||||||
|
|
||||||
|
// Load total metrics when site/sector changes
|
||||||
|
useEffect(() => {
|
||||||
|
loadTotalMetrics();
|
||||||
|
}, [loadTotalMetrics]);
|
||||||
|
|
||||||
// Load keywords - wrapped in useCallback to prevent infinite loops
|
// Load keywords - wrapped in useCallback to prevent infinite loops
|
||||||
const loadKeywords = useCallback(async () => {
|
const loadKeywords = useCallback(async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -712,17 +755,17 @@ export default function Keywords() {
|
|||||||
submoduleColor: 'blue',
|
submoduleColor: 'blue',
|
||||||
metrics: [
|
metrics: [
|
||||||
{ label: 'Keywords', value: totalCount },
|
{ label: 'Keywords', value: totalCount },
|
||||||
{ label: 'Clustered', value: keywords.filter(k => k.cluster_id).length, percentage: `${totalCount > 0 ? Math.round((keywords.filter(k => k.cluster_id).length / totalCount) * 100) : 0}%` },
|
{ label: 'Clustered', value: totalClustered, percentage: `${totalCount > 0 ? Math.round((totalClustered / totalCount) * 100) : 0}%` },
|
||||||
{ label: 'Unmapped', value: keywords.filter(k => !k.cluster_id).length },
|
{ label: 'Unmapped', value: totalUnmapped },
|
||||||
{ label: 'Volume', value: `${(keywords.reduce((sum, k) => sum + (k.volume || 0), 0) / 1000).toFixed(1)}K` },
|
{ label: 'Volume', value: totalVolume > 0 ? `${(totalVolume / 1000).toFixed(1)}K` : '-' },
|
||||||
],
|
],
|
||||||
progress: {
|
progress: {
|
||||||
value: totalCount > 0 ? Math.round((keywords.filter(k => k.cluster_id).length / totalCount) * 100) : 0,
|
value: totalCount > 0 ? Math.round((totalClustered / totalCount) * 100) : 0,
|
||||||
label: 'Clustered',
|
label: 'Clustered',
|
||||||
color: 'blue',
|
color: 'blue',
|
||||||
},
|
},
|
||||||
hint: keywords.filter(k => !k.cluster_id).length > 0
|
hint: totalUnmapped > 0
|
||||||
? `${keywords.filter(k => !k.cluster_id).length} keywords ready to cluster`
|
? `${totalUnmapped} keywords ready to cluster`
|
||||||
: 'All keywords clustered!',
|
: 'All keywords clustered!',
|
||||||
}}
|
}}
|
||||||
moduleStats={{
|
moduleStats={{
|
||||||
|
|||||||
@@ -1,177 +0,0 @@
|
|||||||
|
|
||||||
## 5. Dashboard Redesign Plan
|
|
||||||
|
|
||||||
### Current Issues
|
|
||||||
- Too much whitespace and large headings
|
|
||||||
- Repeating same counts/metrics without different dimensions
|
|
||||||
- Missing actionable insights
|
|
||||||
- No AI operations analytics
|
|
||||||
- Missing "needs attention" items
|
|
||||||
|
|
||||||
### New Dashboard Design: Multi-Dimension Compact Widgets
|
|
||||||
|
|
||||||
Based on Django admin reports analysis, the dashboard should show **different data dimensions** instead of repeating counts:
|
|
||||||
|
|
||||||
### Dashboard Layout (Compact, Information-Dense)
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────────────────────────────────┐
|
|
||||||
│ ⚠ NEEDS ATTENTION (collapsible, only shows if items exist) │
|
|
||||||
│ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐ │
|
|
||||||
│ │ 3 pending review │ │ WP sync failed │ │ Setup incomplete │ │
|
|
||||||
│ │ [Review →] │ │ [Retry] [Fix →] │ │ [Complete →] │ │
|
|
||||||
│ └────────────────────┘ └────────────────────┘ └────────────────────┘ │
|
|
||||||
├─────────────────────────────────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ ┌─────────────────────────────────┐ ┌─────────────────────────────────────────┐ │
|
|
||||||
│ │ WORKFLOW PIPELINE │ │ QUICK ACTIONS │ │
|
|
||||||
│ │ │ │ │ │
|
|
||||||
│ │ Sites → KWs → Clusters → Ideas │ │ [+ Keywords] [⚡ Cluster] [📝 Content] │ │
|
|
||||||
│ │ 2 156 23 67 │ │ [🖼 Images] [✓ Review] [🚀 Publish] │ │
|
|
||||||
│ │ ↓ │ │ │ │
|
|
||||||
│ │ Tasks → Drafts → Published │ │ WORKFLOW GUIDE │ │
|
|
||||||
│ │ 45 28 45 │ │ 1. Add Keywords 5. Generate Content │ │
|
|
||||||
│ │ │ │ 2. Auto Cluster 6. Generate Images │ │
|
|
||||||
│ │ ████████████░░░ 72% Complete │ │ 3. Generate Ideas 7. Review & Approve │ │
|
|
||||||
│ │ │ │ 4. Create Tasks 8. Publish to WP │ │
|
|
||||||
│ └─────────────────────────────────┘ │ [Full Help →] │ │
|
|
||||||
│ └─────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
├─────────────────────────────────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ ┌─────────────────────────────────┐ ┌─────────────────────────────────────────┐ │
|
|
||||||
│ │ AI OPERATIONS (7d) [▼ 30d] │ │ RECENT ACTIVITY │ │
|
|
||||||
│ │ │ │ │ │
|
|
||||||
│ │ Operation Count Credits │ │ • Clustered 45 keywords → 8 clusters │ │
|
|
||||||
│ │ ───────────────────────────────│ │ 2 hours ago │ │
|
|
||||||
│ │ Clustering 8 80 │ │ • Generated 5 articles (4.2K words) │ │
|
|
||||||
│ │ Ideas 12 24 │ │ 4 hours ago │ │
|
|
||||||
│ │ Content 28 1,400 │ │ • Created 15 image prompts │ │
|
|
||||||
│ │ Images 45 225 │ │ Yesterday │ │
|
|
||||||
│ │ ───────────────────────────────│ │ • Published "Best Running Shoes" to WP │ │
|
|
||||||
│ │ Total 93 1,729 │ │ Yesterday │ │
|
|
||||||
│ │ │ │ • Added 23 keywords from seed DB │ │
|
|
||||||
│ │ Success Rate: 98.5% │ │ 2 days ago │ │
|
|
||||||
│ │ Avg Credits/Op: 18.6 │ │ │ │
|
|
||||||
│ └─────────────────────────────────┘ │ [View All Activity →] │ │
|
|
||||||
│ └─────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
├─────────────────────────────────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ ┌─────────────────────────────────┐ ┌─────────────────────────────────────────┐ │
|
|
||||||
│ │ CONTENT VELOCITY │ │ AUTOMATION STATUS │ │
|
|
||||||
│ │ │ │ │ │
|
|
||||||
│ │ This Week This Month Total │ │ ● Active │ Schedule: Daily 9 AM │ │
|
|
||||||
│ │ │ │ │ │
|
|
||||||
│ │ Articles 5 28 156 │ │ Last Run: Dec 27, 7:00 AM │ │
|
|
||||||
│ │ Words 4.2K 24K 156K │ │ ├─ Clustered: 12 keywords │ │
|
|
||||||
│ │ Images 12 67 340 │ │ ├─ Ideas: 8 generated │ │
|
|
||||||
│ │ │ │ ├─ Content: 5 articles │ │
|
|
||||||
│ │ 📈 +23% vs last week │ │ └─ Images: 15 created │ │
|
|
||||||
│ │ │ │ │ │
|
|
||||||
│ │ [View Analytics →] │ │ Next Run: Dec 28, 9:00 AM │ │
|
|
||||||
│ └─────────────────────────────────┘ │ [Configure →] [Run Now →] │ │
|
|
||||||
│ └─────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Widget Specifications
|
|
||||||
|
|
||||||
#### 1. Needs Attention Bar
|
|
||||||
- Collapsible, only visible when items exist
|
|
||||||
- Types: `pending_review`, `sync_failed`, `setup_incomplete`, `automation_failed`
|
|
||||||
- Compact horizontal cards with action buttons
|
|
||||||
|
|
||||||
#### 2. Workflow Pipeline Widget
|
|
||||||
- Visual flow: Sites → Keywords → Clusters → Ideas → Tasks → Drafts → Published
|
|
||||||
- Shows counts at each stage
|
|
||||||
- Single progress bar for overall completion
|
|
||||||
- Clickable stage names link to respective pages
|
|
||||||
|
|
||||||
#### 3. Quick Actions + Workflow Guide Widget
|
|
||||||
- 2x3 grid of action buttons (use existing icons)
|
|
||||||
- Compact numbered workflow guide (1-8 steps)
|
|
||||||
- "Full Help" link to help page
|
|
||||||
|
|
||||||
#### 4. AI Operations Widget (NEW - from Django Admin Reports)
|
|
||||||
Shows data from `CreditUsageLog` model:
|
|
||||||
```typescript
|
|
||||||
interface AIOperationsData {
|
|
||||||
period: '7d' | '30d' | '90d';
|
|
||||||
operations: Array<{
|
|
||||||
type: 'clustering' | 'ideas' | 'content' | 'images';
|
|
||||||
count: number;
|
|
||||||
credits: number;
|
|
||||||
}>;
|
|
||||||
totals: {
|
|
||||||
count: number;
|
|
||||||
credits: number;
|
|
||||||
success_rate: number;
|
|
||||||
avg_credits_per_op: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- Time period filter (7d/30d/90d dropdown)
|
|
||||||
- Table with operation type, count, credits
|
|
||||||
- Success rate percentage
|
|
||||||
- Average credits per operation
|
|
||||||
|
|
||||||
#### 5. Recent Activity Widget
|
|
||||||
Shows data from `AITaskLog` and `CreditUsageLog`:
|
|
||||||
- Last 5 significant operations
|
|
||||||
- Timestamp relative (2 hours ago, Yesterday)
|
|
||||||
- Clickable to navigate to relevant content
|
|
||||||
- "View All Activity" link
|
|
||||||
|
|
||||||
#### 6. Content Velocity Widget (NEW)
|
|
||||||
Shows content production rates:
|
|
||||||
```typescript
|
|
||||||
interface ContentVelocityData {
|
|
||||||
this_week: { articles: number; words: number; images: number };
|
|
||||||
this_month: { articles: number; words: number; images: number };
|
|
||||||
total: { articles: number; words: number; images: number };
|
|
||||||
trend: number; // percentage vs previous period
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- Three time columns: This Week, This Month, Total
|
|
||||||
- Rows: Articles, Words, Images
|
|
||||||
- Trend indicator vs previous period
|
|
||||||
|
|
||||||
#### 7. Automation Status Widget
|
|
||||||
Shows automation run status:
|
|
||||||
- Current status indicator (Active/Paused/Failed)
|
|
||||||
- Schedule display
|
|
||||||
- Last run details with stage breakdown
|
|
||||||
- Next scheduled run
|
|
||||||
- Configure and Run Now buttons
|
|
||||||
|
|
||||||
### API Endpoint Required
|
|
||||||
|
|
||||||
```python
|
|
||||||
# GET /api/v1/dashboard/summary/
|
|
||||||
{
|
|
||||||
"needs_attention": [...],
|
|
||||||
"pipeline": {
|
|
||||||
"sites": 2, "keywords": 156, "clusters": 23,
|
|
||||||
"ideas": 67, "tasks": 45, "drafts": 28, "published": 45,
|
|
||||||
"completion_percentage": 72
|
|
||||||
},
|
|
||||||
"ai_operations": {
|
|
||||||
"period": "7d",
|
|
||||||
"operations": [...],
|
|
||||||
"totals": {...}
|
|
||||||
},
|
|
||||||
"recent_activity": [...],
|
|
||||||
"content_velocity": {...},
|
|
||||||
"automation": {...}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Implementation Notes
|
|
||||||
|
|
||||||
- Use existing components from `components/ui/`
|
|
||||||
- Use CSS tokens from `styles/tokens.css`
|
|
||||||
- Grid layout: `grid grid-cols-1 lg:grid-cols-2 gap-4`
|
|
||||||
- Compact widget padding: `p-4`
|
|
||||||
- No large headings - use subtle section labels
|
|
||||||
@@ -1,181 +0,0 @@
|
|||||||
# Plan: Site & Sector Selector Configuration
|
|
||||||
|
|
||||||
**Source:** COMPREHENSIVE-AUDIT-REPORT.md - Section 1
|
|
||||||
**Priority:** High for Planner & Writer pages
|
|
||||||
**Estimated Effort:** 4-6 hours
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Objective
|
|
||||||
|
|
||||||
Ensure correct placement of Site Selector and Sector Selector across all pages based on data scope requirements.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Configuration Rules
|
|
||||||
|
|
||||||
| Condition | Site Selector | Sector Selector |
|
|
||||||
|-----------|:-------------:|:---------------:|
|
|
||||||
| Data scoped to specific site | ✅ | ❌ |
|
|
||||||
| Data can be filtered by content category | ✅ | ✅ |
|
|
||||||
| Page is not site-specific (account-level) | ❌ | ❌ |
|
|
||||||
| Already in specific context (detail page) | ❌ | ❌ |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Implementation Checklist
|
|
||||||
|
|
||||||
### DASHBOARD Module
|
|
||||||
- [ ] **Home** - Site Selector: ✅ (with "All Sites" option) | Sector: ❌
|
|
||||||
- Overview across sites - sector too granular for dashboard
|
|
||||||
|
|
||||||
### SETUP Module
|
|
||||||
- [ ] **Add Keywords** - Site: ✅ | Sector: ✅
|
|
||||||
- Keywords are site+sector specific
|
|
||||||
- [ ] **Content Settings** - Site: ✅ | Sector: ❌
|
|
||||||
- Settings are site-level, not sector-level
|
|
||||||
- [ ] **Sites List** - Site: ❌ | Sector: ❌
|
|
||||||
- Managing sites themselves
|
|
||||||
- [ ] **Site Dashboard** - Site: ❌ (context) | Sector: ❌
|
|
||||||
- Already in specific site context
|
|
||||||
- [ ] **Site Settings tabs** - Site: ❌ (context) | Sector: ❌
|
|
||||||
- Already in specific site context
|
|
||||||
|
|
||||||
### PLANNER Module
|
|
||||||
- [ ] **Keywords** - Site: ✅ | Sector: ✅
|
|
||||||
- Keywords organized by site+sector
|
|
||||||
- [ ] **Clusters** - Site: ✅ | Sector: ✅
|
|
||||||
- Clusters organized by site+sector
|
|
||||||
- [ ] **Cluster Detail** - Site: ❌ (context) | Sector: ❌ (context)
|
|
||||||
- Already in cluster context
|
|
||||||
- [ ] **Ideas** - Site: ✅ | Sector: ✅
|
|
||||||
- Ideas organized by site+sector
|
|
||||||
|
|
||||||
### WRITER Module
|
|
||||||
- [ ] **Tasks/Queue** - Site: ✅ | Sector: ✅
|
|
||||||
- Tasks organized by site+sector
|
|
||||||
- [ ] **Content/Drafts** - Site: ✅ | Sector: ✅
|
|
||||||
- Content organized by site+sector
|
|
||||||
- [ ] **Content View** - Site: ❌ (context) | Sector: ❌ (context)
|
|
||||||
- Viewing specific content
|
|
||||||
- [ ] **Images** - Site: ✅ | Sector: ✅
|
|
||||||
- Images tied to content by site+sector
|
|
||||||
- [ ] **Review** - Site: ✅ | Sector: ✅
|
|
||||||
- Review queue by site+sector
|
|
||||||
- [ ] **Published** - Site: ✅ | Sector: ✅
|
|
||||||
- Published content by site+sector
|
|
||||||
|
|
||||||
### AUTOMATION Module
|
|
||||||
- [ ] **Automation** - Site: ✅ | Sector: ❌
|
|
||||||
- Automation runs at site level
|
|
||||||
|
|
||||||
### LINKER Module (if enabled)
|
|
||||||
- [ ] **Content List** - Site: ✅ | Sector: ✅
|
|
||||||
- Linking is content-specific
|
|
||||||
|
|
||||||
### OPTIMIZER Module (if enabled)
|
|
||||||
- [ ] **Content Selector** - Site: ✅ | Sector: ✅
|
|
||||||
- Optimization is content-specific
|
|
||||||
- [ ] **Analysis Preview** - Site: ❌ (context) | Sector: ❌ (context)
|
|
||||||
- Already in analysis context
|
|
||||||
|
|
||||||
### THINKER Module (Admin)
|
|
||||||
- [ ] **All Thinker pages** - Site: ❌ | Sector: ❌
|
|
||||||
- System-wide prompts/profiles
|
|
||||||
|
|
||||||
### BILLING Module
|
|
||||||
- [ ] **All Billing pages** - Site: ❌ | Sector: ❌
|
|
||||||
- Account-level billing data
|
|
||||||
|
|
||||||
### ACCOUNT Module
|
|
||||||
- [ ] **Account Settings** - Site: ❌ | Sector: ❌
|
|
||||||
- [ ] **Profile** - Site: ❌ | Sector: ❌
|
|
||||||
- [ ] **Team** - Site: ❌ | Sector: ❌
|
|
||||||
- [ ] **Plans** - Site: ❌ | Sector: ❌
|
|
||||||
- [ ] **Usage** - Site: ❌ | Sector: ❌
|
|
||||||
|
|
||||||
### HELP Module
|
|
||||||
- [ ] **Help Page** - Site: ❌ | Sector: ❌
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Site Setup Checklist on Site Cards
|
|
||||||
|
|
||||||
**Source:** Section 6 of Audit Report
|
|
||||||
|
|
||||||
### Current Status
|
|
||||||
- ✅ `SiteSetupChecklist.tsx` component EXISTS
|
|
||||||
- ✅ Integrated in Site Dashboard (full mode)
|
|
||||||
- ❌ **NOT integrated in SiteCard.tsx** (compact mode)
|
|
||||||
|
|
||||||
### Implementation Task
|
|
||||||
|
|
||||||
**File:** `frontend/src/components/sites/SiteCard.tsx`
|
|
||||||
|
|
||||||
Add compact checklist after status badges:
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
<SiteSetupChecklist
|
|
||||||
siteId={site.id}
|
|
||||||
siteName={site.name}
|
|
||||||
hasIndustry={!!site.industry}
|
|
||||||
hasSectors={site.sectors_count > 0}
|
|
||||||
hasWordPressIntegration={!!site.wordpress_site_url}
|
|
||||||
hasKeywords={site.keywords_count > 0}
|
|
||||||
compact={true}
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Expected Visual:**
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────┐
|
|
||||||
│ My Website [Active] │
|
|
||||||
│ example.com │
|
|
||||||
│ Industry: Tech │ 3 Sectors │
|
|
||||||
│ ●●●○ 3/4 Setup Steps Complete │ ← compact checklist
|
|
||||||
│ [Manage →] │
|
|
||||||
└─────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Backend Requirements
|
|
||||||
|
|
||||||
Ensure `SiteSerializer` returns these fields for checklist:
|
|
||||||
- `keywords_count` - number of keywords
|
|
||||||
- `has_integration` - boolean for WordPress integration
|
|
||||||
- `active_sectors_count` - number of active sectors
|
|
||||||
- `industry_name` - industry name or null
|
|
||||||
|
|
||||||
**Status:** ✅ Already verified these fields are returned
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Files to Modify
|
|
||||||
|
|
||||||
### Frontend
|
|
||||||
1. `frontend/src/components/sites/SiteCard.tsx` - Add compact SiteSetupChecklist
|
|
||||||
2. Various page files to verify/add selector configuration
|
|
||||||
|
|
||||||
### Selector Components
|
|
||||||
- `frontend/src/components/common/SiteSelector.tsx`
|
|
||||||
- `frontend/src/components/common/SectorSelector.tsx`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing Checklist
|
|
||||||
|
|
||||||
- [ ] Site selector shows on all required pages
|
|
||||||
- [ ] Sector selector shows only where data is sector-specific
|
|
||||||
- [ ] Detail pages (Cluster Detail, Content View) have no selectors
|
|
||||||
- [ ] Account/Billing pages have no selectors
|
|
||||||
- [ ] SiteCard shows compact setup checklist
|
|
||||||
- [ ] Checklist updates when site configuration changes
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
- The "All Sites" option on Dashboard should aggregate data across all user's sites
|
|
||||||
- Context pages (detail views) inherit site/sector from parent navigation
|
|
||||||
- Selector state should persist in URL params or store for deep linking
|
|
||||||
@@ -1,289 +0,0 @@
|
|||||||
# Section 2: SETUP Modules - Audit & Action Plan
|
|
||||||
|
|
||||||
**Date:** December 27, 2025
|
|
||||||
**Status:** Finalized for Implementation
|
|
||||||
**Scope:** Add Keywords, Content Settings, Sites (Thinker excluded - admin only)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2.1 Add Keywords
|
|
||||||
|
|
||||||
**Route:** `/setup/add-keywords`
|
|
||||||
**File:** `pages/Setup/AddKeywords.tsx`
|
|
||||||
|
|
||||||
### Current Functionality
|
|
||||||
- Browse pre-populated seed keywords from global database (admin-imported CSV)
|
|
||||||
- Filter by active site's industry/sector
|
|
||||||
- Bulk select and add keywords to Planner workflow
|
|
||||||
- Tracks which keywords are already added
|
|
||||||
- Filters: Search, Country, Difficulty
|
|
||||||
|
|
||||||
### Important Clarification
|
|
||||||
- **This page:** Browse/select from global seed keyword database only
|
|
||||||
- **Manual keyword entry:** Available in Planner/Keywords page (user's own workflow), NOT here
|
|
||||||
- **Keyword imports:** Admin-only via backend admin panel
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Issues to Address
|
|
||||||
|
|
||||||
| # | Issue | Priority | Action |
|
|
||||||
|---|-------|----------|--------|
|
|
||||||
| 1 | Sector requirement unclear | High | Add tooltip/message explaining why buttons are disabled when no sector is selected |
|
|
||||||
| 2 | No "already added" filter | Medium | Add filter toggle: "Show not-yet-added only" |
|
|
||||||
| 3 | No "Next Step" CTA | High | Add button after keywords added: "Next: Plan Your Content →" linking to Planner |
|
|
||||||
| 4 | No keyword count summary | Medium | Display: "X keywords in your workflow • Y available to add" |
|
|
||||||
| 5 | Import/manual add buttons exist | High | Remove any UI elements for importing or manually adding keywords - this is global DB, read-only for users |
|
|
||||||
| 6 | No Keyword Research indication | Low | Add small teaser text: "Looking for more keywords? Keyword Research coming soon" (user-friendly, non-technical wording) |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Implementation Notes
|
|
||||||
|
|
||||||
**For Issue #1 (Sector requirement):**
|
|
||||||
- When buttons are disabled, show tooltip: "Please select an industry and sector in your Site Settings to browse relevant keywords"
|
|
||||||
- Consider linking directly to Site Settings
|
|
||||||
|
|
||||||
**For Issue #3 (Next Step CTA):**
|
|
||||||
- Button should appear after user has added at least 1 keyword
|
|
||||||
- Route to `/planner/keywords`
|
|
||||||
|
|
||||||
**For Issue #5 (Remove import/add):**
|
|
||||||
- Audit the page for any "Import Keywords" or "Add Custom Keyword" buttons
|
|
||||||
- Remove from UI completely
|
|
||||||
- Keywords only come from admin-imported global database
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2.2 Content Settings
|
|
||||||
|
|
||||||
**Route:** `/account/content-settings`
|
|
||||||
**File:** `pages/account/ContentSettingsPage.tsx`
|
|
||||||
**Tabs:** Content Generation, Publishing, Image Settings
|
|
||||||
|
|
||||||
### Current Functionality
|
|
||||||
- **Content Generation Tab:** Append to prompt, default tone, default length
|
|
||||||
- **Publishing Tab:** Auto-publish toggle, keep updated toggle
|
|
||||||
- **Image Settings Tab:** Quality, style, sizes, format (DALL-E 2/3/Runware)
|
|
||||||
|
|
||||||
### Current State
|
|
||||||
- ⚠️ **Content Generation:** Shows "saved" but does NOT persist (TODO in code)
|
|
||||||
- ⚠️ **Publishing:** Shows "saved" but does NOT persist (no backend API)
|
|
||||||
- ✅ **Image Settings:** Works correctly (has API integration)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Issues to Address
|
|
||||||
|
|
||||||
| # | Issue | Priority | Action |
|
|
||||||
|---|-------|----------|--------|
|
|
||||||
| 1 | Content Generation NOT PERSISTED | 🔴 Critical | Implement backend API endpoint to save Content Generation settings |
|
|
||||||
| 2 | Publishing NOT PERSISTED | 🔴 Critical | Implement backend API endpoint - simple toggle for auto-publish (true/false) |
|
|
||||||
| 3 | False "saved" confirmation | 🔴 Critical | Fix after #1 and #2 - currently misleads users |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Implementation Notes
|
|
||||||
|
|
||||||
**For Issue #1 (Content Generation API):**
|
|
||||||
- Fields to persist: append_to_prompt, default_tone, default_length
|
|
||||||
- Should save at account level (global, not per-site)
|
|
||||||
|
|
||||||
**For Issue #2 (Publishing API):**
|
|
||||||
- Simple boolean toggle: auto_publish (true/false)
|
|
||||||
- When true: content automatically publishes to WordPress after generation
|
|
||||||
- When false: content stays in Review status for manual publishing
|
|
||||||
|
|
||||||
**Not Needed for Launch:**
|
|
||||||
- Per-site content settings
|
|
||||||
- Thinker prompts connection explanation (handled via shortcodes in prompts)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2.3 Sites
|
|
||||||
|
|
||||||
**Route:** `/sites`
|
|
||||||
**Files:** `pages/Sites/List.tsx`, `pages/Sites/SiteSettings.tsx`, `pages/Sites/SiteDashboard.tsx`
|
|
||||||
**Tabs (Site Settings):** General, Integrations, Content Types
|
|
||||||
|
|
||||||
### Current Functionality
|
|
||||||
- List all sites with filtering (search, type, hosting, status)
|
|
||||||
- Create sites via WorkflowGuide (requires industry + sectors)
|
|
||||||
- Activate/deactivate sites
|
|
||||||
- Navigate to site dashboard, content, settings
|
|
||||||
- Settings: Name, URL, SEO, WordPress integration, content type mapping
|
|
||||||
|
|
||||||
### What Sites Module Should Be (Launch Scope)
|
|
||||||
- Connect/manage WordPress sites for content publishing
|
|
||||||
- Configure WordPress integration (API credentials)
|
|
||||||
- Set active site for content workflow
|
|
||||||
- Industry/sector selection (for keyword filtering)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Issues to Address
|
|
||||||
|
|
||||||
#### A. Fix/Improve (From Audit)
|
|
||||||
|
|
||||||
| # | Issue | Priority | Action |
|
|
||||||
|---|-------|----------|--------|
|
|
||||||
| 1 | Dashboard stats are mock data | Medium | Implement real site statistics endpoint OR remove stats display |
|
|
||||||
| 2 | No inline editing | Low | Add inline edit for site name from list view |
|
|
||||||
| 3 | No site cloning | Low | Add "Duplicate Site" action to copy configuration |
|
|
||||||
| 4 | No bulk operations | Low | Add bulk activate/deactivate/delete |
|
|
||||||
| 5 | Complex site creation flow | High | Allow site creation without requiring industry/sector upfront |
|
|
||||||
| 6 | Integration tab default after creation | Medium | Default to General tab, not Integrations (less confusing for non-technical users) |
|
|
||||||
| 7 | No setup progress indicator | High | Add visual checklist showing what's configured vs pending (see below) |
|
|
||||||
|
|
||||||
#### B. Remove (Legacy Site Builder)
|
|
||||||
|
|
||||||
| # | Issue | Priority | Action |
|
|
||||||
|---|-------|----------|--------|
|
|
||||||
| 8 | Site Builder legacy pages | High | Remove all frontend pages/components related to site builder feature |
|
|
||||||
| 9 | WordPress content fetching | High | Remove code that fetches existing content FROM WordPress (only IGNY8-generated content should exist) |
|
|
||||||
| 10 | Duplicate Manage.tsx | High | Delete `pages/Sites/Manage.tsx` - redundant with List.tsx |
|
|
||||||
| 11 | Backend site builder code | High | Remove backend APIs/models related to site builder and external content fetching |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Setup Completion Checklist (New Feature)
|
|
||||||
|
|
||||||
Display this checklist on Site card or Site Dashboard to guide users:
|
|
||||||
|
|
||||||
```
|
|
||||||
Site Setup Progress
|
|
||||||
───────────────────
|
|
||||||
☑ Site created
|
|
||||||
☐ Industry/Sectors selected
|
|
||||||
☐ WordPress integration configured (or skipped)
|
|
||||||
☐ Keywords added
|
|
||||||
☐ Content settings configured
|
|
||||||
|
|
||||||
[Complete Setup →]
|
|
||||||
```
|
|
||||||
|
|
||||||
**Implementation Notes:**
|
|
||||||
- Show on each site card in list view (compact version)
|
|
||||||
- Show expanded on Site Dashboard
|
|
||||||
- Each item links to relevant settings page
|
|
||||||
- "Complete Setup" button goes to first incomplete item
|
|
||||||
- When all complete, show "✓ Ready to create content"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2.4 SETUP Cross-Module Issues
|
|
||||||
|
|
||||||
| # | Issue | Priority | Action |
|
|
||||||
|---|-------|----------|--------|
|
|
||||||
| 1 | No guided flow | High | After completing setup tasks, guide user to start content workflow (link to Planner) |
|
|
||||||
| 2 | Scattered settings | Medium | Document where settings live; consider consolidation in future |
|
|
||||||
| 3 | No onboarding checklist | High | Implement Setup Completion Checklist (see 2.3 above) |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
### Total Issues by Section
|
|
||||||
|
|
||||||
| Section | Critical | High | Medium | Low | Total |
|
|
||||||
|---------|----------|------|--------|-----|-------|
|
|
||||||
| 2.1 Add Keywords | 0 | 3 | 2 | 1 | 6 |
|
|
||||||
| 2.2 Content Settings | 3 | 0 | 0 | 0 | 3 |
|
|
||||||
| 2.3 Sites | 0 | 6 | 2 | 3 | 11 |
|
|
||||||
| 2.4 Cross-Module | 0 | 2 | 1 | 0 | 3 |
|
|
||||||
| **TOTAL** | **3** | **11** | **5** | **4** | **23** |
|
|
||||||
|
|
||||||
### Critical Items (Must Fix)
|
|
||||||
|
|
||||||
1. **Content Settings - Content Generation tab not saving** → Implement backend API
|
|
||||||
2. **Content Settings - Publishing tab not saving** → Implement backend API
|
|
||||||
3. **Content Settings - False "saved" message** → Fix after APIs implemented
|
|
||||||
|
|
||||||
### High Priority Items
|
|
||||||
|
|
||||||
1. Add Keywords - Sector requirement tooltip
|
|
||||||
2. Add Keywords - Next Step CTA to Planner
|
|
||||||
3. Add Keywords - Remove import/manual add buttons
|
|
||||||
4. Sites - Allow simpler site creation flow
|
|
||||||
5. Sites - Add Setup Completion Checklist
|
|
||||||
6. Sites - Remove Site Builder legacy code (frontend)
|
|
||||||
7. Sites - Remove WordPress content fetching code
|
|
||||||
8. Sites - Delete duplicate Manage.tsx
|
|
||||||
9. Sites - Remove Site Builder backend code
|
|
||||||
10. Cross-Module - Guided flow after setup
|
|
||||||
11. Cross-Module - Onboarding checklist implementation
|
|
||||||
|
|
||||||
### Files to Delete
|
|
||||||
|
|
||||||
| File | Reason |
|
|
||||||
|------|--------|
|
|
||||||
| `pages/Sites/Manage.tsx` | Duplicate of List.tsx |
|
|
||||||
| Site Builder related pages | Legacy feature removed |
|
|
||||||
| Site Builder related components | Legacy feature removed |
|
|
||||||
|
|
||||||
### Files to Modify
|
|
||||||
|
|
||||||
| File | Changes |
|
|
||||||
|------|---------|
|
|
||||||
| `pages/Setup/AddKeywords.tsx` | Add tooltip, filter, CTA, count summary, remove import buttons, add teaser |
|
|
||||||
| `pages/account/ContentSettingsPage.tsx` | Connect to new backend APIs |
|
|
||||||
| `pages/Sites/List.tsx` | Add setup checklist, inline edit, bulk operations |
|
|
||||||
| `pages/Sites/SiteSettings.tsx` | Default to General tab |
|
|
||||||
| `pages/Sites/SiteDashboard.tsx` | Fix mock stats, add setup checklist |
|
|
||||||
|
|
||||||
### Backend Work Required
|
|
||||||
|
|
||||||
| Area | Work |
|
|
||||||
|------|------|
|
|
||||||
| Content Settings API | Create endpoints for Content Generation and Publishing settings |
|
|
||||||
| Site Statistics API | Implement real stats OR remove from frontend |
|
|
||||||
| Cleanup | Remove Site Builder and content fetching APIs/models |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Status after implementation
|
|
||||||
|
|
||||||
|
|
||||||
## Summary of Section 2 Implementation
|
|
||||||
|
|
||||||
### 2.1 Add Keywords (IndustriesSectorsKeywords.tsx)
|
|
||||||
- ✅ Added `showNotAddedOnly` filter state with "Not Yet Added Only" filter option
|
|
||||||
- ✅ Added `addedCount` and `availableCount` state variables for keyword count tracking
|
|
||||||
- ✅ Added keyword count summary showing "X keywords in your workflow • Y available to add"
|
|
||||||
- ✅ Added "Next: Plan Your Content →" CTA button that appears when keywords are added
|
|
||||||
- ✅ Added "Looking for more keywords? Keyword Research coming soon!" teaser text
|
|
||||||
- ✅ Sector requirement tooltip already existed - no changes needed
|
|
||||||
- ✅ No visible import buttons to remove (dead code existed but was not exposed)
|
|
||||||
|
|
||||||
### 2.2 Content Settings (ContentSettingsPage.tsx)
|
|
||||||
- ✅ Created new backend API endpoint `/v1/system/settings/content/<pk>/` for content_generation and publishing
|
|
||||||
- ✅ Added `ContentSettingsViewSet` to backend with retrieve/update/save actions
|
|
||||||
- ✅ Updated frontend to load content_generation and publishing settings from API
|
|
||||||
- ✅ Updated frontend to save content_generation settings (append_to_prompt, default_tone, default_length)
|
|
||||||
- ✅ Updated frontend to save publishing settings (auto_publish_enabled, auto_sync_enabled)
|
|
||||||
- ✅ Removed TODO comments - settings now actually persist
|
|
||||||
|
|
||||||
### 2.3 Sites
|
|
||||||
- ✅ Created `SiteSetupChecklist` component showing setup progress with checklist
|
|
||||||
- ✅ Updated Dashboard.tsx to use the new checklist component
|
|
||||||
- ✅ Removed mock stats from Dashboard (were showing all zeros)
|
|
||||||
- ✅ Deleted Manage.tsx (redundant duplicate of List.tsx)
|
|
||||||
- ✅ Removed empty `Builder/` folder structure
|
|
||||||
- ✅ Removed routes to deleted pages in App.tsx
|
|
||||||
- ✅ Site Settings already defaults to "general" tab - no changes needed
|
|
||||||
|
|
||||||
### Files Modified
|
|
||||||
1. IndustriesSectorsKeywords.tsx
|
|
||||||
2. ContentSettingsPage.tsx
|
|
||||||
3. settings_views.py
|
|
||||||
4. urls.py
|
|
||||||
5. Dashboard.tsx
|
|
||||||
6. App.tsx
|
|
||||||
|
|
||||||
### Files Created
|
|
||||||
1. SiteSetupChecklist.tsx
|
|
||||||
|
|
||||||
### Files Deleted
|
|
||||||
1. Manage.tsx
|
|
||||||
2. `frontend/src/pages/Sites/Builder/` (empty folder)
|
|
||||||
|
|
||||||
@@ -1,351 +0,0 @@
|
|||||||
# Section 3: WORKFLOW Modules - Audit & Action Plan
|
|
||||||
|
|
||||||
**Date:** December 27, 2025
|
|
||||||
**Status:** Finalized for Implementation
|
|
||||||
**Scope:** Planner, Writer, Automation (Linker & Optimizer excluded - not active modules)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3.1 Planner
|
|
||||||
|
|
||||||
**Route:** `/planner/keywords`
|
|
||||||
**Files:** `pages/Planner/Keywords.tsx`, `pages/Planner/Clusters.tsx`, `pages/Planner/ClusterView.tsx`, `pages/Planner/Ideas.tsx`, `pages/Planner/KeywordOpportunities.tsx`
|
|
||||||
**Tabs:** Keywords, Clusters, Ideas
|
|
||||||
|
|
||||||
### Current Functionality
|
|
||||||
- **Keywords:** CRUD, bulk status updates, auto-cluster AI, filters
|
|
||||||
- **Clusters:** CRUD, bulk operations, auto-generate ideas AI
|
|
||||||
- **Ideas:** CRUD, bulk queue to writer, filters
|
|
||||||
- **Flow:** Keywords → Auto-Cluster → Clusters → Auto-Generate Ideas → Ideas → Queue to Writer
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Issues to Address
|
|
||||||
|
|
||||||
| # | Issue | Priority | Action |
|
|
||||||
|---|-------|----------|--------|
|
|
||||||
| 1 | KeywordOpportunities page exists but orphaned | High | **DELETE** - Remove `pages/Planner/KeywordOpportunities.tsx` and all references to it. Add Keywords page is the source of truth for seed keywords |
|
|
||||||
| 2 | No "Add to Existing Cluster" | Medium | Add option to assign keywords to existing clusters (not just create new) |
|
|
||||||
| 3 | No cluster progress indicator | High | Show which clusters already have ideas generated (badge/indicator) |
|
|
||||||
| 4 | Ideas missing queued count | Medium | Add indicator showing how many ideas are pending vs processed |
|
|
||||||
| 5 | Cluster → Ideas transition unclear | Medium | Make it clear which clusters need ideas generated |
|
|
||||||
| 6 | No return path from Ideas to source cluster | Low | Make cluster name clickable on Ideas page to navigate back |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Issues NOT Being Addressed (Per Discussion)
|
|
||||||
|
|
||||||
| Issue | Reason |
|
|
||||||
|-------|--------|
|
|
||||||
| No cluster merge/split | Risk of breaking functional workflow, complex implementation |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Implementation Notes
|
|
||||||
|
|
||||||
**For Issue #1 (Remove KeywordOpportunities):**
|
|
||||||
- Delete file: `pages/Planner/KeywordOpportunities.tsx`
|
|
||||||
- Remove route from App.tsx or router config
|
|
||||||
- Remove any navigation links to `/planner/keyword-opportunities`
|
|
||||||
- Remove from sidebar if present
|
|
||||||
- The Add Keywords page (`/setup/add-keywords`) is the active workflow item for seed keywords
|
|
||||||
|
|
||||||
**For Issue #3 (Cluster progress indicator):**
|
|
||||||
- On Clusters table, show badge: "X ideas" or "No ideas yet"
|
|
||||||
- Visual distinction between clusters with/without ideas
|
|
||||||
- Consider color coding or icon
|
|
||||||
|
|
||||||
**For Issue #5 (Cluster → Ideas transition):**
|
|
||||||
- Add "Generate Ideas" button prominently on clusters without ideas
|
|
||||||
- Filter option: "Show clusters without ideas"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3.2 Writer
|
|
||||||
|
|
||||||
**Route:** `/writer/tasks`
|
|
||||||
**Files:** `pages/Writer/Tasks.tsx`, `pages/Writer/Drafts.tsx`, `pages/Writer/ContentView.tsx`, `pages/Writer/Images.tsx`, `pages/Writer/Review.tsx`, `pages/Writer/Published.tsx`
|
|
||||||
**Tabs:** Queue, Drafts, Images, Review, Published
|
|
||||||
|
|
||||||
### Current Functionality
|
|
||||||
- **Tasks (Queue):** CRUD, generate content (row action only), generate images bulk
|
|
||||||
- **Drafts:** List drafts, view details, status updates
|
|
||||||
- **Images:** Grouped by content, image generation
|
|
||||||
- **Review:** Status=review filter, publish to WordPress
|
|
||||||
- **Published:** Status=published, WordPress sync status
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Issues to Address
|
|
||||||
|
|
||||||
| # | Issue | Priority | Action |
|
|
||||||
|---|-------|----------|--------|
|
|
||||||
| 1 | Status progression confusion | High | Streamline Draft → Review → Published flow - should not require navigating different pages for status changes |
|
|
||||||
| 2 | Images detached from content workflow | High | Integrate images into content workflow - show/manage images within content view |
|
|
||||||
| 3 | ContentView shows tags and categories twice | High | Fix template to display tags and categories only once |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Issues NOT Being Addressed (Per Discussion)
|
|
||||||
|
|
||||||
| Issue | Reason |
|
|
||||||
|-------|--------|
|
|
||||||
| No bulk content generation | Not an issue per current workflow |
|
|
||||||
| No content editing | Not an issue per current workflow |
|
|
||||||
| No manual task creation | Not an issue per current workflow |
|
|
||||||
| No content regeneration | Not an issue per current workflow |
|
|
||||||
| Review → Published manual only | Not an issue per current workflow |
|
|
||||||
| ContentView missing actions bar | Not an issue per current workflow |
|
|
||||||
| No send_to_linker action | Linker not active module |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Implementation Notes
|
|
||||||
|
|
||||||
**For Issue #1 (Status progression):**
|
|
||||||
- Allow status changes from any tab/view without forcing navigation
|
|
||||||
- Consider unified content list with status filter instead of separate pages
|
|
||||||
- Or add status change dropdown/buttons within each view
|
|
||||||
|
|
||||||
**For Issue #2 (Images integration):**
|
|
||||||
- Show image thumbnails within ContentView
|
|
||||||
- Allow image generation from ContentView
|
|
||||||
- Show image count on content list items
|
|
||||||
|
|
||||||
**For Issue #3 (Duplicate tags/categories):**
|
|
||||||
- Audit ContentView.tsx template
|
|
||||||
- Find and remove duplicate rendering of tags and categories
|
|
||||||
- Should display once in appropriate section
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3.3 Automation
|
|
||||||
|
|
||||||
**Route:** `/automation`
|
|
||||||
**Files:** `pages/Automation/AutomationPage.tsx` (or Dashboard.tsx)
|
|
||||||
**Tabs:** None (single page)
|
|
||||||
|
|
||||||
### Current Functionality
|
|
||||||
- Pipeline overview (7 stages: Keywords → Clusters → Ideas → Tasks → Content → Image Prompts → Images)
|
|
||||||
- Schedule configuration (frequency, time, enable/disable)
|
|
||||||
- Run controls (Run Now, Pause, Resume)
|
|
||||||
- Real-time progress polling
|
|
||||||
- Metrics display and activity log
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Issues to Address
|
|
||||||
|
|
||||||
| # | Issue | Priority | Action |
|
|
||||||
|---|-------|----------|--------|
|
|
||||||
| 1 | No stage-by-stage control | Medium | Add toggles to enable/disable individual pipeline stages |
|
|
||||||
| 2 | No review gate config | Low | Add UI to configure review gate rules (Stage 7) |
|
|
||||||
| 3 | No error recovery | High | Add retry capability for failed items (per-item or per-stage) |
|
|
||||||
| 4 | No batch size config | Medium | Add setting to throttle items processed per run |
|
|
||||||
| 5 | No dry run/preview | Medium | Add preview mode to show what WOULD be processed before running |
|
|
||||||
| 6 | Activity log not filterable | Medium | Add filters: by stage, status, date |
|
|
||||||
| 7 | Credit estimation unclear | High | Clarify labeling - consistent terminology (credits vs content pieces) |
|
|
||||||
| 8 | Run history depth unknown | Low | Add pagination to run history |
|
|
||||||
| 9 | No indication of manual vs automated | Low | Show source indicator for processed items |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Implementation Notes
|
|
||||||
|
|
||||||
**Critical Constraint:** All changes must NOT affect the actual AI functions that run on module pages. Automation uses the same functions - only UI/control changes, not function logic.
|
|
||||||
|
|
||||||
**For Issue #1 (Stage toggles):**
|
|
||||||
- Add on/off toggle for each of the 7 stages
|
|
||||||
- When stage is off, automation skips it
|
|
||||||
- Visual indicator showing which stages are active
|
|
||||||
|
|
||||||
**For Issue #3 (Error recovery):**
|
|
||||||
- Show failed items in activity log with "Retry" button
|
|
||||||
- Option to retry all failed items from a run
|
|
||||||
- Clear error messages explaining what failed
|
|
||||||
|
|
||||||
**For Issue #5 (Dry run/preview):**
|
|
||||||
- "Preview Run" button shows list of items that would be processed
|
|
||||||
- Shows count per stage
|
|
||||||
- User can then confirm or cancel
|
|
||||||
|
|
||||||
**For Issue #7 (Credit estimation):**
|
|
||||||
- Use consistent terminology matching the pricing simplification plan
|
|
||||||
- Show estimated cost before running
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3.4 Linker
|
|
||||||
|
|
||||||
**Status:** ❌ NOT ACTIVE MODULE - Skipped
|
|
||||||
|
|
||||||
Not part of current phase. No issues to address.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3.5 Optimizer
|
|
||||||
|
|
||||||
**Status:** ❌ NOT ACTIVE MODULE - Skipped
|
|
||||||
|
|
||||||
Not part of current phase. No issues to address.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3.6 WORKFLOW Cross-Module Issues
|
|
||||||
|
|
||||||
### Issues to Address
|
|
||||||
|
|
||||||
| # | Issue | Priority | Action |
|
|
||||||
|---|-------|----------|--------|
|
|
||||||
| 1 | No Planner → Writer visibility | Medium | After queuing ideas to writer, provide clear feedback and link to Writer |
|
|
||||||
| 2 | No cross-module notifications | High | Log all AI runs in notification dropdown (bell icon) with correct end results |
|
|
||||||
| 3 | Progress modals have wrong texts | High | Fix placeholder text, wrong wording, inaccurate counts (showing "X" or placeholders) |
|
|
||||||
| 4 | Progress modal counts inaccurate | High | Ensure counts reflect actual items being processed |
|
|
||||||
| 5 | No breadcrumb navigation | Medium | Add breadcrumbs showing workflow path (Cluster → Idea → Task → Content) |
|
|
||||||
| 6 | No "Next Step" suggestions | Medium | After each action, suggest what to do next |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Issues NOT Being Addressed (Per Discussion)
|
|
||||||
|
|
||||||
| Issue | Reason |
|
|
||||||
|-------|--------|
|
|
||||||
| No Writer → Linker integration | Linker not active module |
|
|
||||||
| No Writer → Optimizer integration | Optimizer not active module |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Implementation Notes
|
|
||||||
|
|
||||||
**For Issue #2 (Notifications):**
|
|
||||||
- Bell icon dropdown should show log of all AI function runs
|
|
||||||
- Each entry shows: function type, status (success/failed/in-progress), timestamp
|
|
||||||
- Include runs from: Clustering, Idea Generation, Content Generation, Image Generation
|
|
||||||
- Show result: "Generated 5 ideas from Cluster X" or "Failed: insufficient credits"
|
|
||||||
- Link to relevant content/page
|
|
||||||
|
|
||||||
**For Issues #3 & #4 (Progress modals):**
|
|
||||||
- Audit all progress modals across modules
|
|
||||||
- Replace placeholder text ("X", "processing...", wrong labels)
|
|
||||||
- Ensure counts match actual items:
|
|
||||||
- "Processing 5 of 12 keywords" (not "Processing X of Y")
|
|
||||||
- "Generated 3 ideas" (actual count, not placeholder)
|
|
||||||
- Match text to actual AI function being performed
|
|
||||||
- Consistent terminology across all modals
|
|
||||||
|
|
||||||
**Progress Modals to Audit:**
|
|
||||||
- Keyword clustering modal
|
|
||||||
- Idea generation modal
|
|
||||||
- Content generation modal
|
|
||||||
- Image prompt extraction modal
|
|
||||||
- Image generation modal
|
|
||||||
- Any bulk operation modals
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
### Total Issues by Section
|
|
||||||
|
|
||||||
| Section | High | Medium | Low | Total |
|
|
||||||
|---------|------|--------|-----|-------|
|
|
||||||
| 3.1 Planner | 2 | 3 | 1 | 6 |
|
|
||||||
| 3.2 Writer | 3 | 0 | 0 | 3 |
|
|
||||||
| 3.3 Automation | 2 | 5 | 2 | 9 |
|
|
||||||
| 3.4 Linker | - | - | - | Skipped |
|
|
||||||
| 3.5 Optimizer | - | - | - | Skipped |
|
|
||||||
| 3.6 Cross-Module | 2 | 4 | 0 | 6 |
|
|
||||||
| **TOTAL** | **9** | **12** | **3** | **24** |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### High Priority Items
|
|
||||||
|
|
||||||
1. **Planner** - Delete KeywordOpportunities page and all references
|
|
||||||
2. **Planner** - Add cluster progress indicator (which have ideas)
|
|
||||||
3. **Writer** - Fix status progression confusion
|
|
||||||
4. **Writer** - Integrate images into content workflow
|
|
||||||
5. **Writer** - Fix duplicate tags/categories in ContentView
|
|
||||||
6. **Automation** - Add error recovery/retry for failed items
|
|
||||||
7. **Automation** - Clarify credit/content terminology
|
|
||||||
8. **Cross-Module** - Fix progress modal texts and counts
|
|
||||||
9. **Cross-Module** - Implement notification logging for AI runs
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Files to Delete
|
|
||||||
|
|
||||||
| File | Reason |
|
|
||||||
|------|--------|
|
|
||||||
| `pages/Planner/KeywordOpportunities.tsx` | Orphaned page, Add Keywords is source of truth |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Files to Modify
|
|
||||||
|
|
||||||
| File | Changes |
|
|
||||||
|------|---------|
|
|
||||||
| `pages/Planner/Keywords.tsx` | Remove any KeywordOpportunities references |
|
|
||||||
| `pages/Planner/Clusters.tsx` | Add ideas count badge, "Generate Ideas" prominence |
|
|
||||||
| `pages/Planner/Ideas.tsx` | Add queued count indicator, clickable cluster name |
|
|
||||||
| `pages/Writer/Tasks.tsx` | Streamline status changes |
|
|
||||||
| `pages/Writer/Drafts.tsx` | Streamline status changes |
|
|
||||||
| `pages/Writer/ContentView.tsx` | Fix duplicate tags/categories, integrate images |
|
|
||||||
| `pages/Writer/Images.tsx` | Better integration with content workflow |
|
|
||||||
| `pages/Writer/Review.tsx` | Streamline status changes |
|
|
||||||
| `pages/Automation/AutomationPage.tsx` | Stage toggles, batch size, preview, filters, error retry |
|
|
||||||
| All progress modal components | Fix placeholder text, counts, wording |
|
|
||||||
| Notification dropdown component | Add AI run logging |
|
|
||||||
| Router/App.tsx | Remove KeywordOpportunities route |
|
|
||||||
| Sidebar component | Remove KeywordOpportunities link if present |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Backend Work Required
|
|
||||||
|
|
||||||
| Area | Work |
|
|
||||||
|------|------|
|
|
||||||
| Automation stage control | API to save stage enable/disable preferences |
|
|
||||||
| Automation batch size | API to save batch size setting |
|
|
||||||
| Error recovery | API to retry failed items |
|
|
||||||
| Notification logging | Ensure AI runs are logged for notification display |
|
|
||||||
|
|
||||||
---
|
|
||||||
## After Implementation
|
|
||||||
Section 3 implementation is complete. Here's a summary of all changes made:
|
|
||||||
|
|
||||||
## Section 3 WORKFLOW Modules - Implementation Complete ✅
|
|
||||||
|
|
||||||
### Completed Tasks:
|
|
||||||
|
|
||||||
1. **Delete KeywordOpportunities.tsx** ✅
|
|
||||||
- Deleted the orphaned page file
|
|
||||||
- Removed import and route from App.tsx
|
|
||||||
- Updated PAGES.md documentation
|
|
||||||
|
|
||||||
2. **Add cluster ideas badge** ✅
|
|
||||||
- Modified clusters.config.tsx
|
|
||||||
- Ideas column now shows badge: "X ideas" (green) or "No ideas" (gray)
|
|
||||||
|
|
||||||
3. **Fix ContentView duplicate tags/categories** ✅
|
|
||||||
- Modified ContentViewTemplate.tsx
|
|
||||||
- Removed duplicate tags/categories section that appeared below metadata
|
|
||||||
|
|
||||||
4. **Fix progress modal placeholder texts** ✅
|
|
||||||
- Modified ProgressModal.tsx
|
|
||||||
- Fixed "X" placeholders in step labels with cleaner fallbacks
|
|
||||||
- "Mapping Content for X Image Prompts" → "Mapping content for image prompts"
|
|
||||||
- "Writing X In‑article Image Prompts" → "Writing In‑article Image Prompts"
|
|
||||||
- Success message fallback cleaned up
|
|
||||||
|
|
||||||
5. **Add queued count to Ideas** ✅
|
|
||||||
- Already implemented via headerMetrics showing New/Queued/Completed counts
|
|
||||||
|
|
||||||
6. **Clickable cluster in Ideas** ✅
|
|
||||||
- Modified ideas.config.tsx
|
|
||||||
- Cluster name now links to `/planner/clusters/:id`
|
|
||||||
|
|
||||||
### Documentation Updated:
|
|
||||||
- CHANGELOG.md - Added v1.1.5 section
|
|
||||||
- ENDPOINTS.md - Added Content Settings API docs
|
|
||||||
- PAGES.md - Removed KeywordOpportunities, updated version
|
|
||||||
@@ -1,397 +0,0 @@
|
|||||||
# Section 4: ACCOUNT Modules - Audit & Action Plan
|
|
||||||
|
|
||||||
**Date:** December 27, 2025
|
|
||||||
**Status:** Finalized for Implementation
|
|
||||||
**Scope:** Account Settings, Plans & Billing, Usage (AI Models excluded - admin only)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4.1 Account Settings
|
|
||||||
|
|
||||||
**Route:** `/account/settings`
|
|
||||||
**File:** `pages/account/AccountSettingsPage.tsx`
|
|
||||||
**Tabs:** Account, Profile, Team
|
|
||||||
|
|
||||||
### Current Functionality
|
|
||||||
- **Account Tab:** Organization name, billing email, full billing address, tax ID/VAT
|
|
||||||
- **Profile Tab:** First/last name, email, phone, timezone, language, notifications, security
|
|
||||||
- **Team Tab:** List team members, invite via email, remove members, role display
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Issues to Address
|
|
||||||
|
|
||||||
| # | Issue | Priority | Action |
|
|
||||||
|---|-------|----------|--------|
|
|
||||||
| 1 | Profile NOT connected to API | 🔴 Critical | Study existing backend - if profile API exists and is consistent with system, connect it. If not present, create consistent with existing API structure |
|
|
||||||
| 2 | Change Password does nothing | 🔴 Critical | Implement password change functionality |
|
|
||||||
| 3 | No role assignment on invite | High | Add role dropdown (Admin/Member) to invitation form |
|
|
||||||
| 4 | No role editing for members | High | Add ability to change member role after invitation |
|
|
||||||
| 5 | No email verification | High | Implement email verification flow when email is changed |
|
|
||||||
| 6 | Orphaned TeamManagement.tsx | High | Delete `pages/account/TeamManagement.tsx` - functionality exists in AccountSettingsPage |
|
|
||||||
| 7 | No 2FA option | Medium | Add two-factor authentication option in security section |
|
|
||||||
| 8 | No account deletion | Medium | Add account closure/deletion capability |
|
|
||||||
| 9 | No session management | Medium | Add view/revoke active sessions capability |
|
|
||||||
| 10 | No pending invitation management | Medium | Add ability to resend or cancel pending invitations |
|
|
||||||
| 11 | No team member limit display | Medium | Show "X of Y team members" based on plan limit |
|
|
||||||
| 12 | Inconsistent role system | Medium | Backend returns `is_admin` boolean but UI shows Admin/Member - align these |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Implementation Notes
|
|
||||||
|
|
||||||
**For Issue #1 (Profile API):**
|
|
||||||
- First: Audit backend to check if profile endpoint exists
|
|
||||||
- If exists: Study implementation, verify consistency with other APIs, then connect frontend
|
|
||||||
- If not exists: Create new endpoint following existing API patterns in the codebase
|
|
||||||
- Fields to persist: first_name, last_name, email, phone, timezone, language, notification preferences
|
|
||||||
|
|
||||||
**For Issue #2 (Password change):**
|
|
||||||
- Implement secure password change requiring current password
|
|
||||||
- Validate new password meets requirements
|
|
||||||
- Consider session invalidation after password change
|
|
||||||
|
|
||||||
**For Issue #12 (Role consistency):**
|
|
||||||
- Decide on role system: boolean `is_admin` or role enum (admin/member/viewer)
|
|
||||||
- Align frontend display with backend data structure
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4.2 Plans & Billing
|
|
||||||
|
|
||||||
**Route:** `/account/plans`
|
|
||||||
**Files:** `pages/account/PlansAndBillingPage.tsx`, `pages/Billing/CreditPurchase.tsx`
|
|
||||||
**Tabs:** Current Plan, Upgrade Plan, History
|
|
||||||
|
|
||||||
### Current Functionality
|
|
||||||
- **Current Plan:** Plan name, status, credits, balance, renewal date, features
|
|
||||||
- **Upgrade:** Pricing table, plan comparison, change policy
|
|
||||||
- **History:** Invoices with PDF download, payments, payment methods
|
|
||||||
|
|
||||||
### Payment Context
|
|
||||||
Currently using manual payment methods only (bank transfer, wallet). No automatic payment processing.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Issues to Address
|
|
||||||
|
|
||||||
| # | Issue | Priority | Action |
|
|
||||||
|---|-------|----------|--------|
|
|
||||||
| 1 | No proration preview | High | Show prorated amount before plan upgrade/downgrade |
|
|
||||||
| 2 | Credit purchase not linked | Medium | Link to credit purchase from Plans & Billing page |
|
|
||||||
| 3 | Cancellation is immediate | High | Add confirmation dialog before plan cancellation |
|
|
||||||
| 4 | No downgrade proration display | Medium | Show calculation when downgrading plan |
|
|
||||||
| 5 | Throttling errors surface to users | Medium | Replace raw throttling messages with user-friendly spinner/message |
|
|
||||||
| 6 | No billing cycle visualization | Medium | Make renewal date prominent, show billing cycle clearly |
|
|
||||||
| 7 | No cancellation reason collection | Low | Add optional reason selection when cancelling |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Issues NOT Being Addressed (Per Discussion)
|
|
||||||
|
|
||||||
| Issue | Reason |
|
|
||||||
|-------|--------|
|
|
||||||
| No payment failure retry | Manual payment only - no auto-retry needed |
|
|
||||||
| Payment method UI incomplete | Manual payment only - limited methods by design |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Implementation Notes
|
|
||||||
|
|
||||||
**For Issue #1 (Proration preview):**
|
|
||||||
- Before confirming plan change, show:
|
|
||||||
- Current plan remaining value
|
|
||||||
- New plan cost
|
|
||||||
- Prorated amount due/credited
|
|
||||||
- Calculate based on days remaining in billing cycle
|
|
||||||
|
|
||||||
**For Issue #3 (Cancellation confirmation):**
|
|
||||||
- Modal dialog: "Are you sure you want to cancel?"
|
|
||||||
- Show what they'll lose (features, remaining credits)
|
|
||||||
- Require explicit confirmation
|
|
||||||
|
|
||||||
**For Issue #5 (Throttling messages):**
|
|
||||||
- Intercept throttling errors
|
|
||||||
- Show spinner with "Processing your request..." instead of technical error
|
|
||||||
- Implement proper retry logic behind the scenes
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4.3 Usage
|
|
||||||
|
|
||||||
**Route:** `/account/usage`
|
|
||||||
**Files:** `pages/account/UsageAnalyticsPage.tsx`, `pages/account/UsageLimits.tsx`, `pages/account/CreditActivity.tsx`
|
|
||||||
**Tabs:** Your Limits & Usage, Credit History, API Activity
|
|
||||||
|
|
||||||
### Current Functionality
|
|
||||||
- **Quick Stats:** Credits left, used this month, monthly limit, usage %
|
|
||||||
- **Limits:** Hard limits (sites, users, keywords, clusters) + Monthly limits
|
|
||||||
- **Credit History:** Transaction log with type, amount, description
|
|
||||||
- **API Activity:** Call statistics, endpoint breakdown
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Issues to Address
|
|
||||||
|
|
||||||
| # | Issue | Priority | Action |
|
|
||||||
|---|-------|----------|--------|
|
|
||||||
| 1 | API Activity is HARDCODED | 🔴 Critical | Implement real API activity tracking - replace fake values (1,234, 567, 342) |
|
|
||||||
| 2 | Success rate is fake | 🔴 Critical | Calculate and display real success rate from actual data |
|
|
||||||
| 3 | No usage alerts | High | Implement default alerts at usage thresholds (80%, 90%, 100%) - sent to all users automatically |
|
|
||||||
| 4 | No per-site usage | High | Add breakdown showing which site consumed what |
|
|
||||||
| 5 | No usage forecasting | Medium | Add "At current rate, you'll reach limit in X days" |
|
|
||||||
| 6 | No actionable insights | Medium | Suggest upgrade when approaching limits |
|
|
||||||
| 7 | Credit history lacks context | Medium | Add links from credit transactions to related content/operations |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Issues NOT Being Addressed (Per Discussion)
|
|
||||||
|
|
||||||
| Issue | Reason |
|
|
||||||
|-------|--------|
|
|
||||||
| No per-user usage | Not needed for current phase |
|
|
||||||
| No usage export | Not needed for current phase |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Implementation Notes
|
|
||||||
|
|
||||||
**For Issue #1 & #2 (Real API Activity):**
|
|
||||||
- Backend needs to log API calls (may already exist)
|
|
||||||
- Track: endpoint, timestamp, status (success/fail), response time
|
|
||||||
- Aggregate for display: total calls, success rate, calls by endpoint
|
|
||||||
- Replace hardcoded values with real calculated data
|
|
||||||
|
|
||||||
**For Issue #3 (Usage alerts):**
|
|
||||||
- Default behavior: all users receive alerts
|
|
||||||
- Trigger points: 80%, 90%, 100% of limits
|
|
||||||
- Delivery: in-app notification + email
|
|
||||||
- No user preferences needed - alerts go to everyone
|
|
||||||
|
|
||||||
**For Issue #4 (Per-site usage):**
|
|
||||||
- Break down credit usage by site
|
|
||||||
- Show: "Site A: 450 credits, Site B: 230 credits"
|
|
||||||
- Pie chart or table visualization
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4.4 AI Models (Admin Only)
|
|
||||||
|
|
||||||
**Status:** ❌ SKIP ENTIRELY
|
|
||||||
|
|
||||||
Not part of user-facing modules. Admin only - no changes needed.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4.5 ACCOUNT Cross-Module Issues (MAJOR)
|
|
||||||
|
|
||||||
These are architectural issues requiring proper analysis and solutions.
|
|
||||||
|
|
||||||
### Issues to Address
|
|
||||||
|
|
||||||
| # | Issue | Priority | Action |
|
|
||||||
|---|-------|----------|--------|
|
|
||||||
| 1 | Multiple credit balance sources | 🔴 Critical | Establish ONE source of truth for credit balance. Analyze: Plans page, Usage page, billingStore - determine which is authoritative, remove others, refactor all references |
|
|
||||||
| 2 | Fragmented billing pages | High | **AI Agent Task:** Audit system to identify all billing-related pages/functions, find duplicates/redundancies, propose consolidation solution |
|
|
||||||
| 3 | Legacy routes still exist | High | Remove legacy routes (`/billing/overview`, `/team`, `/profile`), remove redirect code, refactor any references throughout codebase |
|
|
||||||
| 4 | No notification preferences | Low | Not needed - default alerts go to all users |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Implementation Notes
|
|
||||||
|
|
||||||
**For Issue #1 (Single source of truth for balance):**
|
|
||||||
|
|
||||||
*Phase 1: Analysis*
|
|
||||||
- Identify all places that fetch/display credit balance:
|
|
||||||
- `billingStore.ts` (Zustand store)
|
|
||||||
- Plans & Billing page
|
|
||||||
- Usage page
|
|
||||||
- Dashboard (if applicable)
|
|
||||||
- Header component (if showing balance)
|
|
||||||
- Document how each fetches data (API endpoint, frequency)
|
|
||||||
|
|
||||||
*Phase 2: Decision*
|
|
||||||
- Determine which should be THE source:
|
|
||||||
- Likely `billingStore` as central state management
|
|
||||||
- Single API endpoint for balance data
|
|
||||||
- All components should read from this one source
|
|
||||||
|
|
||||||
*Phase 3: Implementation*
|
|
||||||
- Refactor all components to use single source
|
|
||||||
- Remove duplicate API calls
|
|
||||||
- Remove duplicate state management
|
|
||||||
- Ensure consistency across all views
|
|
||||||
|
|
||||||
**For Issue #2 (Fragmented billing pages):**
|
|
||||||
|
|
||||||
*AI Agent Audit Task:*
|
|
||||||
```
|
|
||||||
TASK: Billing Pages Consolidation Audit
|
|
||||||
|
|
||||||
1. DISCOVER all billing-related files:
|
|
||||||
- pages/account/PlansAndBillingPage.tsx
|
|
||||||
- pages/Billing/CreditPurchase.tsx
|
|
||||||
- pages/Billing/Credits.tsx (if exists)
|
|
||||||
- pages/Settings/CreditsAndBilling.tsx (if exists)
|
|
||||||
- Any other billing-related pages
|
|
||||||
|
|
||||||
2. ANALYZE each page:
|
|
||||||
- What functionality does it provide?
|
|
||||||
- What routes point to it?
|
|
||||||
- Is it actively used or orphaned?
|
|
||||||
- Does it duplicate functionality from another page?
|
|
||||||
|
|
||||||
3. IDENTIFY redundancies:
|
|
||||||
- Same functionality in multiple places
|
|
||||||
- Overlapping features
|
|
||||||
- Dead/orphaned pages
|
|
||||||
|
|
||||||
4. PROPOSE solution:
|
|
||||||
- Which pages to keep
|
|
||||||
- Which pages to merge
|
|
||||||
- Which pages to delete
|
|
||||||
- Final consolidated structure
|
|
||||||
|
|
||||||
5. DOCUMENT migration path:
|
|
||||||
- What routes need updating
|
|
||||||
- What references need changing
|
|
||||||
- What imports need refactoring
|
|
||||||
```
|
|
||||||
|
|
||||||
**For Issue #3 (Legacy routes removal):**
|
|
||||||
|
|
||||||
*Routes to remove:*
|
|
||||||
- `/billing/overview`
|
|
||||||
- `/team`
|
|
||||||
- `/profile`
|
|
||||||
|
|
||||||
*Process:*
|
|
||||||
1. Find route definitions in router/App.tsx
|
|
||||||
2. Remove route entries
|
|
||||||
3. Find and remove redirect logic
|
|
||||||
4. Search codebase for any links to these routes
|
|
||||||
5. Update or remove those links
|
|
||||||
6. Delete any orphaned components only used by these routes
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
### Total Issues by Section
|
|
||||||
|
|
||||||
| Section | Critical | High | Medium | Low | Total |
|
|
||||||
|---------|----------|------|--------|-----|-------|
|
|
||||||
| 4.1 Account Settings | 2 | 4 | 6 | 0 | 12 |
|
|
||||||
| 4.2 Plans & Billing | 0 | 2 | 4 | 1 | 7 |
|
|
||||||
| 4.3 Usage | 2 | 2 | 3 | 0 | 7 |
|
|
||||||
| 4.4 AI Models | - | - | - | - | Skipped |
|
|
||||||
| 4.5 Cross-Module | 1 | 2 | 0 | 1 | 4 |
|
|
||||||
| **TOTAL** | **5** | **10** | **13** | **2** | **30** |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Critical Items (Must Fix)
|
|
||||||
|
|
||||||
1. **Account Settings** - Profile tab not connected to API
|
|
||||||
2. **Account Settings** - Password change does nothing
|
|
||||||
3. **Usage** - API Activity tab shows hardcoded fake data
|
|
||||||
4. **Usage** - Success rate is fake (98.5%)
|
|
||||||
5. **Cross-Module** - Multiple credit balance sources causing inconsistency
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### High Priority Items
|
|
||||||
|
|
||||||
1. Account Settings - Role assignment on invite
|
|
||||||
2. Account Settings - Role editing for members
|
|
||||||
3. Account Settings - Email verification
|
|
||||||
4. Account Settings - Delete orphaned TeamManagement.tsx
|
|
||||||
5. Plans & Billing - Proration preview
|
|
||||||
6. Plans & Billing - Cancellation confirmation dialog
|
|
||||||
7. Usage - Usage alerts at thresholds
|
|
||||||
8. Usage - Per-site usage breakdown
|
|
||||||
9. Cross-Module - Billing pages consolidation audit
|
|
||||||
10. Cross-Module - Legacy routes removal
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Files to Delete
|
|
||||||
|
|
||||||
| File | Reason |
|
|
||||||
|------|--------|
|
|
||||||
| `pages/account/TeamManagement.tsx` | Orphaned - functionality in AccountSettingsPage |
|
|
||||||
| Legacy route redirect handlers | After removing `/billing/overview`, `/team`, `/profile` |
|
|
||||||
| Duplicate billing pages | After consolidation audit determines which to remove |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Files to Modify
|
|
||||||
|
|
||||||
| File | Changes |
|
|
||||||
|------|---------|
|
|
||||||
| `pages/account/AccountSettingsPage.tsx` | Connect profile API, implement password change, add role management, add invitation management |
|
|
||||||
| `pages/account/PlansAndBillingPage.tsx` | Add proration preview, cancellation confirmation, link credit purchase |
|
|
||||||
| `pages/account/UsageAnalyticsPage.tsx` | Implement real API activity, add per-site breakdown, add forecasting |
|
|
||||||
| `store/billingStore.ts` | Establish as single source of truth for balance |
|
|
||||||
| Router/App.tsx | Remove legacy routes |
|
|
||||||
| All components using credit balance | Refactor to use single source |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Backend Work Required
|
|
||||||
|
|
||||||
| Area | Work |
|
|
||||||
|------|------|
|
|
||||||
| Profile API | Audit existing endpoint OR create new one consistent with API structure |
|
|
||||||
| Password change API | Implement secure password change endpoint |
|
|
||||||
| API Activity tracking | Ensure backend logs API calls, create endpoint to retrieve activity data |
|
|
||||||
| Usage alerts | Backend service to check thresholds and trigger notifications |
|
|
||||||
| Per-site usage | Endpoint to return credit usage broken down by site |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### AI Agent Specific Tasks
|
|
||||||
|
|
||||||
| Task | Description |
|
|
||||||
|------|-------------|
|
|
||||||
| Billing Pages Audit | Discover all billing pages, analyze functionality, identify redundancies, propose consolidation |
|
|
||||||
| Credit Balance Refactor | Identify all balance sources, determine single source, refactor all references |
|
|
||||||
| Legacy Routes Cleanup | Remove routes, remove redirects, update all references |
|
|
||||||
| Profile API Study | Check if endpoint exists, verify consistency, connect or create |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
## ✅ Section 4 Implementation Complete
|
|
||||||
|
|
||||||
### CRITICAL Items Completed:
|
|
||||||
|
|
||||||
1. **Profile API Connection** (AccountSettingsPage.tsx)
|
|
||||||
- Profile tab now loads user data from `useAuthStore`
|
|
||||||
- Added `getUserProfile()` and `updateUserProfile()` functions to billing.api.ts
|
|
||||||
|
|
||||||
2. **Password Change Implementation** (AccountSettingsPage.tsx)
|
|
||||||
- Added password change modal with old/new password fields
|
|
||||||
- Connected to `/auth/change-password/` backend endpoint
|
|
||||||
- Added validation (min 8 chars, confirmation match)
|
|
||||||
|
|
||||||
3. **Fixed Fake API Activity Data** (UsageAnalyticsPage.tsx)
|
|
||||||
- Removed hardcoded values (98.5%, 1,234, 567, 342)
|
|
||||||
- API tab now shows real data from `analytics?.usage_by_type`
|
|
||||||
- Displays "Operations by Type" with actual credits/counts
|
|
||||||
|
|
||||||
### HIGH Priority Items Completed:
|
|
||||||
|
|
||||||
4. **Deleted TeamManagementPage.tsx**
|
|
||||||
- Removed orphaned file (functionality already exists as tab in AccountSettingsPage)
|
|
||||||
|
|
||||||
5. **Added Cancellation Confirmation Dialog** (PlansAndBillingPage.tsx)
|
|
||||||
- Cancel button now shows confirmation modal
|
|
||||||
- Modal explains consequences (loss of features, credit preservation)
|
|
||||||
- User must confirm before cancellation proceeds
|
|
||||||
|
|
||||||
6. **Legacy Routes Verified**
|
|
||||||
- `/billing/overview` → Points to CreditsAndBilling page
|
|
||||||
- `/account/team` → Redirects to `/account/settings`
|
|
||||||
- `/settings/profile` → Redirects to `/account/settings`
|
|
||||||
@@ -1,652 +0,0 @@
|
|||||||
# Section 5: HELP Module - Audit & Action Plan
|
|
||||||
|
|
||||||
**Date:** December 27, 2025
|
|
||||||
**Status:** Finalized for Implementation
|
|
||||||
**Scope:** Help Center, Documentation, Support Channels
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5.1 Help & Docs
|
|
||||||
|
|
||||||
**Route:** `/help`
|
|
||||||
**File:** `pages/Help/HelpCenter.tsx`
|
|
||||||
|
|
||||||
### Current Functionality
|
|
||||||
- Table of Contents with jump-to-section navigation
|
|
||||||
- Getting Started: Quick Start Guide, Workflow Overview
|
|
||||||
- Planner Module: Keywords, Clusters, Ideas documentation
|
|
||||||
- Writer Module: Tasks, Content, Images documentation
|
|
||||||
- Automation Setup overview
|
|
||||||
- FAQ section (~20 questions)
|
|
||||||
- Support CTA buttons (non-functional)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Issues to Address
|
|
||||||
|
|
||||||
| # | Issue | Priority | Action |
|
|
||||||
|---|-------|----------|--------|
|
|
||||||
| 1 | Support dropdown link broken | 🔴 Critical | Fix link - currently goes to `/profile` which is 404 |
|
|
||||||
| 2 | Contact Support button does nothing | 🔴 Critical | Implement mailto: or external support URL |
|
|
||||||
| 3 | Feature Request button does nothing | 🔴 Critical | Implement mailto: or external feedback URL |
|
|
||||||
| 4 | No actual support channel | 🔴 Critical | Configure working support email/system |
|
|
||||||
| 5 | Placeholder pages exist | High | **DELETE** `/help/docs`, `/help/system-testing`, `/help/function-testing` pages |
|
|
||||||
| 6 | No search functionality | Medium | Add search within help content |
|
|
||||||
| 7 | No contextual help | Low | Consider adding in-app tooltips or "?" icons (future) |
|
|
||||||
| 8 | Stale content risk | Medium | Help content is hardcoded in TSX - document update process |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Pages to Delete
|
|
||||||
|
|
||||||
| File | Route | Reason |
|
|
||||||
|------|-------|--------|
|
|
||||||
| `pages/Help/Documentation.tsx` | `/help/docs` | Empty placeholder - not needed |
|
|
||||||
| `pages/Help/SystemTesting.tsx` | `/help/system-testing` | Empty placeholder - not needed |
|
|
||||||
| `pages/Help/FunctionTesting.tsx` | `/help/function-testing` | Empty placeholder - not needed |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5.2 Documentation Requirements (NEW)
|
|
||||||
|
|
||||||
### Documentation Approach
|
|
||||||
|
|
||||||
Create detailed, step-by-step documentation for each module and flow. Documentation should be:
|
|
||||||
- **Easy to use** - Clear language, no technical jargon
|
|
||||||
- **Step-by-step** - Numbered instructions with expected outcomes
|
|
||||||
- **Visual** - Screenshots or diagrams where helpful
|
|
||||||
- **Current** - Matches exactly how the system is implemented
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Modules to Document
|
|
||||||
|
|
||||||
| Module | Status | Documentation Needed |
|
|
||||||
|--------|--------|---------------------|
|
|
||||||
| **Dashboard** | Active | Overview, metrics explanation, navigation |
|
|
||||||
| **Add Keywords** | Active | How to browse, filter, select, add keywords |
|
|
||||||
| **Content Settings** | Active | Content Generation, Publishing, Image Settings tabs |
|
|
||||||
| **Sites** | Active | Site creation, WordPress integration, site management |
|
|
||||||
| **Planner - Keywords** | Active | Adding, managing, clustering keywords |
|
|
||||||
| **Planner - Clusters** | Active | Understanding clusters, generating ideas |
|
|
||||||
| **Planner - Ideas** | Active | Managing ideas, queueing to writer |
|
|
||||||
| **Writer - Queue** | Active | Task management, content generation |
|
|
||||||
| **Writer - Drafts** | Active | Reviewing drafts, status management |
|
|
||||||
| **Writer - Images** | Active | Image generation, management |
|
|
||||||
| **Writer - Review** | Active | Review process, approval workflow |
|
|
||||||
| **Writer - Published** | Active | Published content, WordPress sync |
|
|
||||||
| **Automation** | Active | Pipeline setup, scheduling, monitoring |
|
|
||||||
| **Account Settings** | Active | Account, Profile, Team management |
|
|
||||||
| **Plans & Billing** | Active | Plans, upgrades, payment, invoices |
|
|
||||||
| **Usage** | Active | Understanding limits, credit usage, history |
|
|
||||||
| Linker | ❌ Not Active | Skip - not documenting |
|
|
||||||
| Optimizer | ❌ Not Active | Skip - not documenting |
|
|
||||||
| Sites/Site Builder | ❌ Not Active | Skip - legacy feature removed |
|
|
||||||
| Thinker | Admin Only | Skip - not user-facing |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Documentation Structure
|
|
||||||
|
|
||||||
For each module, document:
|
|
||||||
|
|
||||||
```
|
|
||||||
## [Module Name]
|
|
||||||
|
|
||||||
### Overview
|
|
||||||
Brief description of what this module does and its purpose in the workflow.
|
|
||||||
|
|
||||||
### How to Access
|
|
||||||
- Navigation path to reach this module
|
|
||||||
- Direct URL
|
|
||||||
|
|
||||||
### Step-by-Step Guide
|
|
||||||
|
|
||||||
#### [Task 1 Name]
|
|
||||||
1. Step one with specific instruction
|
|
||||||
2. Step two with expected result
|
|
||||||
3. Step three...
|
|
||||||
|
|
||||||
#### [Task 2 Name]
|
|
||||||
1. Step one...
|
|
||||||
2. Step two...
|
|
||||||
|
|
||||||
### Key Features
|
|
||||||
- Feature 1: What it does
|
|
||||||
- Feature 2: What it does
|
|
||||||
|
|
||||||
### Tips & Best Practices
|
|
||||||
- Tip 1
|
|
||||||
- Tip 2
|
|
||||||
|
|
||||||
### Common Questions
|
|
||||||
Q: Question?
|
|
||||||
A: Answer
|
|
||||||
|
|
||||||
### Troubleshooting
|
|
||||||
- Problem: X
|
|
||||||
Solution: Y
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Detailed Documentation Outlines
|
|
||||||
|
|
||||||
#### Dashboard Documentation
|
|
||||||
|
|
||||||
```
|
|
||||||
## Dashboard
|
|
||||||
|
|
||||||
### Overview
|
|
||||||
Your command center showing workflow progress, key metrics, and quick actions.
|
|
||||||
|
|
||||||
### Metrics Explained
|
|
||||||
- Keywords: Total keywords in your workflow
|
|
||||||
- Articles: Content pieces created
|
|
||||||
- Images: Images generated
|
|
||||||
- Completion %: Overall workflow progress
|
|
||||||
|
|
||||||
### Workflow Progress
|
|
||||||
Visual pipeline showing: Sites → Keywords → Clusters → Ideas → Content → Published
|
|
||||||
|
|
||||||
### Quick Actions
|
|
||||||
- [Action 1]: What it does, when to use
|
|
||||||
- [Action 2]: What it does, when to use
|
|
||||||
|
|
||||||
### Setup Checklist
|
|
||||||
Understanding the setup completion indicator...
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Add Keywords Documentation
|
|
||||||
|
|
||||||
```
|
|
||||||
## Add Keywords
|
|
||||||
|
|
||||||
### Overview
|
|
||||||
Browse and add keywords from our curated database to your content workflow.
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
- Active site with industry and sector selected
|
|
||||||
|
|
||||||
### Step-by-Step: Adding Keywords
|
|
||||||
|
|
||||||
1. Navigate to SETUP → Add Keywords
|
|
||||||
2. Browse available keywords filtered by your site's industry/sector
|
|
||||||
3. Use filters to narrow results:
|
|
||||||
- Search: Find specific keywords
|
|
||||||
- Country: Filter by target country
|
|
||||||
- Difficulty: Filter by SEO difficulty
|
|
||||||
4. Select keywords by clicking checkboxes
|
|
||||||
5. Click "Add to Workflow" button
|
|
||||||
6. Keywords are now in your Planner
|
|
||||||
|
|
||||||
### After Adding Keywords
|
|
||||||
Click "Next: Plan Your Content →" to proceed to the Planner module.
|
|
||||||
|
|
||||||
### Tips
|
|
||||||
- Start with 10-20 keywords to test your workflow
|
|
||||||
- Mix high and low difficulty keywords
|
|
||||||
- Focus on your core topics first
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Planner Documentation
|
|
||||||
|
|
||||||
```
|
|
||||||
## Planner
|
|
||||||
|
|
||||||
### Overview
|
|
||||||
Organize keywords into topic clusters and generate content ideas.
|
|
||||||
|
|
||||||
### The Planner Flow
|
|
||||||
Keywords → Clusters → Ideas → Writer Queue
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Keywords Tab
|
|
||||||
|
|
||||||
#### Adding Keywords Manually
|
|
||||||
1. Click "Add Keyword" button
|
|
||||||
2. Enter keyword text
|
|
||||||
3. Set initial status
|
|
||||||
4. Save
|
|
||||||
|
|
||||||
#### Clustering Keywords
|
|
||||||
1. Select keywords to cluster (checkboxes)
|
|
||||||
2. Click "Auto-Cluster" button
|
|
||||||
3. AI analyzes and groups related keywords
|
|
||||||
4. Review created clusters in Clusters tab
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Clusters Tab
|
|
||||||
|
|
||||||
#### Understanding Clusters
|
|
||||||
Clusters group related keywords by topic for focused content creation.
|
|
||||||
|
|
||||||
#### Generating Ideas from Clusters
|
|
||||||
1. Select cluster(s) to generate ideas for
|
|
||||||
2. Click "Generate Ideas" button
|
|
||||||
3. AI creates content ideas based on cluster keywords
|
|
||||||
4. Review ideas in Ideas tab
|
|
||||||
|
|
||||||
#### Cluster Progress
|
|
||||||
- Badge shows "X ideas" for clusters with generated ideas
|
|
||||||
- "No ideas yet" indicates pending clusters
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Ideas Tab
|
|
||||||
|
|
||||||
#### Reviewing Ideas
|
|
||||||
Each idea shows: title, target keyword, cluster source
|
|
||||||
|
|
||||||
#### Sending Ideas to Writer
|
|
||||||
1. Select ideas to write (checkboxes)
|
|
||||||
2. Click "Queue to Writer" button
|
|
||||||
3. Ideas become tasks in Writer Queue
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Writer Documentation
|
|
||||||
|
|
||||||
```
|
|
||||||
## Writer
|
|
||||||
|
|
||||||
### Overview
|
|
||||||
Generate, review, and publish AI-created content.
|
|
||||||
|
|
||||||
### The Writer Flow
|
|
||||||
Queue → Drafts → Review → Published
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Queue Tab (Tasks)
|
|
||||||
|
|
||||||
#### Understanding Tasks
|
|
||||||
Tasks are content pieces waiting to be generated.
|
|
||||||
|
|
||||||
#### Generating Content
|
|
||||||
1. Find task in queue
|
|
||||||
2. Click "Generate Content" action
|
|
||||||
3. AI writes the article
|
|
||||||
4. Content moves to Drafts
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Drafts Tab
|
|
||||||
|
|
||||||
#### Reviewing Drafts
|
|
||||||
1. Click on draft to view full content
|
|
||||||
2. Review AI-generated article
|
|
||||||
3. Check content quality and accuracy
|
|
||||||
|
|
||||||
#### Moving to Review
|
|
||||||
1. Select draft(s)
|
|
||||||
2. Change status to "Review"
|
|
||||||
3. Content moves to Review tab
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Images Tab
|
|
||||||
|
|
||||||
#### Generating Images
|
|
||||||
1. Select content needing images
|
|
||||||
2. Click "Generate Images"
|
|
||||||
3. AI creates images based on content
|
|
||||||
4. Images attach to content
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Review Tab
|
|
||||||
|
|
||||||
#### Final Review Process
|
|
||||||
1. Review content and images together
|
|
||||||
2. Make any final adjustments
|
|
||||||
3. Approve for publishing
|
|
||||||
|
|
||||||
#### Publishing to WordPress
|
|
||||||
1. Select reviewed content
|
|
||||||
2. Click "Publish" button
|
|
||||||
3. Content syncs to WordPress
|
|
||||||
4. Moves to Published tab
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Published Tab
|
|
||||||
|
|
||||||
#### Viewing Published Content
|
|
||||||
- See all published articles
|
|
||||||
- WordPress sync status
|
|
||||||
- Publication dates
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Automation Documentation
|
|
||||||
|
|
||||||
```
|
|
||||||
## Automation
|
|
||||||
|
|
||||||
### Overview
|
|
||||||
Automate your entire content pipeline from keywords to published articles.
|
|
||||||
|
|
||||||
### Pipeline Stages
|
|
||||||
1. Keywords → Clustering
|
|
||||||
2. Clusters → Idea Generation
|
|
||||||
3. Ideas → Task Creation
|
|
||||||
4. Tasks → Content Generation
|
|
||||||
5. Content → Image Prompt Extraction
|
|
||||||
6. Prompts → Image Generation
|
|
||||||
7. Review Gate
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Setting Up Automation
|
|
||||||
|
|
||||||
#### Configure Schedule
|
|
||||||
1. Set frequency (daily, weekly, etc.)
|
|
||||||
2. Set preferred run time
|
|
||||||
3. Enable/disable automation
|
|
||||||
|
|
||||||
#### Stage Controls
|
|
||||||
Enable or disable individual stages as needed.
|
|
||||||
|
|
||||||
#### Batch Size
|
|
||||||
Set how many items process per run.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Running Automation
|
|
||||||
|
|
||||||
#### Manual Run
|
|
||||||
Click "Run Now" to start pipeline immediately.
|
|
||||||
|
|
||||||
#### Monitoring Progress
|
|
||||||
- Real-time progress display
|
|
||||||
- Stage-by-stage status
|
|
||||||
- Activity log
|
|
||||||
|
|
||||||
#### Handling Errors
|
|
||||||
- Failed items shown in log
|
|
||||||
- Click "Retry" to reprocess failed items
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Best Practices
|
|
||||||
- Start with small batch sizes
|
|
||||||
- Monitor first few runs closely
|
|
||||||
- Review automation output regularly
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Account Settings Documentation
|
|
||||||
|
|
||||||
```
|
|
||||||
## Account Settings
|
|
||||||
|
|
||||||
### Overview
|
|
||||||
Manage your account, profile, and team.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Account Tab
|
|
||||||
- Organization name
|
|
||||||
- Billing email
|
|
||||||
- Billing address
|
|
||||||
- Tax ID/VAT number
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Profile Tab
|
|
||||||
- Personal information (name, email, phone)
|
|
||||||
- Timezone and language preferences
|
|
||||||
- Notification settings
|
|
||||||
- Security settings (password, 2FA)
|
|
||||||
|
|
||||||
#### Changing Password
|
|
||||||
1. Go to Profile tab
|
|
||||||
2. Click "Change Password"
|
|
||||||
3. Enter current password
|
|
||||||
4. Enter and confirm new password
|
|
||||||
5. Save changes
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Team Tab
|
|
||||||
|
|
||||||
#### Inviting Team Members
|
|
||||||
1. Click "Invite Member"
|
|
||||||
2. Enter email address
|
|
||||||
3. Select role (Admin or Member)
|
|
||||||
4. Send invitation
|
|
||||||
|
|
||||||
#### Managing Members
|
|
||||||
- View all team members
|
|
||||||
- Change member roles
|
|
||||||
- Remove members
|
|
||||||
|
|
||||||
#### Team Limits
|
|
||||||
Your plan allows X team members. Currently using Y.
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Plans & Billing Documentation
|
|
||||||
|
|
||||||
```
|
|
||||||
## Plans & Billing
|
|
||||||
|
|
||||||
### Overview
|
|
||||||
Manage your subscription, view invoices, and track payments.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Current Plan Tab
|
|
||||||
- Plan name and features
|
|
||||||
- Credit balance
|
|
||||||
- Renewal date
|
|
||||||
- Usage summary
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Upgrade Plan Tab
|
|
||||||
|
|
||||||
#### Changing Plans
|
|
||||||
1. Review available plans
|
|
||||||
2. Compare features
|
|
||||||
3. Click "Upgrade" on desired plan
|
|
||||||
4. Review proration (credit for remaining time)
|
|
||||||
5. Confirm change
|
|
||||||
|
|
||||||
#### Cancelling Plan
|
|
||||||
1. Click "Cancel Plan"
|
|
||||||
2. Review what you'll lose
|
|
||||||
3. Confirm cancellation
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### History Tab
|
|
||||||
- Invoice history with PDF download
|
|
||||||
- Payment records
|
|
||||||
- Payment method management
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Usage Documentation
|
|
||||||
|
|
||||||
```
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Overview
|
|
||||||
Track your credit usage, limits, and activity.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Your Limits & Usage Tab
|
|
||||||
|
|
||||||
#### Understanding Limits
|
|
||||||
- **Hard Limits:** Maximum allowed (sites, users, keywords)
|
|
||||||
- **Monthly Limits:** Reset each billing cycle
|
|
||||||
|
|
||||||
#### Credit Balance
|
|
||||||
- Credits remaining
|
|
||||||
- Credits used this month
|
|
||||||
- Monthly allocation
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Credit History Tab
|
|
||||||
Transaction log showing all credit activity:
|
|
||||||
- Credit additions (plan, purchases)
|
|
||||||
- Credit usage (content, images, etc.)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### API Activity Tab
|
|
||||||
- Total API calls
|
|
||||||
- Success rate
|
|
||||||
- Activity by endpoint
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Usage Alerts
|
|
||||||
Automatic alerts at 80%, 90%, and 100% of limits.
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5.3 FAQ Updates
|
|
||||||
|
|
||||||
### Current FAQ Topics (~20 questions)
|
|
||||||
Review and update existing FAQ to ensure accuracy.
|
|
||||||
|
|
||||||
### Additional FAQ Topics Needed
|
|
||||||
|
|
||||||
| Topic | Questions to Add |
|
|
||||||
|-------|------------------|
|
|
||||||
| Credits | How credits work, what uses credits, credit costs |
|
|
||||||
| Automation | How to set up, troubleshooting, best practices |
|
|
||||||
| WordPress | Integration setup, sync issues, troubleshooting |
|
|
||||||
| Content | Generation tips, quality settings, editing |
|
|
||||||
| Images | Generation options, formats, sizes |
|
|
||||||
| Billing | Payment methods, invoices, plan changes |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
### Total Issues
|
|
||||||
|
|
||||||
| Category | Critical | High | Medium | Low | Total |
|
|
||||||
|----------|----------|------|--------|-----|-------|
|
|
||||||
| Support/Links | 4 | 0 | 0 | 0 | 4 |
|
|
||||||
| Pages to Delete | 0 | 1 | 0 | 0 | 1 |
|
|
||||||
| Features | 0 | 0 | 2 | 1 | 3 |
|
|
||||||
| Documentation | 0 | 1 | 0 | 0 | 1 |
|
|
||||||
| **TOTAL** | **4** | **2** | **2** | **1** | **9** |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Critical Items (Must Fix)
|
|
||||||
|
|
||||||
1. Fix Support dropdown link (currently 404)
|
|
||||||
2. Implement Contact Support button (mailto: or support URL)
|
|
||||||
3. Implement Feature Request button (mailto: or feedback URL)
|
|
||||||
4. Configure working support channel
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### High Priority Items
|
|
||||||
|
|
||||||
1. Delete placeholder pages (`/help/docs`, `/help/system-testing`, `/help/function-testing`)
|
|
||||||
2. Create comprehensive step-by-step documentation for all active modules
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Files to Delete
|
|
||||||
|
|
||||||
| File | Reason |
|
|
||||||
|------|--------|
|
|
||||||
| `pages/Help/Documentation.tsx` | Empty placeholder |
|
|
||||||
| `pages/Help/SystemTesting.tsx` | Empty placeholder |
|
|
||||||
| `pages/Help/FunctionTesting.tsx` | Empty placeholder |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Files to Modify
|
|
||||||
|
|
||||||
| File | Changes |
|
|
||||||
|------|---------|
|
|
||||||
| `pages/Help/HelpCenter.tsx` | Fix support link, implement button handlers, add comprehensive documentation, update FAQ |
|
|
||||||
| Router/App.tsx | Remove routes for deleted help pages |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Documentation Modules (Do NOT Document)
|
|
||||||
|
|
||||||
| Module | Reason |
|
|
||||||
|--------|--------|
|
|
||||||
| Linker | Not active |
|
|
||||||
| Optimizer | Not active |
|
|
||||||
| Sites/Site Builder | Legacy feature removed |
|
|
||||||
| Thinker | Admin only - not user-facing |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Documentation Deliverables
|
|
||||||
|
|
||||||
Create detailed step-by-step documentation for:
|
|
||||||
|
|
||||||
1. ✅ Dashboard
|
|
||||||
2. ✅ Add Keywords
|
|
||||||
3. ✅ Content Settings
|
|
||||||
4. ✅ Sites (WordPress integration focus, not site builder)
|
|
||||||
5. ✅ Planner - Keywords
|
|
||||||
6. ✅ Planner - Clusters
|
|
||||||
7. ✅ Planner - Ideas
|
|
||||||
8. ✅ Writer - Queue/Tasks
|
|
||||||
9. ✅ Writer - Drafts
|
|
||||||
10. ✅ Writer - Images
|
|
||||||
11. ✅ Writer - Review
|
|
||||||
12. ✅ Writer - Published
|
|
||||||
13. ✅ Automation
|
|
||||||
14. ✅ Account Settings
|
|
||||||
15. ✅ Plans & Billing
|
|
||||||
16. ✅ Usage
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
## Section 5 HELP Module - All CRITICAL Items Fixed:
|
|
||||||
|
|
||||||
1. **Fixed Support Dropdown Links** (UserDropdown.tsx)
|
|
||||||
- "Edit profile" → `/account/settings`
|
|
||||||
- "Account settings" → `/account/settings`
|
|
||||||
- "Support" → `/help`
|
|
||||||
|
|
||||||
2. **Implemented Contact Support Button** (Help.tsx)
|
|
||||||
- Now opens `mailto:support@igny8.com?subject=Support Request`
|
|
||||||
|
|
||||||
3. **Implemented Feature Request Button** (Help.tsx)
|
|
||||||
- Now opens `mailto:feedback@igny8.com?subject=Feature Request`
|
|
||||||
|
|
||||||
### Section 5 HIGH Priority Items:
|
|
||||||
|
|
||||||
4. **Deleted Placeholder Pages**
|
|
||||||
- Docs.tsx ❌
|
|
||||||
- SystemTesting.tsx ❌
|
|
||||||
- FunctionTesting.tsx ❌
|
|
||||||
|
|
||||||
5. **Removed Routes from App.tsx**
|
|
||||||
- `/help/docs`, `/help/system-testing`, `/help/function-testing`
|
|
||||||
|
|
||||||
6. **Added Comprehensive Documentation** (Help.tsx)
|
|
||||||
- **Dashboard** section - Metrics, Pipeline, Setup Checklist
|
|
||||||
- **Setup Module** section - Add Keywords, Content Settings, Sites Management
|
|
||||||
- **Account & Billing** section - Account Settings, Plans & Billing, Usage & Limits
|
|
||||||
- **8 new FAQ items** covering credits, billing, WordPress, automation
|
|
||||||
|
|
||||||
### Files Changed:
|
|
||||||
- CHANGELOG.md - Updated to v1.1.7
|
|
||||||
- PAGES.md - Updated to v1.1.7
|
|
||||||
- App.tsx - Removed placeholder imports/routes
|
|
||||||
- UserDropdown.tsx - Fixed all links
|
|
||||||
- Help.tsx - Full documentation overhaul
|
|
||||||
|
|
||||||
### Files Deleted:
|
|
||||||
- Docs.tsx
|
|
||||||
- SystemTesting.tsx
|
|
||||||
- FunctionTesting.tsx
|
|
||||||
@@ -1,494 +0,0 @@
|
|||||||
# Section 6: Sidebar & Navigation - Audit & Action Plan
|
|
||||||
|
|
||||||
**Date:** December 27, 2025
|
|
||||||
**Status:** Finalized for Implementation
|
|
||||||
**Scope:** Sidebar structure, navigation restructure (tabs → sidebar dropdowns)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6.1 Current Navigation Structure
|
|
||||||
|
|
||||||
**File:** `layout/AppSidebar.tsx`
|
|
||||||
|
|
||||||
```
|
|
||||||
Dashboard (standalone)
|
|
||||||
├─ SETUP
|
|
||||||
│ ├─ Add Keywords → /setup/add-keywords
|
|
||||||
│ ├─ Content Settings → /account/content-settings
|
|
||||||
│ ├─ Sites → /sites
|
|
||||||
│ └─ Thinker (admin only) → /thinker/prompts
|
|
||||||
├─ WORKFLOW
|
|
||||||
│ ├─ Planner → /planner/keywords
|
|
||||||
│ ├─ Writer → /writer/tasks
|
|
||||||
│ ├─ Automation → /automation
|
|
||||||
│ ├─ Linker → /linker/content [NOT ACTIVE - REMOVE]
|
|
||||||
│ └─ Optimizer → /optimizer/content [NOT ACTIVE - REMOVE]
|
|
||||||
├─ ACCOUNT
|
|
||||||
│ ├─ Account Settings → /account/settings
|
|
||||||
│ ├─ Plans & Billing → /account/plans
|
|
||||||
│ ├─ Usage → /account/usage
|
|
||||||
│ └─ AI Models (admin only) → /settings/integration
|
|
||||||
└─ HELP
|
|
||||||
└─ Help & Docs → /help
|
|
||||||
```
|
|
||||||
|
|
||||||
### Current In-Page Navigation (TO BE REMOVED)
|
|
||||||
|
|
||||||
| Module | Current Tabs/Buttons | Location |
|
|
||||||
|--------|---------------------|----------|
|
|
||||||
| **Planner** | Keywords, Clusters, Ideas | Tab buttons in page header |
|
|
||||||
| **Writer** | Queue, Drafts, Images, Review, Published | Tab buttons in page header |
|
|
||||||
| **Account Settings** | Account, Profile, Team | Tabs in page |
|
|
||||||
| **Plans & Billing** | Current Plan, Upgrade Plan, History | Tabs in page |
|
|
||||||
| **Usage** | Your Limits & Usage, Credit History, API Activity | Tabs in page |
|
|
||||||
| **Content Settings** | Content Generation, Publishing, Image Settings | Tabs in page |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6.2 Issues to Address
|
|
||||||
|
|
||||||
| # | Issue | Priority | Action |
|
|
||||||
|---|-------|----------|--------|
|
|
||||||
| 1 | Linker in navigation | High | **REMOVE** - not active module |
|
|
||||||
| 2 | Optimizer in navigation | High | **REMOVE** - not active module |
|
|
||||||
| 3 | KeywordOpportunities reference | High | **REMOVE** - page being deleted |
|
|
||||||
| 4 | Help sub-pages in routes | High | **REMOVE** - pages being deleted |
|
|
||||||
| 5 | Menu order incorrect | High | Reorder SETUP: Sites → Add Keywords → Content Settings → Thinker |
|
|
||||||
| 6 | Tabs/buttons clutter page headers | High | **MOVE to sidebar dropdowns** |
|
|
||||||
| 7 | No breadcrumb navigation | Medium | Add breadcrumbs (space now available in header) |
|
|
||||||
| 8 | No "Next Step" guidance | Medium | Add contextual next step (space now available in header) |
|
|
||||||
| 9 | No active section highlighting | Medium | Highlight current section/page in sidebar |
|
|
||||||
| 10 | Credit purchase not in sidebar | Low | Accessible from Plans & Billing |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6.3 New Navigation Structure: Sidebar Dropdowns
|
|
||||||
|
|
||||||
### Decision: Move All Sub-Navigation to Sidebar
|
|
||||||
|
|
||||||
**Rationale:**
|
|
||||||
- New app launch - no existing user patterns to unlearn
|
|
||||||
- Desktop-only app - no mobile concerns
|
|
||||||
- Same number of clicks - active dropdown stays expanded automatically
|
|
||||||
- Cleaner page headers - space for breadcrumbs and "Next Step" CTAs
|
|
||||||
- Better discoverability - all navigation visible in one place
|
|
||||||
- Scalable - easy to add new sub-pages in future
|
|
||||||
- Consistent pattern across all modules
|
|
||||||
|
|
||||||
### New Sidebar Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
Dashboard
|
|
||||||
|
|
||||||
SETUP
|
|
||||||
├─ Sites ▼
|
|
||||||
│ ├─ All Sites → /sites
|
|
||||||
│ └─ Site Settings → /sites/:id/settings (contextual)
|
|
||||||
├─ Add Keywords → /setup/add-keywords
|
|
||||||
├─ Content Settings ▼
|
|
||||||
│ ├─ Content Generation → /account/content-settings/generation
|
|
||||||
│ ├─ Publishing → /account/content-settings/publishing
|
|
||||||
│ └─ Image Settings → /account/content-settings/images
|
|
||||||
└─ Thinker (admin only) ▼
|
|
||||||
├─ Prompts → /thinker/prompts
|
|
||||||
└─ Author Profiles → /thinker/author-profiles
|
|
||||||
|
|
||||||
WORKFLOW
|
|
||||||
├─ Planner ▼
|
|
||||||
│ ├─ Keywords → /planner/keywords
|
|
||||||
│ ├─ Clusters → /planner/clusters
|
|
||||||
│ └─ Ideas → /planner/ideas
|
|
||||||
├─ Writer ▼
|
|
||||||
│ ├─ Queue → /writer/tasks
|
|
||||||
│ ├─ Drafts → /writer/drafts
|
|
||||||
│ ├─ Images → /writer/images
|
|
||||||
│ ├─ Review → /writer/review
|
|
||||||
│ └─ Published → /writer/published
|
|
||||||
└─ Automation → /automation
|
|
||||||
|
|
||||||
ACCOUNT
|
|
||||||
├─ Account Settings ▼
|
|
||||||
│ ├─ Account → /account/settings/account
|
|
||||||
│ ├─ Profile → /account/settings/profile
|
|
||||||
│ └─ Team → /account/settings/team
|
|
||||||
├─ Plans & Billing ▼
|
|
||||||
│ ├─ Current Plan → /account/plans/current
|
|
||||||
│ ├─ Upgrade Plan → /account/plans/upgrade
|
|
||||||
│ └─ History → /account/plans/history
|
|
||||||
├─ Usage ▼
|
|
||||||
│ ├─ Limits & Usage → /account/usage/limits
|
|
||||||
│ ├─ Credit History → /account/usage/credits
|
|
||||||
│ └─ API Activity → /account/usage/api
|
|
||||||
└─ AI Models (admin only) → /settings/integration
|
|
||||||
|
|
||||||
HELP
|
|
||||||
└─ Help & Docs → /help
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6.4 Sidebar Behavior Specification
|
|
||||||
|
|
||||||
### Dropdown Behavior
|
|
||||||
|
|
||||||
1. **Active Page Detection:**
|
|
||||||
- When user navigates to any page, its parent dropdown auto-expands
|
|
||||||
- Current page is highlighted within the dropdown
|
|
||||||
- Active dropdown stays expanded - does NOT collapse
|
|
||||||
|
|
||||||
2. **Click Behavior:**
|
|
||||||
- Click on dropdown parent (if not expanded) → expands dropdown
|
|
||||||
- Click on dropdown parent (if expanded) → collapses dropdown
|
|
||||||
- Click on sub-item → navigates to that page, dropdown stays open
|
|
||||||
- Only active page's dropdown auto-opens on page load
|
|
||||||
|
|
||||||
3. **Visual States:**
|
|
||||||
```
|
|
||||||
Planner ▼ ← Parent: expanded indicator
|
|
||||||
Keywords ← Normal sub-item
|
|
||||||
Clusters ● ← Active page: highlighted
|
|
||||||
Ideas ← Normal sub-item
|
|
||||||
|
|
||||||
Writer ▶ ← Collapsed (not active)
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Persistence:**
|
|
||||||
- Active dropdown remains expanded during navigation within that module
|
|
||||||
- On direct URL access or refresh, opens dropdown containing current page
|
|
||||||
- Non-active dropdowns default to collapsed state
|
|
||||||
|
|
||||||
### Example Flow
|
|
||||||
|
|
||||||
User is on `/planner/clusters`:
|
|
||||||
|
|
||||||
```
|
|
||||||
WORKFLOW
|
|
||||||
├─ Planner ▼ [EXPANDED - contains active page]
|
|
||||||
│ ├─ Keywords [clickable]
|
|
||||||
│ ├─ Clusters ● [ACTIVE - highlighted]
|
|
||||||
│ └─ Ideas [clickable]
|
|
||||||
├─ Writer ▶ [COLLAPSED]
|
|
||||||
└─ Automation [no dropdown - single page]
|
|
||||||
```
|
|
||||||
|
|
||||||
User clicks "Ideas":
|
|
||||||
- Navigates to `/planner/ideas`
|
|
||||||
- Planner dropdown stays expanded
|
|
||||||
- "Ideas" becomes highlighted
|
|
||||||
- "Clusters" returns to normal state
|
|
||||||
|
|
||||||
User clicks "Writer":
|
|
||||||
- Writer dropdown expands
|
|
||||||
- Planner dropdown can stay expanded or collapse (design choice)
|
|
||||||
- Shows Writer sub-items
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6.5 Page Header Structure (After Tabs Removal)
|
|
||||||
|
|
||||||
### Before (Current)
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────────────────┐
|
|
||||||
│ [Keywords] [Clusters] [Ideas] [+ Add] [Bulk ▼] [Filter] [Search] │
|
|
||||||
├─────────────────────────────────────────────────────────────────────┤
|
|
||||||
│ Content area... │
|
|
||||||
```
|
|
||||||
|
|
||||||
### After (New)
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────────────────┐
|
|
||||||
│ Planner > Clusters [+ Add] [Bulk ▼] [Next: Ideas →] │
|
|
||||||
├─────────────────────────────────────────────────────────────────────┤
|
|
||||||
│ [Filter] [Search...] │
|
|
||||||
├─────────────────────────────────────────────────────────────────────┤
|
|
||||||
│ Content area... │
|
|
||||||
```
|
|
||||||
|
|
||||||
### Header Components
|
|
||||||
|
|
||||||
| Component | Position | Purpose |
|
|
||||||
|-----------|----------|---------|
|
|
||||||
| Breadcrumb | Left | Shows: Section > Page (e.g., "Planner > Clusters") |
|
|
||||||
| Primary Actions | Center-Right | Add, Bulk actions |
|
|
||||||
| Next Step CTA | Right | Contextual "Next: [Action] →" button |
|
|
||||||
| Filters/Search | Below header or inline | Data filtering |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6.6 Breadcrumb Implementation
|
|
||||||
|
|
||||||
### Breadcrumb Pattern
|
|
||||||
|
|
||||||
```
|
|
||||||
[Section] > [Page]
|
|
||||||
[Section] > [Page] > [Detail]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
| Route | Breadcrumb Display |
|
|
||||||
|-------|-------------------|
|
|
||||||
| `/planner/keywords` | Planner > Keywords |
|
|
||||||
| `/planner/clusters` | Planner > Clusters |
|
|
||||||
| `/planner/clusters/:id` | Planner > Clusters > [Cluster Name] |
|
|
||||||
| `/writer/drafts` | Writer > Drafts |
|
|
||||||
| `/writer/drafts/:id` | Writer > Drafts > [Content Title] |
|
|
||||||
| `/account/settings/team` | Account Settings > Team |
|
|
||||||
| `/account/plans/upgrade` | Plans & Billing > Upgrade Plan |
|
|
||||||
|
|
||||||
### Implementation
|
|
||||||
|
|
||||||
- Create reusable `<Breadcrumb />` component
|
|
||||||
- Each page defines its breadcrumb trail via props or route config
|
|
||||||
- Clickable links except for current page (last item)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6.7 "Next Step" CTA Implementation
|
|
||||||
|
|
||||||
### Contextual Next Steps
|
|
||||||
|
|
||||||
| Current Location | Condition | Next Step CTA |
|
|
||||||
|------------------|-----------|---------------|
|
|
||||||
| Sites | Site created | "Next: Add Keywords →" |
|
|
||||||
| Add Keywords | Keywords added (count > 0) | "Next: Plan Your Content →" |
|
|
||||||
| Planner > Keywords | Has unclustered keywords | "Next: Cluster Keywords →" |
|
|
||||||
| Planner > Clusters | Cluster selected/has clusters | "Next: Generate Ideas →" |
|
|
||||||
| Planner > Ideas | Has ideas | "Next: Queue to Writer →" |
|
|
||||||
| Writer > Queue | Has tasks | "Next: Generate Content →" |
|
|
||||||
| Writer > Drafts | Has drafts | "Next: Review Drafts →" |
|
|
||||||
| Writer > Review | Has reviewed content | "Next: Publish →" |
|
|
||||||
|
|
||||||
### Implementation
|
|
||||||
|
|
||||||
- Create `<NextStepCTA />` component
|
|
||||||
- Each page determines when to show and what action
|
|
||||||
- Button styled prominently but not intrusive
|
|
||||||
- Links to logical next step in workflow
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6.8 Route Updates Required
|
|
||||||
|
|
||||||
### Routes to Add/Update
|
|
||||||
|
|
||||||
To support sidebar navigation, routes need restructuring:
|
|
||||||
|
|
||||||
| Current Route | New Route | Notes |
|
|
||||||
|---------------|-----------|-------|
|
|
||||||
| `/account/content-settings` | `/account/content-settings/generation` | Default to first sub-page |
|
|
||||||
| (same page, different tab) | `/account/content-settings/publishing` | Separate route |
|
|
||||||
| (same page, different tab) | `/account/content-settings/images` | Separate route |
|
|
||||||
| `/account/settings` | `/account/settings/account` | Default to first sub-page |
|
|
||||||
| (same page, different tab) | `/account/settings/profile` | Separate route |
|
|
||||||
| (same page, different tab) | `/account/settings/team` | Separate route |
|
|
||||||
| `/account/plans` | `/account/plans/current` | Default to first sub-page |
|
|
||||||
| (same page, different tab) | `/account/plans/upgrade` | Separate route |
|
|
||||||
| (same page, different tab) | `/account/plans/history` | Separate route |
|
|
||||||
| `/account/usage` | `/account/usage/limits` | Default to first sub-page |
|
|
||||||
| (same page, different tab) | `/account/usage/credits` | Separate route |
|
|
||||||
| (same page, different tab) | `/account/usage/api` | Separate route |
|
|
||||||
|
|
||||||
### Routes to Remove
|
|
||||||
|
|
||||||
| Route | Reason |
|
|
||||||
|-------|--------|
|
|
||||||
| `/linker/*` | Module not active |
|
|
||||||
| `/optimizer/*` | Module not active |
|
|
||||||
| `/planner/keyword-opportunities` | Page deleted |
|
|
||||||
| `/help/docs` | Page deleted |
|
|
||||||
| `/help/system-testing` | Page deleted |
|
|
||||||
| `/help/function-testing` | Page deleted |
|
|
||||||
| `/billing/overview` | Legacy route |
|
|
||||||
| `/team` | Legacy route |
|
|
||||||
| `/profile` | Legacy route |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6.9 Implementation Plan
|
|
||||||
|
|
||||||
### Phase 1: Sidebar Restructure
|
|
||||||
|
|
||||||
1. **Update `AppSidebar.tsx`:**
|
|
||||||
- Add dropdown functionality for multi-page modules
|
|
||||||
- Implement expand/collapse with active state detection
|
|
||||||
- Remove Linker and Optimizer
|
|
||||||
- Reorder SETUP: Sites → Add Keywords → Content Settings → Thinker
|
|
||||||
- Add visual indicators (▼ expanded, ▶ collapsed, ● active)
|
|
||||||
|
|
||||||
2. **Create dropdown data structure:**
|
|
||||||
```typescript
|
|
||||||
const sidebarConfig = [
|
|
||||||
{
|
|
||||||
section: 'SETUP',
|
|
||||||
items: [
|
|
||||||
{ label: 'Sites', path: '/sites', icon: Globe },
|
|
||||||
{ label: 'Add Keywords', path: '/setup/add-keywords', icon: Key },
|
|
||||||
{
|
|
||||||
label: 'Content Settings',
|
|
||||||
icon: Settings,
|
|
||||||
children: [
|
|
||||||
{ label: 'Content Generation', path: '/account/content-settings/generation' },
|
|
||||||
{ label: 'Publishing', path: '/account/content-settings/publishing' },
|
|
||||||
{ label: 'Image Settings', path: '/account/content-settings/images' },
|
|
||||||
]
|
|
||||||
},
|
|
||||||
// ... etc
|
|
||||||
]
|
|
||||||
},
|
|
||||||
// ... other sections
|
|
||||||
];
|
|
||||||
```
|
|
||||||
|
|
||||||
### Phase 2: Route Updates
|
|
||||||
|
|
||||||
1. **Update Router/App.tsx:**
|
|
||||||
- Add new sub-routes for tabbed pages
|
|
||||||
- Set up redirects from parent routes to default child
|
|
||||||
- Remove deleted/inactive routes
|
|
||||||
|
|
||||||
2. **Example route structure:**
|
|
||||||
```typescript
|
|
||||||
// Content Settings
|
|
||||||
<Route path="/account/content-settings" element={<Navigate to="/account/content-settings/generation" />} />
|
|
||||||
<Route path="/account/content-settings/generation" element={<ContentSettingsGeneration />} />
|
|
||||||
<Route path="/account/content-settings/publishing" element={<ContentSettingsPublishing />} />
|
|
||||||
<Route path="/account/content-settings/images" element={<ContentSettingsImages />} />
|
|
||||||
```
|
|
||||||
|
|
||||||
### Phase 3: Page Header Updates
|
|
||||||
|
|
||||||
1. **Remove tab components from all pages:**
|
|
||||||
- Planner (Keywords, Clusters, Ideas tabs)
|
|
||||||
- Writer (Queue, Drafts, Images, Review, Published tabs)
|
|
||||||
- Account Settings (Account, Profile, Team tabs)
|
|
||||||
- Plans & Billing (Current, Upgrade, History tabs)
|
|
||||||
- Usage (Limits, Credits, API tabs)
|
|
||||||
- Content Settings (Generation, Publishing, Images tabs)
|
|
||||||
|
|
||||||
2. **Add Breadcrumb component to each page**
|
|
||||||
|
|
||||||
3. **Add NextStepCTA component where applicable**
|
|
||||||
|
|
||||||
4. **Reorganize header layout:**
|
|
||||||
- Left: Breadcrumb
|
|
||||||
- Right: Actions + Next Step CTA
|
|
||||||
|
|
||||||
### Phase 4: Component Creation
|
|
||||||
|
|
||||||
1. **Create `components/navigation/Breadcrumb.tsx`**
|
|
||||||
2. **Create `components/navigation/NextStepCTA.tsx`**
|
|
||||||
3. **Create `components/navigation/SidebarDropdown.tsx`** (if not using existing UI library component)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
### Total Issues
|
|
||||||
|
|
||||||
| Category | High | Medium | Low | Total |
|
|
||||||
|----------|------|--------|-----|-------|
|
|
||||||
| Remove inactive modules | 2 | 0 | 0 | 2 |
|
|
||||||
| Remove deleted pages | 2 | 0 | 0 | 2 |
|
|
||||||
| Menu order | 1 | 0 | 0 | 1 |
|
|
||||||
| Navigation restructure | 1 | 0 | 0 | 1 |
|
|
||||||
| New features | 0 | 3 | 1 | 4 |
|
|
||||||
| **TOTAL** | **6** | **3** | **1** | **10** |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### High Priority Items
|
|
||||||
|
|
||||||
1. Remove Linker from sidebar navigation
|
|
||||||
2. Remove Optimizer from sidebar navigation
|
|
||||||
3. Remove KeywordOpportunities route references
|
|
||||||
4. Remove Help sub-page routes
|
|
||||||
5. Reorder SETUP menu: Sites → Add Keywords → Content Settings → Thinker
|
|
||||||
6. **Implement sidebar dropdown navigation (replace all tabs)**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Medium Priority Items
|
|
||||||
|
|
||||||
1. Add breadcrumb navigation component
|
|
||||||
2. Add "Next Step" contextual guidance
|
|
||||||
3. Add active section highlighting in sidebar
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Files to Delete
|
|
||||||
|
|
||||||
| File | Reason |
|
|
||||||
|------|--------|
|
|
||||||
| Tab components in page headers | Replaced by sidebar navigation |
|
|
||||||
| Any standalone tab navigation components | No longer needed |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Files to Create
|
|
||||||
|
|
||||||
| File | Purpose |
|
|
||||||
|------|---------|
|
|
||||||
| `components/navigation/Breadcrumb.tsx` | Reusable breadcrumb component |
|
|
||||||
| `components/navigation/NextStepCTA.tsx` | Contextual next step button |
|
|
||||||
| Possibly split page components | If current tabbed pages are single files, may need to split |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Files to Modify
|
|
||||||
|
|
||||||
| File | Changes |
|
|
||||||
|------|---------|
|
|
||||||
| `layout/AppSidebar.tsx` | Complete restructure with dropdowns, remove inactive modules, reorder |
|
|
||||||
| `Router/App.tsx` | Add sub-routes, remove inactive routes, add redirects |
|
|
||||||
| `pages/Planner/*.tsx` | Remove tab navigation from header |
|
|
||||||
| `pages/Writer/*.tsx` | Remove tab navigation from header |
|
|
||||||
| `pages/account/AccountSettingsPage.tsx` | Split into separate route components OR remove tabs |
|
|
||||||
| `pages/account/PlansAndBillingPage.tsx` | Split into separate route components OR remove tabs |
|
|
||||||
| `pages/account/UsageAnalyticsPage.tsx` | Split into separate route components OR remove tabs |
|
|
||||||
| `pages/account/ContentSettingsPage.tsx` | Split into separate route components OR remove tabs |
|
|
||||||
| All page headers | Add Breadcrumb, reorganize layout, add NextStepCTA |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Implementation Decision
|
|
||||||
|
|
||||||
**CONFIRMED: Implement sidebar-based navigation with dropdowns**
|
|
||||||
|
|
||||||
- Remove all tab/button navigation from page headers
|
|
||||||
- All sub-navigation moves to sidebar as expandable dropdowns
|
|
||||||
- Active dropdown stays expanded (same click count as current tabs)
|
|
||||||
- Page headers gain space for breadcrumbs and "Next Step" CTAs
|
|
||||||
- Clean, consistent navigation pattern across all modules
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
Section 6 implementation is complete. Here's a summary of what was done:
|
|
||||||
|
|
||||||
## Section 6 Implementation Complete ✅
|
|
||||||
|
|
||||||
### Sidebar Changes
|
|
||||||
- **Removed** Linker and Optimizer modules from sidebar (not ready for launch)
|
|
||||||
- **Reordered** SETUP menu: Sites → Add Keywords → Content Settings → Thinker
|
|
||||||
- **Added dropdown sub-items** for all major modules with clickable navigation
|
|
||||||
|
|
||||||
### URL-Based Tab Navigation
|
|
||||||
Account pages now use URL paths instead of internal state for tabs:
|
|
||||||
- `/account/settings` → Account tab, `/account/settings/profile` → Profile, `/account/settings/team` → Team
|
|
||||||
- `/account/plans` → Current Plan, `/account/plans/upgrade` → Upgrade, `/account/plans/history` → History
|
|
||||||
- `/account/usage` → Limits, `/account/usage/credits` → Credits, `/account/usage/activity` → Activity
|
|
||||||
- `/account/content-settings` → Content Generation, `/account/content-settings/publishing` → Publishing, `/account/content-settings/images` → Images
|
|
||||||
|
|
||||||
### Navigation Cleanup
|
|
||||||
- **Removed ModuleNavigationTabs** from all module pages (Planner, Writer, Thinker, Sites)
|
|
||||||
- **Added breadcrumb prop** to PageHeader component
|
|
||||||
- All pages now display breadcrumb navigation (e.g., "Planner / Keywords")
|
|
||||||
|
|
||||||
### Files Modified
|
|
||||||
- AppSidebar.tsx - Sidebar restructure
|
|
||||||
- App.tsx - Added sub-routes
|
|
||||||
- PageHeader.tsx - Added breadcrumb prop
|
|
||||||
- 4 account pages - URL-based tab navigation
|
|
||||||
- 3 Planner pages, 5 Writer pages, 4 Thinker pages, 1 Sites page - Removed tabs, added breadcrumbs
|
|
||||||
- CHANGELOG.md - Updated to v1.1.8
|
|
||||||
@@ -1,308 +0,0 @@
|
|||||||
# IGNY8 Pricing System - Final Simplified Plan
|
|
||||||
|
|
||||||
**Date:** December 26, 2025
|
|
||||||
**Status:** APPROVED DIRECTION
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. Current System Assessment ✅
|
|
||||||
|
|
||||||
The existing token-based credit system is **correct and safe**:
|
|
||||||
- ✅ `CreditCostConfig` with `tokens_per_credit` ratio per operation
|
|
||||||
- ✅ `min_credits` per operation (floor protection)
|
|
||||||
- ✅ Actual tokens calculated after AI call (accurate margin)
|
|
||||||
- ✅ Model-aware pricing (different models = different costs)
|
|
||||||
|
|
||||||
**Keep this system. Just simplify the limits and UI.**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Actual Cost Analysis (From Production Data)
|
|
||||||
|
|
||||||
### Per-Article Cost Breakdown (GPT-4.1 pricing)
|
|
||||||
|
|
||||||
| Stage | Input Tokens | Output Tokens | Actual Cost |
|
|
||||||
|-------|--------------|---------------|-------------|
|
|
||||||
| Clustering (per article share*) | ~400 | ~400 | **$0.005** |
|
|
||||||
| Idea Generation (per article share*) | ~900 | ~1000 | **$0.012** |
|
|
||||||
| Content Writing | 2500 | 3500 | **$0.041** |
|
|
||||||
| Image Prompt Extraction | 500 | 1100 | **$0.012** |
|
|
||||||
| **Text Subtotal** | | | **$0.07** |
|
|
||||||
| Images (3 avg @ $0.04) | | | **$0.12** |
|
|
||||||
| **TOTAL PER ARTICLE** | | | **$0.19** |
|
|
||||||
|
|
||||||
*With 6 images (max): **$0.31 per article**
|
|
||||||
|
|
||||||
### Target Markup: 10-15x
|
|
||||||
|
|
||||||
| Scenario | Our Cost | 10x Price | 15x Price |
|
|
||||||
|----------|----------|-----------|-----------|
|
|
||||||
| Article (3 images) | $0.19 | $1.90 | $2.85 |
|
|
||||||
| Article (6 images) | $0.31 | $3.10 | $4.65 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Simplified Credit Pricing (10x Markup)
|
|
||||||
|
|
||||||
### 3.1 Credit Cost per Operation
|
|
||||||
|
|
||||||
Using **1 credit = $0.01** and **10x markup**:
|
|
||||||
|
|
||||||
| Operation | Actual Cost | Target Price | Credits |
|
|
||||||
|-----------|-------------|--------------|---------|
|
|
||||||
| Clustering | $0.005 | $0.05 | **5** |
|
|
||||||
| Idea Generation | $0.012 | $0.12 | **10** |
|
|
||||||
| Content Writing | $0.041 | $0.41 | **40** |
|
|
||||||
| Image Prompts | $0.012 | $0.12 | **10** |
|
|
||||||
| Image (per image) | $0.04 | $0.40 | **40** |
|
|
||||||
| Linking | $0.003 | $0.03 | **3** |
|
|
||||||
| Optimization | $0.005 | $0.05 | **5** |
|
|
||||||
|
|
||||||
### 3.2 Full Article Workflow Cost
|
|
||||||
|
|
||||||
| Workflow | Calculation | Total Credits |
|
|
||||||
|----------|-------------|---------------|
|
|
||||||
| Text only | 5 + 10 + 40 + 10 = 65 | **65 credits** |
|
|
||||||
| + 3 images | 65 + (3 × 40) = 185 | **185 credits** |
|
|
||||||
| + 6 images | 65 + (6 × 40) = 305 | **305 credits** |
|
|
||||||
| + linking + optimization | +3 +5 = +8 | **+8 credits** |
|
|
||||||
|
|
||||||
**Typical article: ~200 credits = $2.00** (at 10x margin)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Simplified Plan Structure
|
|
||||||
|
|
||||||
### 4.1 Remove All Limits Except Keywords
|
|
||||||
|
|
||||||
**DELETE:**
|
|
||||||
- ❌ max_content_ideas
|
|
||||||
- ❌ max_content_words
|
|
||||||
- ❌ max_images_basic
|
|
||||||
- ❌ max_images_premium
|
|
||||||
- ❌ max_image_prompts
|
|
||||||
- ❌ max_clusters (soft limit via credits)
|
|
||||||
- ❌ All usage tracking fields
|
|
||||||
|
|
||||||
**KEEP:**
|
|
||||||
- ✅ Credits (token-based, monthly allocation)
|
|
||||||
- ✅ max_keywords (storage limit, defines plan tier)
|
|
||||||
- ✅ max_sites, max_users (account management)
|
|
||||||
|
|
||||||
### 4.2 New Plan Tiers
|
|
||||||
|
|
||||||
| Plan | Price | Credits/Month | Keywords | Sites | Users | ~Articles |
|
|
||||||
|------|-------|---------------|----------|-------|-------|-----------|
|
|
||||||
| **Free** | $0 | 200 | 100 | 1 | 1 | ~1 |
|
|
||||||
| **Starter** | $29 | 3,000 | 1,000 | 3 | 3 | ~15 |
|
|
||||||
| **Growth** | $79 | 10,000 | 5,000 | 10 | 10 | ~50 |
|
|
||||||
| **Scale** | $199 | 30,000 | Unlimited | ∞ | ∞ | ~150 |
|
|
||||||
|
|
||||||
**Simple value proposition:**
|
|
||||||
- Starter: ~15 full articles/month for $29 (~$2/article)
|
|
||||||
- Growth: ~50 full articles/month for $79 (~$1.60/article)
|
|
||||||
- Scale: ~150 full articles/month for $199 (~$1.33/article)
|
|
||||||
|
|
||||||
### 4.3 Credit Top-Up Pricing
|
|
||||||
|
|
||||||
| Package | Credits | Price | Per Credit |
|
|
||||||
|---------|---------|-------|------------|
|
|
||||||
| Small | 500 | $7 | $0.014 |
|
|
||||||
| Medium | 2,000 | $25 | $0.0125 |
|
|
||||||
| Large | 5,000 | $55 | $0.011 |
|
|
||||||
| Bulk | 15,000 | $150 | $0.01 |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5. Content Length Feature (New)
|
|
||||||
|
|
||||||
### 5.1 Add Word Count Selection
|
|
||||||
|
|
||||||
**Content Settings (Site-level default):**
|
|
||||||
```
|
|
||||||
Target Article Length: [Short ~800] [Medium ~1500] [Long ~2500] [Custom: ___]
|
|
||||||
```
|
|
||||||
|
|
||||||
**Idea Generation (per-idea):**
|
|
||||||
- Include target word count in idea brief
|
|
||||||
- AI considers length when generating outline
|
|
||||||
|
|
||||||
**Content Generation (per-content):**
|
|
||||||
- Pass word count to prompt
|
|
||||||
- Affects token usage (longer = more credits)
|
|
||||||
|
|
||||||
### 5.2 Credit Adjustment for Length
|
|
||||||
|
|
||||||
| Length | Words | Token Estimate | Credits |
|
|
||||||
|--------|-------|----------------|---------|
|
|
||||||
| Short | ~800 | 2000 | 25 |
|
|
||||||
| Medium | ~1500 | 3500 | 40 |
|
|
||||||
| Long | ~2500 | 5500 | 60 |
|
|
||||||
| Extra Long | ~4000 | 8000 | 90 |
|
|
||||||
|
|
||||||
**User sees:** "Short article: ~150 credits, Long article: ~250 credits"
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 6. Implementation Plan
|
|
||||||
|
|
||||||
### Phase 1: Backend Updates (Day 1-2)
|
|
||||||
|
|
||||||
**6.1 Update CreditCostConfig values:**
|
|
||||||
|
|
||||||
```python
|
|
||||||
# New fixed credit costs (min_credits = display value)
|
|
||||||
CREDIT_CONFIGS = {
|
|
||||||
'clustering': {'tokens_per_credit': 160, 'min_credits': 5},
|
|
||||||
'idea_generation': {'tokens_per_credit': 190, 'min_credits': 10},
|
|
||||||
'content_generation': {'tokens_per_credit': 150, 'min_credits': 25}, # Base for short
|
|
||||||
'image_prompt_extraction': {'tokens_per_credit': 160, 'min_credits': 10},
|
|
||||||
'image_generation': {'tokens_per_credit': 1, 'min_credits': 40}, # Fixed per image
|
|
||||||
'linking': {'tokens_per_credit': 300, 'min_credits': 3},
|
|
||||||
'optimization': {'tokens_per_credit': 200, 'min_credits': 5},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**6.2 Remove monthly limit fields:**
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Plan model - DELETE these fields
|
|
||||||
- max_content_ideas
|
|
||||||
- max_content_words
|
|
||||||
- max_images_basic
|
|
||||||
- max_images_premium
|
|
||||||
- max_image_prompts
|
|
||||||
|
|
||||||
# Account model - DELETE these fields
|
|
||||||
- usage_content_ideas
|
|
||||||
- usage_content_words
|
|
||||||
- usage_images_basic
|
|
||||||
- usage_images_premium
|
|
||||||
- usage_image_prompts
|
|
||||||
- usage_period_start
|
|
||||||
- usage_period_end
|
|
||||||
```
|
|
||||||
|
|
||||||
**6.3 Remove LimitService monthly methods:**
|
|
||||||
- Delete `check_monthly_limit()`
|
|
||||||
- Delete `increment_usage()`
|
|
||||||
- Delete monthly reset task
|
|
||||||
- Keep `check_hard_limit()` for sites/users/keywords
|
|
||||||
|
|
||||||
### Phase 2: Content Length Feature (Day 2-3)
|
|
||||||
|
|
||||||
**6.4 Add ContentSettings.target_word_count:**
|
|
||||||
|
|
||||||
```python
|
|
||||||
class ContentSettings(models.Model):
|
|
||||||
# ... existing fields ...
|
|
||||||
target_word_count = models.IntegerField(
|
|
||||||
default=1500,
|
|
||||||
choices=[(800, 'Short'), (1500, 'Medium'), (2500, 'Long'), (4000, 'Extra Long')],
|
|
||||||
help_text="Default target word count for articles"
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
**6.5 Update AI prompts:**
|
|
||||||
- `generate_ideas.py` - Include word count in idea brief
|
|
||||||
- `generate_content.py` - Pass word count target
|
|
||||||
|
|
||||||
### Phase 3: Frontend Updates (Day 3-4)
|
|
||||||
|
|
||||||
**6.6 Update Content Settings page:**
|
|
||||||
- Add word count selector
|
|
||||||
|
|
||||||
**6.7 Update Usage page:**
|
|
||||||
- Show credits only (remove monthly limit bars)
|
|
||||||
- Show keywords used vs limit
|
|
||||||
- Show simple cost reference
|
|
||||||
|
|
||||||
**6.8 Fix/Replace CreditCostsPanel.tsx:**
|
|
||||||
- Show fixed credit costs (not token-based confusion)
|
|
||||||
- Simple table: "Content: 40 credits, Image: 40 credits"
|
|
||||||
|
|
||||||
**6.9 Update Pricing page:**
|
|
||||||
- New plan structure
|
|
||||||
- "~X articles/month" messaging
|
|
||||||
|
|
||||||
### Phase 4: Migration & Cleanup (Day 4-5)
|
|
||||||
|
|
||||||
**6.10 Database migration:**
|
|
||||||
- Remove deprecated fields
|
|
||||||
- Update existing plans to new structure
|
|
||||||
|
|
||||||
**6.11 Clean up dead code:**
|
|
||||||
- Remove LimitService monthly tracking
|
|
||||||
- Remove usage increment calls in services
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 7. User Experience (After Simplification)
|
|
||||||
|
|
||||||
### What User Sees:
|
|
||||||
|
|
||||||
**Dashboard:**
|
|
||||||
```
|
|
||||||
Credits: 2,847 / 3,000 remaining
|
|
||||||
Keywords: 234 / 1,000
|
|
||||||
```
|
|
||||||
|
|
||||||
**Before generating content:**
|
|
||||||
```
|
|
||||||
Estimated cost: ~185 credits
|
|
||||||
- Content (medium): 40 credits
|
|
||||||
- Image prompts: 10 credits
|
|
||||||
- 3 images: 120 credits
|
|
||||||
- Clustering share: ~5 credits
|
|
||||||
- Ideas share: ~10 credits
|
|
||||||
```
|
|
||||||
|
|
||||||
**Content Settings:**
|
|
||||||
```
|
|
||||||
Article Length: [Short] [Medium ✓] [Long] [Extra Long]
|
|
||||||
Images per Article: [3 ▼]
|
|
||||||
```
|
|
||||||
|
|
||||||
### What Admin Sees:
|
|
||||||
|
|
||||||
**Plans admin:**
|
|
||||||
- Credits/month
|
|
||||||
- Keywords limit
|
|
||||||
- Sites/Users limits
|
|
||||||
- Price
|
|
||||||
|
|
||||||
**No more:**
|
|
||||||
- 5 different monthly limit fields
|
|
||||||
- Usage tracking complexity
|
|
||||||
- Monthly reset management
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. Summary
|
|
||||||
|
|
||||||
| Before | After |
|
|
||||||
|--------|-------|
|
|
||||||
| Credits + 5 monthly limits | Credits only |
|
|
||||||
| 9 limit fields per plan | 3 limit fields (credits, keywords, sites) |
|
|
||||||
| 5 usage tracking fields | 1 field (credits balance) |
|
|
||||||
| Complex monthly resets | Simple credit allocation |
|
|
||||||
| Unpredictable costs | Clear cost estimates |
|
|
||||||
| No length control | Word count selection |
|
|
||||||
|
|
||||||
**Result:**
|
|
||||||
- ✅ Safe margins (token-based calculation preserved)
|
|
||||||
- ✅ Simple for user (one number to track)
|
|
||||||
- ✅ Simple for admin (fewer fields to manage)
|
|
||||||
- ✅ Predictable (show estimated costs upfront)
|
|
||||||
- ✅ Flexible (manual or automation workflows work same way)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 9. Immediate Actions
|
|
||||||
|
|
||||||
1. **Update CreditCostConfig** in database with new values
|
|
||||||
2. **Add target_word_count** to ContentSettings model
|
|
||||||
3. **Update prompts** to include word count
|
|
||||||
4. **Remove monthly limit checks** from services
|
|
||||||
5. **Update frontend** Usage page and CreditCostsPanel
|
|
||||||
6. **Migration** to remove deprecated fields
|
|
||||||
@@ -1,406 +0,0 @@
|
|||||||
# Section 1: Dashboard - Audit & Action Plan
|
|
||||||
|
|
||||||
**Date:** December 27, 2025
|
|
||||||
**Status:** Finalized for Implementation (To be done LAST after all other sections complete)
|
|
||||||
**Scope:** Main dashboard page - metrics, workflow visualization, quick actions
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1.1 Current Functionality
|
|
||||||
|
|
||||||
**Route:** `/`
|
|
||||||
**Files:** `pages/Dashboard/Home.tsx`, `components/dashboard/*`
|
|
||||||
|
|
||||||
### What Dashboard Currently Shows
|
|
||||||
|
|
||||||
- **Workflow Progress:** 6-step pipeline visualization (Sites → Keywords → Clusters → Ideas → Content → Published)
|
|
||||||
- **Quick Actions:** 5 navigation shortcuts
|
|
||||||
- **Key Metrics:** 4 cards (Keywords, Articles, Images, Completion %)
|
|
||||||
- **Credit Usage:** Monthly allowance and usage bar
|
|
||||||
- **Workflow Modules Guide:** 8 info cards explaining modules
|
|
||||||
- **Onboarding:** Site creation wizard for new users
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1.2 Critical Gaps
|
|
||||||
|
|
||||||
| # | Issue | Impact | Priority |
|
|
||||||
|---|-------|--------|----------|
|
|
||||||
| 1 | No aggregated API endpoint | Performance - makes 6+ sequential API calls with 120ms delays | 🔴 Critical |
|
|
||||||
| 2 | Published content count incorrect | Data accuracy - cannot distinguish published vs draft | 🔴 Critical |
|
|
||||||
| 3 | Usage Summary is hardcoded | Misleading - shows fake "547 credits / $0.34" data | 🔴 Critical |
|
|
||||||
| 4 | Recent Activity is hardcoded | Misleading - static mock activity that never updates | 🔴 Critical |
|
|
||||||
| 5 | No real-time updates | Stale data - only refreshes on manual action | High |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1.3 Missing Professional Features
|
|
||||||
|
|
||||||
| # | Feature | Why Important | Priority |
|
|
||||||
|---|---------|---------------|----------|
|
|
||||||
| 6 | Needs Attention section | Users don't know what requires action | High |
|
|
||||||
| 7 | Recent content activity | No real list of recently created/published content | High |
|
|
||||||
| 8 | Error/warning alerts | No indication of failed syncs, low credits, config issues | High |
|
|
||||||
| 9 | Pipeline queue depth | No visibility into items waiting at each stage | Medium |
|
|
||||||
| 10 | Automation status | No run status, last run time, or items processed | Medium |
|
|
||||||
| 11 | Site health/sync status | No WordPress sync health indicator | Medium |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1.4 Workflow Issues
|
|
||||||
|
|
||||||
| # | Issue | Priority |
|
|
||||||
|---|-------|----------|
|
|
||||||
| 12 | Quick Actions don't adapt to user state | Medium - shows same 5 actions regardless of workflow stage |
|
|
||||||
| 13 | Workflow Completion % is misleading | Medium - formula doesn't reflect real content-from-keywords ratio |
|
|
||||||
| 14 | Modules Guide not dismissible | Low - 8 large cards always shown, no way to hide |
|
|
||||||
| 15 | Chart widget code exists but unused | Low - dead code, no trend visualization |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1.5 Issues to Address
|
|
||||||
|
|
||||||
### Critical (Must Fix)
|
|
||||||
|
|
||||||
| # | Issue | Action |
|
|
||||||
|---|-------|--------|
|
|
||||||
| 1 | No aggregated API endpoint | Create `/v1/dashboard/summary/` endpoint that returns all dashboard data in single call |
|
|
||||||
| 2 | Published content count incorrect | Fix query to separate published vs draft status |
|
|
||||||
| 3 | Usage Summary is hardcoded | Replace with real billing data from billingStore |
|
|
||||||
| 4 | Recent Activity is hardcoded | Implement real activity log OR remove section entirely |
|
|
||||||
|
|
||||||
### High Priority
|
|
||||||
|
|
||||||
| # | Issue | Action |
|
|
||||||
|---|-------|--------|
|
|
||||||
| 5 | No real-time updates | Add polling or websocket for live updates |
|
|
||||||
| 6 | No "Needs Attention" section | Add widget showing: pending reviews, failed syncs, low credits, incomplete setup |
|
|
||||||
| 7 | No recent content activity | Show real list of recently created/updated content |
|
|
||||||
| 8 | No error/warning alerts | Display alerts for: failed WordPress syncs, approaching limits, config issues |
|
|
||||||
|
|
||||||
### Medium Priority
|
|
||||||
|
|
||||||
| # | Issue | Action |
|
|
||||||
|---|-------|--------|
|
|
||||||
| 9 | No pipeline queue depth | Show count of items at each workflow stage |
|
|
||||||
| 10 | No automation status | Display: last run time, items processed, next scheduled run |
|
|
||||||
| 11 | No site health indicator | Show WordPress connection status per site |
|
|
||||||
| 12 | Quick Actions don't adapt | Make contextual based on user's workflow state |
|
|
||||||
| 13 | Completion % misleading | Revise formula to reflect actual workflow progress |
|
|
||||||
|
|
||||||
### Low Priority
|
|
||||||
|
|
||||||
| # | Issue | Action |
|
|
||||||
|---|-------|--------|
|
|
||||||
| 14 | Modules Guide not dismissible | Add dismiss/hide option, remember preference |
|
|
||||||
| 15 | Dead chart widget code | Either implement trend visualization or remove dead code |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1.6 Dashboard Revamp Specification
|
|
||||||
|
|
||||||
### New Dashboard Layout
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
||||||
│ DASHBOARD │
|
|
||||||
├─────────────────────────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
||||||
│ │ NEEDS ATTENTION (if any) │ │
|
|
||||||
│ │ ⚠ 3 content pieces pending review [View →] │ │
|
|
||||||
│ │ ⚠ WordPress sync failed for Site A [Retry] [Fix] │ │
|
|
||||||
│ │ ⚠ Credit usage at 85% [Upgrade →] │ │
|
|
||||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
||||||
│ │ Keywords │ │ Articles │ │ Images │ │ Completion │ │
|
|
||||||
│ │ 156 │ │ 43 │ │ 127 │ │ 68% │ │
|
|
||||||
│ │ +12 this mo │ │ +8 this mo │ │ +24 this mo │ │ ↑ from 52% │ │
|
|
||||||
│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
||||||
│ │ WORKFLOW PIPELINE │ │
|
|
||||||
│ │ Sites(2) → Keywords(156) → Clusters(23) → Ideas(67) → Content(43) → Published(38) │
|
|
||||||
│ │ ✓ ✓ ✓ 12 pending 5 pending │ │
|
|
||||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌────────────────────────────┐ ┌────────────────────────────────────┐ │
|
|
||||||
│ │ CONTENT USAGE │ │ QUICK ACTIONS │ │
|
|
||||||
│ │ ████████████░░░░ 68/100 │ │ [+ Add Keywords] │ │
|
|
||||||
│ │ 68 used this month │ │ [Generate Content] ← contextual │ │
|
|
||||||
│ │ Resets in 12 days │ │ [Review Drafts] (5) │ │
|
|
||||||
│ └────────────────────────────┘ │ [View Published] │ │
|
|
||||||
│ └────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
||||||
│ │ RECENT ACTIVITY │ │
|
|
||||||
│ │ • Generated 5 articles from "Product Reviews" cluster 2 hours ago │ │
|
|
||||||
│ │ • Published "Best Running Shoes 2025" to Site A 3 hours ago │ │
|
|
||||||
│ │ • Created 12 ideas from keyword clustering Yesterday │ │
|
|
||||||
│ │ • Automation run completed: 8 articles generated Yesterday │ │
|
|
||||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
||||||
│ │ AUTOMATION STATUS │ │
|
|
||||||
│ │ Status: ● Active Last run: 2 hours ago Next: Tomorrow 9:00 AM │ │
|
|
||||||
│ │ Last run: Processed 15 keywords → 3 clusters → 12 ideas → 8 articles │ │
|
|
||||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Dashboard Components
|
|
||||||
|
|
||||||
| Component | Purpose | Data Source |
|
|
||||||
|-----------|---------|-------------|
|
|
||||||
| Needs Attention | Actionable alerts requiring user action | Aggregated from all modules |
|
|
||||||
| Key Metrics | Overview counts | Aggregated API endpoint |
|
|
||||||
| Workflow Pipeline | Visual progress through stages | Aggregated API endpoint |
|
|
||||||
| Content Usage | Credit/content piece usage | billingStore (single source of truth) |
|
|
||||||
| Quick Actions | Contextual navigation shortcuts | Based on workflow state |
|
|
||||||
| Recent Activity | Real activity log | Activity tracking system |
|
|
||||||
| Automation Status | Automation module summary | Automation service |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1.7 Aggregated API Endpoint
|
|
||||||
|
|
||||||
### Endpoint: `GET /v1/dashboard/summary/`
|
|
||||||
|
|
||||||
**Response Structure:**
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"metrics": {
|
|
||||||
"keywords_total": 156,
|
|
||||||
"keywords_this_month": 12,
|
|
||||||
"articles_total": 43,
|
|
||||||
"articles_this_month": 8,
|
|
||||||
"articles_draft": 5,
|
|
||||||
"articles_published": 38,
|
|
||||||
"images_total": 127,
|
|
||||||
"images_this_month": 24,
|
|
||||||
"completion_percentage": 68
|
|
||||||
},
|
|
||||||
"pipeline": {
|
|
||||||
"sites": 2,
|
|
||||||
"keywords": 156,
|
|
||||||
"clusters": 23,
|
|
||||||
"ideas": 67,
|
|
||||||
"ideas_pending": 12,
|
|
||||||
"content": 43,
|
|
||||||
"content_pending": 5,
|
|
||||||
"published": 38
|
|
||||||
},
|
|
||||||
"usage": {
|
|
||||||
"credits_used": 68,
|
|
||||||
"credits_total": 100,
|
|
||||||
"reset_days": 12
|
|
||||||
},
|
|
||||||
"alerts": [
|
|
||||||
{
|
|
||||||
"type": "pending_review",
|
|
||||||
"message": "3 content pieces pending review",
|
|
||||||
"action_url": "/writer/review",
|
|
||||||
"action_label": "View"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "sync_failed",
|
|
||||||
"message": "WordPress sync failed for Site A",
|
|
||||||
"action_url": "/sites/1/settings",
|
|
||||||
"action_label": "Fix"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"recent_activity": [
|
|
||||||
{
|
|
||||||
"type": "content_generated",
|
|
||||||
"message": "Generated 5 articles from 'Product Reviews' cluster",
|
|
||||||
"timestamp": "2025-12-27T10:30:00Z"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"automation": {
|
|
||||||
"status": "active",
|
|
||||||
"last_run": "2025-12-27T08:00:00Z",
|
|
||||||
"next_run": "2025-12-28T09:00:00Z",
|
|
||||||
"last_run_summary": "15 keywords → 3 clusters → 12 ideas → 8 articles"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1.8 "Needs Attention" Widget Specification
|
|
||||||
|
|
||||||
### Alert Types
|
|
||||||
|
|
||||||
| Type | Trigger | Message | Action |
|
|
||||||
|------|---------|---------|--------|
|
|
||||||
| `pending_review` | Content in review status > 0 | "X content pieces pending review" | Link to Writer > Review |
|
|
||||||
| `sync_failed` | WordPress sync error | "WordPress sync failed for [Site]" | Link to Site Settings |
|
|
||||||
| `low_credits` | Usage > 80% | "Credit usage at X%" | Link to Upgrade |
|
|
||||||
| `credits_exhausted` | Usage = 100% | "Monthly content limit reached" | Link to Upgrade |
|
|
||||||
| `setup_incomplete` | Setup checklist incomplete | "Complete your setup" | Link to incomplete item |
|
|
||||||
| `automation_failed` | Last automation run had errors | "Automation encountered errors" | Link to Automation |
|
|
||||||
|
|
||||||
### Display Rules
|
|
||||||
|
|
||||||
- Show maximum 3-4 alerts at a time
|
|
||||||
- Prioritize by severity: errors > warnings > info
|
|
||||||
- Dismissible alerts (remember dismissal for session)
|
|
||||||
- Empty state: Hide section entirely when no alerts
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1.9 Quick Actions - Contextual Logic
|
|
||||||
|
|
||||||
### Logic for Displaying Actions
|
|
||||||
|
|
||||||
```
|
|
||||||
IF no sites exist:
|
|
||||||
→ "Create Your First Site"
|
|
||||||
|
|
||||||
ELSE IF no keywords:
|
|
||||||
→ "Add Keywords"
|
|
||||||
|
|
||||||
ELSE IF keywords but no clusters:
|
|
||||||
→ "Cluster Keywords"
|
|
||||||
|
|
||||||
ELSE IF clusters but no ideas:
|
|
||||||
→ "Generate Ideas"
|
|
||||||
|
|
||||||
ELSE IF ideas but no content:
|
|
||||||
→ "Generate Content"
|
|
||||||
|
|
||||||
ELSE IF content in draft:
|
|
||||||
→ "Review Drafts (X)"
|
|
||||||
|
|
||||||
ELSE IF content in review:
|
|
||||||
→ "Publish Content (X)"
|
|
||||||
|
|
||||||
ALWAYS show:
|
|
||||||
→ "View Published" (if any published)
|
|
||||||
→ "Run Automation" (if automation configured)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Default Actions (Always Available)
|
|
||||||
|
|
||||||
- Add Keywords
|
|
||||||
- View Planner
|
|
||||||
- View Writer
|
|
||||||
- Settings
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1.10 Implementation Notes
|
|
||||||
|
|
||||||
### Data Flow
|
|
||||||
|
|
||||||
1. **On Dashboard Load:**
|
|
||||||
- Single API call to `/v1/dashboard/summary/`
|
|
||||||
- Populate all widgets from response
|
|
||||||
- No sequential calls, no delays
|
|
||||||
|
|
||||||
2. **Real-time Updates (Optional):**
|
|
||||||
- Poll every 60 seconds for updates
|
|
||||||
- OR use WebSocket for push updates
|
|
||||||
- Update only changed data
|
|
||||||
|
|
||||||
3. **Credit Usage:**
|
|
||||||
- Use billingStore as single source of truth
|
|
||||||
- Dashboard reads from store, doesn't fetch separately
|
|
||||||
|
|
||||||
### Performance Requirements
|
|
||||||
|
|
||||||
- Dashboard should load in < 2 seconds
|
|
||||||
- Single API call instead of 6+ sequential calls
|
|
||||||
- Lazy load Modules Guide (below fold)
|
|
||||||
- Cache dashboard data for 30 seconds
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
### Total Issues
|
|
||||||
|
|
||||||
| Category | Critical | High | Medium | Low | Total |
|
|
||||||
|----------|----------|------|--------|-----|-------|
|
|
||||||
| Data Issues | 4 | 0 | 0 | 0 | 4 |
|
|
||||||
| Missing Features | 0 | 4 | 4 | 0 | 8 |
|
|
||||||
| UX Issues | 0 | 0 | 2 | 2 | 4 |
|
|
||||||
| **TOTAL** | **4** | **4** | **6** | **2** | **16** |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Critical Items (Must Fix)
|
|
||||||
|
|
||||||
1. Create aggregated dashboard API endpoint
|
|
||||||
2. Fix published content count (distinguish published vs draft)
|
|
||||||
3. Replace hardcoded usage summary with real data
|
|
||||||
4. Replace hardcoded recent activity with real data OR remove
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### High Priority Items
|
|
||||||
|
|
||||||
1. Add "Needs Attention" widget
|
|
||||||
2. Implement real recent activity log
|
|
||||||
3. Add error/warning alerts display
|
|
||||||
4. Add real-time or polling updates
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Medium Priority Items
|
|
||||||
|
|
||||||
1. Show pipeline queue depth (items at each stage)
|
|
||||||
2. Add automation status display
|
|
||||||
3. Add site health/sync indicator
|
|
||||||
4. Make Quick Actions contextual
|
|
||||||
5. Fix completion percentage formula
|
|
||||||
6. Integrate Setup Completion Checklist
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Files to Create
|
|
||||||
|
|
||||||
| File | Purpose |
|
|
||||||
|------|---------|
|
|
||||||
| `components/dashboard/NeedsAttention.tsx` | Alerts widget |
|
|
||||||
| `components/dashboard/AutomationStatus.tsx` | Automation summary widget |
|
|
||||||
| `components/dashboard/RecentActivity.tsx` | Real activity log |
|
|
||||||
| Backend: `api/views/dashboard.py` | Aggregated endpoint |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Files to Modify
|
|
||||||
|
|
||||||
| File | Changes |
|
|
||||||
|------|---------|
|
|
||||||
| `pages/Dashboard/Home.tsx` | Complete revamp with new layout |
|
|
||||||
| `components/dashboard/CreditBalanceWidget.tsx` | Connect to billingStore single source |
|
|
||||||
| `components/dashboard/WorkflowProgress.tsx` | Add queue depth indicators |
|
|
||||||
| `components/dashboard/QuickActions.tsx` | Add contextual logic |
|
|
||||||
| `components/dashboard/KeyMetrics.tsx` | Connect to aggregated API |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Backend Work Required
|
|
||||||
|
|
||||||
| Area | Work |
|
|
||||||
|------|------|
|
|
||||||
| Aggregated API | Create `/v1/dashboard/summary/` endpoint |
|
|
||||||
| Activity Logging | Ensure all actions are logged for activity feed |
|
|
||||||
| Alert Aggregation | Collect alerts from all modules |
|
|
||||||
| Pipeline Counts | Query for items at each workflow stage |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
|
|
||||||
**Dashboard should be implemented LAST because it depends on:**
|
|
||||||
|
|
||||||
- Section 2 (SETUP): Setup Completion Checklist
|
|
||||||
- Section 3 (WORKFLOW): Pipeline data, activity logging
|
|
||||||
- Section 4 (ACCOUNT): Credit balance single source of truth
|
|
||||||
- Section 6 (Navigation): Consistent navigation patterns
|
|
||||||
|
|
||||||
---
|
|
||||||
Reference in New Issue
Block a user