Files
teknav-bak/app/docs/superpowers/plans/2026-05-02-phase11-track1.md
T
arsam e9cd12dda6 Import remaining project documentation and reference notes
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
2026-09-18 23:33:04 +03:30

160 lines
6.3 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 11 Track 1 Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Close 5 functional gaps in the Teknav Admin Panel where backend support is already present but UI wiring is missing.
**Architecture:** Modify existing React components in `teknav-admin.jsx` to add form fields, filters, dedicated tabs, and bulk operation controls.
**Tech Stack:** React 18, Fastify (Backend), Prisma, custom CSS-in-JS (via `teknav-ui.jsx`).
---
### Task 1: Article Editor Flags Toggles
**Files:**
- Modify: `teknav-admin.jsx`
- [ ] **Step 1: Locate flags group in ArticleEditor**
Find the "نشانه‌گذاری" group in the `ArticleEditor` component (approx line 1500-1600).
- [ ] **Step 2: Add toggles for premiumOnly, sponsored, and featured**
Update the array of flags to include all three fields. Ensure `premiumOnly` uses a lock icon, `sponsored` uses a star/badge, and `featured` uses a star.
```javascript
// Inside ArticleEditor flags group
{[
{ key: 'premiumOnly', label: 'فقط اعضای ویژه', icon: '🔒' },
{ key: 'sponsored', label: 'محتوای حمایت‌شده', icon: '⭐' },
{ key: 'featured', label: 'مقاله ویژه', icon: '★' },
].map(({ key, label, icon }) => (
<div key={key} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
<label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, color: '#263238', cursor: 'pointer' }}>
<span style={{ fontSize: 14 }}>{icon}</span>
<span>{label}</span>
</label>
<button
type="button"
onClick={() => set(key, !form[key])}
style={{
width: 44, height: 24, borderRadius: 12, border: 'none', cursor: 'pointer',
background: form[key] ? BRAND.primary : '#D0CCC5',
position: 'relative', transition: 'background 0.2s', flexShrink: 0,
}}
>
<span style={{
position: 'absolute', top: 3, width: 18, height: 18, borderRadius: '50%', background: '#fff',
transition: 'inset-inline-start 0.2s',
insetInlineStart: form[key] ? 23 : 3,
}} />
</button>
</div>
))}
```
- [ ] **Step 3: Verify form state update**
Ensure `handleSave` correctly includes these new boolean fields in the `data` object sent to `adminApi.createArticle` or `adminApi.updateArticle`.
- [ ] **Step 4: Manual verification**
Open a "Published" article in the editor, toggle "Premium Only", save, and verify it persists (check local browser network tab).
---
### Task 2: Content Freshness Filter
**Files:**
- Modify: `teknav-admin.jsx`
- [ ] **Step 1: Locate filter bar in ArticlesManagement**
Find the `ArticlesManagement` component and its filter inputs (approx line 300-400).
- [ ] **Step 2: Add freshness filter dropdown**
Add a new `<select>` for `freshnessFilter` with options: همه | به‌روز | نیاز به بازنگری | قدیمی.
```javascript
<select value={freshnessFilter} onChange={e => setFreshnessFilter(e.target.value)} style={{ ...inputStyle, maxWidth: 180 }} dir="rtl">
<option value="">همه تازگی‌ها</option>
<option value="up_to_date">به‌روز</option>
<option value="needs_update">نیاز به بازنگری</option>
<option value="outdated">قدیمی</option>
</select>
```
- [ ] **Step 3: Update filtering logic**
Ensure `filtered` useMemo includes the freshness filter logic:
```javascript
if (freshnessFilter) list = list.filter(a => a.contentFreshnessStatus === freshnessFilter);
```
- [ ] **Step 4: Manual verification**
Change the dropdown value and ensure the table updates to show only articles with the matching status.
---
### Task 3: Dedicated SEO Audit Tab
**Files:**
- Modify: `teknav-admin.jsx`
- [ ] **Step 1: Register new tab in SIDEBAR_ITEMS**
Add `{ id: 'seo-audit', label: 'ممیزی SEO', icon: '◈' }` to the `admin` role in `SIDEBAR_ITEMS`.
- [ ] **Step 2: Update AdminPanel to handle 'seo-audit' tab**
In the main `AdminPanel` render loop, add a case for `activeTab === 'seo-audit'`.
- [ ] **Step 3: Move SeoAuditPanel rendering**
Ensure `SeoAuditPanel` is rendered as the primary component for the new tab.
- [ ] **Step 4: Manual verification**
Click the "SEO Audit" item in the sidebar and verify it renders the full audit table.
---
### Task 4: Engagement Analytics Enhancements
**Files:**
- Modify: `teknav-admin.jsx`
- [ ] **Step 1: Expand EngagementAnalyticsPanel**
Enhance the existing `EngagementAnalyticsPanel` to show more detail.
- [ ] **Step 2: Add 7-day event count chart**
Re-use `WeeklyChart` or the area-SVG pattern to visualize `engagement.weeklyData`.
- [ ] **Step 3: Add Top 5 articles table**
Render `engagement.topArticles` in a simple list or table.
- [ ] **Step 4: Manual verification**
Open Analytics -> Engagement tab and verify charts and tables populate with real data.
---
### Task 5: Bulk Comment Moderation UI
**Files:**
- Modify: `teknav-admin.jsx`
- [ ] **Step 1: Add selection state to CommentsModeration**
Ensure `selected` Set state is active (it seems partially present in the current code section).
- [ ] **Step 2: Add floating action bar**
Render the bulk action bar at the bottom of the screen when `selected.size > 0`.
```javascript
{selected.size > 0 && (
<div style={{ position: 'fixed', bottom: 24, left: '50%', transform: 'translateX(-50%)', background: BRAND.ink, color: '#fff', borderRadius: 14, padding: '12px 20px', display: 'flex', alignItems: 'center', gap: 12, zIndex: 600 }}>
<span style={{ fontWeight: 700 }}>{selected.size.toLocaleString('fa-IR')} مورد انتخاب شده</span>
<button onClick={() => bulkAction('delete')} style={bulkBtnStyle}>حذف</button>
<button onClick={() => bulkAction('approve')} style={bulkBtnStyle}>تأیید</button>
<button onClick={() => setSelected(new Set())}>لغو</button>
</div>
)}
```
- [ ] **Step 3: Wire bulkAction to API**
Call `adminApi.bulkModerateComments(ids, action)` and refresh the list.
- [ ] **Step 4: Manual verification**
Check 2-3 comments, click "Approve", and verify they are processed and the selection is cleared.