Files
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

342 lines
26 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PHASES.md
Completion log. Active work and future roadmap live in `ARCH.md`.
## Current Production Baseline
Teknav is a Persian RTL Vite/React SPA backed by Fastify, Prisma, PostgreSQL, Redis, Argon2id sessions, CSRF, Persian search, SEO artifacts, admin CMS APIs, media uploads, scheduled publishing, SMTP email flows, and Kavenegar OTP. Production deployment is native Linux/systemd with nginx on `https://www.teknav.ir`; Docker is not the current deployment target.
## Phase 1 - Frontend: Zero CDN + Vite
Shipped.
- Vite 5 + React 18.3.1 with ES modules.
- Removed unpkg, Google Fonts, and CDN scripts.
- Local font loading from `public/fonts/`.
- `scripts/check-no-cdn.mjs` runs on `npm run build`.
- Dev/preview port is locked to `3009`.
## Phase 2 - Database + Seed
Shipped.
- Backend workspace in `backend/`.
- Prisma schema for users, authors, categories, tags, articles, reactions, saved articles, newsletter subscribers, activity logs, and media assets.
- Persian FTS function/indexes are applied idempotently from `backend/prisma/seed.ts`.
- Seed imports `teknav-data.js`, hashes credentials with Argon2id, and creates the three real Teknav authors.
- Staff seed credentials live in `backend/prisma/credentials.json`; operator-facing credentials live in ignored `ACCOUNTS.md`.
## Phase 3 - Auth
Shipped.
- Redis-backed sessions with `tek_sid` and `tek_csrf`.
- Login/logout/me APIs in `backend/src/routes/auth.ts`.
- CSRF middleware for mutating routes.
- Login/signup captcha and per-IP rate limiting.
- Frontend `AuthProvider` uses `/api/v1/auth/*` on the wire; no localStorage auth source.
## Phase 4 - Public API + Caching
Shipped.
- Public articles, categories, tags, authors, search, newsletter, save, and reaction APIs.
- Redis response caching, search caching, newsletter rate limiting, and buffered article view counters.
- Public pages use `src/lib/content-api.js`.
## Phase 5 - Admin/CMS API
Shipped.
- Role-gated article CRUD, publish, schedule, category/tag/user/author management, uploads, activity logs, and dashboard metrics.
- Admin panels use `src/lib/admin-api.js` and show real API data only.
- No mock/example data should appear in admin, writer, reviewer, media, activity, or dashboard views.
- Media uploads are tracked in `MediaAsset`; admin/editor media library is backed by `/api/v1/admin/media`.
## Phase 6 - Native Deployment
Shipped.
- Production runbook: `DEPLOY.md`.
- nginx templates: `nginx/nginx.conf.example` and `nginx/nginx.default.conf`.
- systemd assets: `deploy/systemd/teknav-backend.service`, `teknav-migrate.service`, `teknav-publish-due.service/.timer`, and `teknav-backup.service/.timer`.
- Log rotation: `deploy/logrotate/teknav`.
- Backups: `scripts/systemd-backup.sh`.
- Schema application: `backend/scripts/apply-schema.mjs` via `npm run prisma:apply`.
## Phase 7 - Production CMS Readiness
Shipped.
- Public profiles and profile editing.
- Avatar uploads and WebP conversion support.
- HTML article editor with image upload.
- Email verification and password reset via SMTP.
- Phone OTP via Kavenegar.
- Article scheduling and due-publish timer.
- Activity CSV export.
- Persian SEO metadata, canonical `www.teknav.ir`, sitemap, robots, and RSS feed.
- Three writer-admin seed accounts added for آرسام صباغ, رادمان قلیچی, and سیداحمدرضا محجوب.
## Phase 8 - Engagement + Real-Time Admin
Implemented; Linux validation pending.
- Prisma schema adds comments, comment flags, reading history, notifications, and writer follows.
- Article pages include real API-backed comments/replies, flagging, history tracking, and comment count.
- Header notifications use authenticated SSE at `/api/v1/auth/notifications/stream`.
- Writer profiles expose follower count and follow/unfollow; own profile shows reading history and followed writers.
- Admin/editor dashboard uses SSE at `/api/v1/admin/stream` for active visitors, activity, and live view counter updates.
- Admin/editor comments panel supports flagged filtering, delete, and clear-flag actions.
- nginx templates disable buffering/compression for SSE stream paths.
## Phase 9 - Content Modernization + Publication Features
Implemented. Linux production validation pending.
- Prisma schema adds article SEO fields, daily article view logs, comment likes, newsletter campaigns, article series, editorial review workflow, and reading lists.
- Public API adds related articles, series pages, newsletter unsubscribe, comment likes, and reading-list endpoints.
- Admin API adds analytics, review queue, newsletter campaign send/list, and series CRUD endpoints.
- Frontend article pages consume richer SEO metadata, expose comment likes, keep related articles API-backed, and route public series pages at `/series/:slug`.
- Admin panel adds API-backed Phase 9 sections for analytics, review workflow, newsletter campaigns, and article series.
- `teknav-data.js` finalizes Phase 9 seed/reference metadata: 23 published articles, refreshed dates, canonical paths, Open Graph metadata, and generated content for former placeholders.
- `scripts/generate-seo.mjs` now uses `dateModified`, canonical paths, meta descriptions, and RSS `content:encoded`.
- `scripts/generate-og-images.mjs` provides local OG image generation for article cards; install dependencies on Linux before use.
- Series prev/next navigation banner added to article pages (`SeriesNavBanner`), pulling live series membership from the public article API.
## Phase 10 - SEO Growth, Trust, and Writer Studio
Implemented. Linux production validation pending.
### SEO and trust foundations
- Public topic authority hubs at `/topics/ai`, `/topics/security`, `/topics/software`, `/topics/hardware`, `/topics/startups`, and `/topics/data` with `CollectionPage`, `FAQPage`, `ItemList`, and `BreadcrumbList` JSON-LD.
- `scripts/generate-seo.mjs` covers topic hubs, public author profiles, glossary terms, newsletter archive, and `/ACCOUNTS.md` robots blocking.
- Prisma schema adds editorial trust fields (`factCheckedAt`, `reviewedById`, `sourceNotes`, `contentFreshnessStatus`), `TopicFollow`, newsletter campaign slugs, and the first-party `AnalyticsEvent` table.
- First-party analytics events for article views, newsletter subscriptions, saves, writer/topic follows, and share clicks.
- Topic follows at `/api/v1/topics/:slug/follow` with counts on hub pages.
- Public newsletter archive at `/newsletter` and `/newsletter/:slug`.
- Role-aware panel metrics at `GET /api/v1/admin/panel-metrics`.
- Article approval-to-publish quality gates: review workflow, Phase 10 metadata completion, cache refresh, and writer/topic follower notifications.
- Public tag pages and `GET /api/v1/articles?tag=...`.
- Admin API adds `GET /api/v1/admin/seo/audit`, `GET /api/v1/admin/analytics/content`, `GET /api/v1/admin/analytics/newsletter`, `GET /api/v1/admin/analytics/engagement`.
- `npm run smoke:prod` production health checks.
### Community and retention
- PWA with `manifest.json`, service worker, offline caching, and install prompt.
- Personalized home feed (`sort=personalized`) using followed topics, followed writers, and read history.
- Comment upvoting with best-comment sorting; expanded heart/fire/thinking reactions.
- 5-day reading streaks and "Continue Reading" progress tracking.
- Threaded article Q&A at `/api/v1/articles/:slug/qa`.
- Glossary/dictionary term pages at `/glossary/:slug`.
- "X vs Y" comparison templates with responsive comparison-table styling.
### Auth and trust
- Google/GitHub OAuth at `/api/v1/auth/oauth/:provider`.
- SMS 2FA via Kavenegar OTP; `tek_2fa` ticket-based login completion.
- Verified expert badges on author records, profiles, lists, and article bylines.
- Published article corrections/errata via `ArticleCorrection`.
- Google Discover readiness: 1200×630 local hero images, `fetchPriority="high"`, `max-image-preview:large`.
### Monetization foundations
- `/jobs` with `JobListing` and company submission API.
- `/courses` with course API and public page.
- `/membership` premium membership page.
- `User.membershipTier`, `Article.premiumOnly`, content locking for non-premium readers.
- `Article.sponsored` and public "Promoted Content" labels.
### Operations
- Global Fastify rate limiting.
- Bulk comment moderation.
- First-party client error capture at `/api/v1/errors`.
- `backend/tests/phase10-smoke.test.mjs` for auth/article/comment smoke coverage.
- Weekly newsletter digest job: `npm run newsletter:digest` and `teknav-weekly-digest.timer`.
### Writer Studio V5 (close-out polish)
- HtmlEditor toolbar: grouped buttons (Formatting | Headings | Inline+Block | Lists | Media) with hover states; Bold/Italic labels styled; keyboard shortcuts Ctrl+B, Ctrl+I in editor and Ctrl+S to save draft globally.
- Live word count and character count footer on the editor textarea.
- WritingTipCard: manual prev/next navigation with position counter; auto-advance timer resets on manual nav.
- ArtifactStudio diagram library: gradient placeholder cards replaced with live scaled `DiagramRenderer compact` mini-previews.
- ArtifactStudio code mode: relabelled "code preview" with empty-state hint; was falsely claiming "live preview".
- WeeklyChart data pipeline fixed: was reading non-existent `weeklyViews`; now correctly uses `viewsByDay.slice(-7).map(d => d.views)`.
- Analytics sparklines upgraded: full-width filled-area SVG with gradient, dot on latest point, "۳۰ روز پیش → امروز" axis labels.
- Analytics table: sparklines prefetched for all articles on mount; inline 80×20 mini-sparkline per row; totals footer row; column header corrected to "روند اخیر".
- Overview tab: amber `needsRevision` banner when reviewer has flagged articles; dynamic time-of-day greeting (صبح/ظهر/عصر/شب بخیر) with matching tagline.
- Article editor meta-panel: fields grouped into "اطلاعات پایه", "زمان‌بندی", and collapsible "سئو پیشرفته" sections; slug field added to SEO section.
- Article editor preview mode: renders selected diagram (`DiagramRenderer`) and subtitle above content.
- Article editor: dirty-state indicator (● ذخیره نشده · Ctrl+S) shown when form has unsaved changes.
- Article editor: amber "بازخورد ویراستار" banner when opening a `نیازمند اصلاح` article that has a reviewer note.
- Articles list: hard cap of 15 replaced with show-more/less pagination button; reviewer note shown inline for revision-flagged rows.
- Overview recent-articles: reviewer note shown inline for `نیازمند اصلاح` articles.
- Comments tab: article title chip next to commenter name; "8-recent" cap note with redirect to article; button relabelled to direct to full comment thread.
- Backend: `articleInclude` joins `review { note, status }`; `publicArticle` exposes `reviewNote`; this flows through writer dashboard, articles list, and editor.
## Phase 11 — Platform Completeness
Implemented. Linux production validation pending.
### Track 1 — Admin completeness
- Sponsored / premiumOnly / featured toggle buttons in `ArticleEditor` meta-panel (flags group).
- Content freshness filter dropdown (`current` / `needs_update` / `scheduled_refresh` / `archived`) in articles management list.
- Dedicated SEO audit tab in AdminPanel — full paginated table with severity badges (خطا/هشدار/پیشنهاد) and per-article links; removed hard-capped inline audit from analytics panel.
- Dedicated engagement analytics sub-tab inside analytics panel — 7-day bar chart, event-type breakdown table, top-5 articles.
- Bulk comment moderation: checkbox per row, floating action bar (حذف/تأیید/علامت‌گذاری/لغو انتخاب), wired to existing `POST /api/v1/admin/comments/bulk`.
### Track 2 — Reader UX
- Article card reading list picker: bookmark icon (admin only for logged-in users) opens `ReadingListModal` from any card on the home feed.
- Continue-reading progress overlay: progress bar + "ادامه مطالعه" chip on home feed cards when user has 5–95% progress via `engagementApi.getStreaks()`.
- Scheduled-publish topic notifications: `backend/scripts/publish-due.mjs` now also queries `TopicFollow` for the article's category and notifies topic followers (deduped against writer-follow notifications).
- Google Search Console and Bing Webmaster placeholder verification files in `public/` (`google-token-placeholder.html`, `BingSiteAuth.xml`).
### Track 3 — Monetization
- Premium gate card redesign: blurred/faded content with `mask-image` gradient, `PremiumGateCard` component with crown icon, 3-bullet benefit list, "عضویت ویژه" CTA, and "ورود به حساب" secondary for unauthenticated users.
- Zarinpal membership subscription flow: `POST /api/v1/membership/subscribe` → Zarinpal payment request → gateway redirect; `GET /api/v1/membership/callback` → verify → upgrade `User.membershipTier='premium'` + `membershipExpiresAt` + `Notification`; `GET /api/v1/membership/status`; `MembershipPage` wired with live status and subscribe button; `MembershipSuccessPage` at `/membership/success`.
- Job listing admin panel: `GET /api/v1/admin/jobs` (with status filter) and `PATCH /api/v1/admin/jobs/:id` (approve/reject/featuredUntil) in `monetization.ts`; `JobsPanel` component in admin sidebar; `JobListing.featuredUntil` field added to schema.
- Premium enforcement confirmed: `publicArticle()` in `public.ts` already strips body and sets `premiumLocked: true` for non-premium users on `premiumOnly` articles.
### Track 4 — Reliability
- `ClientError` Prisma model: persists client errors from `POST /api/v1/errors` (was logging-only); `GET /api/v1/admin/errors` returns top-10 messages by count, daily counts (30 days), and 20 most recent raw errors; `ClientErrorsPanel` admin tab with daily sparkline, top-errors table, recent errors list.
- `StorageAdapter` interface in `backend/src/lib/storage.ts`: `LocalStorageAdapter` (default, active on `STORAGE_BACKEND=local` or unset — all uploads go to `config.UPLOAD_DIR`), `S3StorageAdapter` stub (activate with `STORAGE_BACKEND=s3`; not yet wired to a real S3 client). Upload handler in `admin.ts` switched to use the adapter.
- Schema additions: `ClientError`, `MembershipPayment`, `JobListing.featuredUntil`, `NotificationType.system`.
### Data completeness
- `teknav-data.js` expanded to 32 articles (`art1`–`art32`) with full content via `article-contents-*.js` files; all `contentFreshnessStatus` values corrected from `fresh`/`stable` to `current`.
## Phase 12 — Web Push + Published Article Editing
Implemented. Linux production validation pending (VAPID keys + `web-push` install + `PushSubscription` schema apply).
### Web push notifications
- `PushSubscription` Prisma model: `id`, `userId`, `endpoint` (unique), `auth`, `p256dh`, `userAgent`, `createdAt`; `@@index([userId])`; cascade-delete on user removal.
- `backend/src/lib/push.ts`: VAPID init guarded by env var presence (no-op if unconfigured); `buildPushPayload()` maps all 8 `NotificationType` values to Persian `{title, body, url, icon}`; `sendPushToUser()` queries subscriptions, sends via `web-push`, auto-deletes expired (410) endpoints.
- Three new authenticated routes in `notifications.ts`: `GET /api/v1/auth/push/vapid-key` (returns public key), `POST /api/v1/auth/push/subscribe` (upsert by endpoint), `DELETE /api/v1/auth/push/unsubscribe`.
- `createNotification()` in `realtime.ts` extended: fire-and-forget `sendPushToUser()` call after SSE publish; in-app notification path unchanged.
- Service worker: `push` event handler shows RTL/Persian notification with badge; `notificationclick` handler focuses existing window or opens new one at `data.url`.
- `pushApi` client in `engagement-api.js`: `getVapidKey()`, `isSubscribed()`, `subscribe()`, `unsubscribe()` with CSRF token from cookie.
- `PushNotificationPrompt` dismissible banner in `teknav-ui.jsx`: shown to authenticated users when `Notification.permission === 'default'` and not previously dismissed; bottom-right dark overlay, RTL.
- Push toggle in `ProfileSettingsModal` (`teknav-profile.jsx`): handles enabled / blocked / unsupported states; calls `pushApi.subscribe()` / `unsubscribe()`.
### Published article editing
- `ArticleEditor` accepts `role` prop (default `'writer'`); derives `isPublished` and `canPublishDirectly` (true for admin/editor).
- Info banners: blue for writers (changes go to draft/review), green for admin/editor (direct publish with Ctrl+S note).
- Button set branches: admin/editor on published article → "بروزرسانی و انتشار" / "تبدیل به پیش‌نویس" / "زمان‌بندی مجدد"; writer on published article → "ذخیره پیش‌نویس" / "ارسال برای بررسی مجدد".
- Backend PATCH bug fixed in `admin.ts`: removed `PUBLISHED → PENDING` conversion in bulk data update; `requestedStatus === PUBLISHED` is now excluded from the initial DB write and handled cleanly by the existing `publishArticleWithPhase10Checks()` block (preserves original `publishedAt`, runs quality gates).
- `quality_check_failed` (409) error surfaced in `ArticleEditor` save handler — shows specific issue list via toast.
### Bug fixes
- `scripts/generate-seo.mjs`: local `xml` variable inside `url()` function renamed to `lines`; was shadowing the outer `xml()` HTML-escape function, causing image titles to not be escaped.
## Phase 13 — Community Depth + Writer Tools
Implemented. Linux production validation pending (requires `prisma:apply` for new schema additions).
### Schema additions
- `PushSubscription.userId` made nullable (supports guest subscriptions); `topics String[]` array added.
- `NotificationPreference` model: per-user, per-eventType, per-channel (push/email/sms) opt-out toggle; defaults to enabled.
- `UserBadge` model: earned reading badges (AI enthusiast, streak-7, etc.) with `@@unique([userId, badgeType])`.
- `ArticleRevision` model: content snapshot before each article PATCH, capped at 20 per article.
### Web Push for guests
- `POST /api/v1/push/guest-subscribe` (unauthenticated, IP-rate-limited 5/min): stores `PushSubscription` with `userId=null` and `topics` array.
- `DELETE /api/v1/push/guest-unsubscribe`: removes guest subscription by endpoint.
- `GET /api/v1/push/vapid-key`: unauthenticated VAPID public key endpoint.
- `backend/src/lib/push.ts`: `sendGuestPushByTopic(topic, payload)` fans out to `userId IS NULL AND topics @> [topic]`.
- `backend/scripts/publish-due.mjs`: after notifying registered topic followers, also calls `sendGuestPush` for each published article's topic.
- Topic hub pages (`teknav-pages.jsx`): "🔔 دریافت اعلان مقالات" button next to follow button; works without login; persists in browser push subscription.
### Fine-Grained Notification Center
- `GET /api/v1/auth/notifications/preferences`: returns full 8×3 matrix (eventType × channel) with enabled state (default true for unset).
- `PUT /api/v1/auth/notifications/preferences`: batch upsert via `@@unique([userId, eventType, channel])`.
- `sendPushToUser()` in `push.ts` now checks `NotificationPreference` for `channel='push'` before delivering — honors user opt-out.
- `NotificationPreferencesPanel` collapsible section in `ProfileSettingsModal`: toggle grid with inline optimistic updates.
### Verified Reader Badges
- Badge rules: `ai_enthusiast`, `security_expert`, `data_scientist`, `hardware_geek`, `software_craftsman`, `startup_explorer` (10 articles read in topic), plus `streak_7` and `streak_30` (streak count).
- Evaluation runs in `publish-due.mjs` cron — NOT on the article-view hot path.
- `GET /api/v1/auth/badges` and `GET /api/v1/admin/users/:id/badges` endpoints.
- `engagementApi.listBadges()` client method.
### Article Version History
- `ArticleRevision` snapshot created before every PATCH update in `admin.ts` (captures title, content, summary, status, savedById).
- Pruned to 20 most recent per article at write time.
- `GET /api/v1/admin/articles/:id/revisions` (paginated list, no content), `GET /api/v1/admin/articles/:id/revisions/:revisionId` (with full content), `POST /api/v1/admin/articles/:id/revisions/:revisionId/restore` (admin/editor only; snapshots current state before restoring).
- `RevisionDrawer` side-panel in `ArticleEditor`: lists revisions with date/author/status; click to preview content; "بازیابی این نسخه" restores for admin/editor.
- `revisionsApi` client in `engagement-api.js`.
### Collaborative Editing Presence
- Heartbeat: `POST /api/v1/admin/articles/:id/heartbeat` sets `Redis SET presence:article:{id}:user:{uid}` with 45s TTL.
- `GET /api/v1/admin/articles/:id/presence`: SCAN + MGET, enriches with user name/avatar from DB.
- `ArticleEditor` fires heartbeat on mount and every 30s; polls presence every 30s.
- Shows avatar-chip row in editor header when 2+ editors are online on the same article.
- `presenceApi` client in `engagement-api.js`.
## Production Follow-Ups
- On Linux: run `npm run preflight:prod`, then `cd backend && npm run prisma:generate && npm run prisma:apply && npm run seed`, then frontend SEO/OG generation, frontend/backend builds, strict backend endpoint tests, and `npm run smoke:prod`.
- Verify all flows after schema apply: auth, comments/likes/flags, history, notifications/SSE, reading lists, topic/writer follows, tag pages, series pages, topic hubs, newsletter archive/campaigns, review workflow, analytics endpoints, panel metrics, first-party events.
- Rotate all seed/admin passwords after first production login.
- Remove `resetPasswordOnSeed` from writer-admin credentials after rotation.
- Confirm SMTP and Kavenegar credentials on the server before sending emails/OTPs.
## Post-Phase 13 Production Hardening
Implemented.
- Added root `.env.prod.example` for `/etc/teknav/backend.env`, covering database, Redis, sessions, CORS, uploads, SMTP, SMS, VAPID, Zarinpal, and local storage defaults.
- Added `npm run preflight:prod` via `scripts/production-readiness.mjs` to catch missing templates, nginx SSE/credential-protection regressions, generated Prisma engine artifacts, and missing test coverage before deployment.
- Added `backend/tests/public-contract.test.mjs` for public/anonymous API contract checks, and made smoke tests strict with `TEST_REQUIRE_SERVER=1` when a running backend must be validated.
- Added minimal public `/api/v1/health`, added `/api/v1/ready` dependency readiness, and added admin-only `/api/v1/admin/health` diagnostics with non-secret feature flags.
## Phase 14 — Farsi Knowledge & Tech Ecosystem
Implemented. Linux production validation pending (`CREATE EXTENSION vector`, `prisma:apply`).
- **Wiki & Glossary Proposals:** `WikiProposal` and `GlossaryProposal` Prisma models; `POST /api/v1/wiki/proposals` and `PATCH /api/v1/admin/wiki/proposals/:id`; `DiffViewer` React component.
- **Automated Internal Linking Engine:** `link-engine.ts` with `cheerio`; injects `<a href="/glossary/:slug">` anchors into published articles.
- **Semantic Search & RAG:** `ArticleEmbedding` model; pgvector; `POST /api/v1/search/semantic`; `GET /api/v1/rag/:slug`.
- **LMS:** `LearningPath`, `LearningModule`, `Quiz`, `UserCertification` models; auto-certification at ≥80% pass score.
- **Tech Directory (backend):** `CompanyProfile`, `CompanyClaim` Prisma models; `DirectoryPanel` admin UI.
- Production note: requires `CREATE EXTENSION vector` as PostgreSQL superuser before `prisma:apply`.
## Phase 15 — Viewership & Top-of-Funnel Scaling
Implemented. Build verified: 0 CDN refs, 0 preflight failures.
**15A — Web Stories:**
- CSS scroll-snap story pages for all published articles at `dist/stories/{slug}/index.html`.
- OG + Twitter Card meta tags on each story page; keyboard navigation (arrow keys).
- `sitemap-stories.xml` added to sitemap index; `<link rel="alternate">` on every article page.
- `scripts/generate-web-stories.mjs` — build script; runs after `generate-article-pages`.
**15B1 — Quote Card Sharer:**
- `src/components/QuoteSharer.jsx` — Selection API tooltip, Canvas 1080×1080 branded card.
- RTL text wrapping, dark gradient, gold separator, Teknav branding.
- Actions: Web Share API → PNG download fallback, copy-to-clipboard (text + URL), Escape-to-close.
- Analytics: `contentApi.trackEvent({ type: 'share_clicked', metadata: { channel: 'quote_card' } })`.
- Mounted in `ArticleDetail` for non-premium, non-TekRAG articles.
**15B2 — Embeddable Widget System:**
- `embed.html` — second Vite rollup entry; `<meta name="robots" content="noindex,nofollow">`.
- `src/embed.jsx` — bootstrapper routing by URL path type.
- `src/widgets/GlossaryWidget.jsx` / `ArticleCardWidget.jsx` / `CompanyWidget.jsx` — dark mode, postMessage resize on height change only.
- `public/embed-loader.js` — third-party `<script>` snippet injecting sandboxed `<iframe>`.
- nginx: `/embed/` location with `frame-ancestors *` CSP.
**15C1 — Comparison Pages:**
- 10 comparisons in `TeknavData.comparisons`; `dist/compare/{slug}/index.html` with ItemList + FAQPage + BreadcrumbList JSON-LD.
- `ComparisonPage` — two-column pros/cons, use cases, verdict, localStorage vote widget, share button, `factCheckedAt`.
- `ComparisonsListPage` at `/compare` with search/filter.
- Related comparisons block auto-injected on article pages.
- `scripts/generate-comparison-pages.mjs`.
**15C2 — Tech Directory:**
- 10 companies in `TeknavData.companies`; `dist/directory/{slug}/index.html` with Organization + BreadcrumbList JSON-LD.
- `DirectoryListPage` + `CompanyProfilePage` with claim button.
- `GET /api/v1/directory/companies` and `GET /api/v1/directory/companies/:slug` in `backend/src/routes/directory.ts`.
- `scripts/generate-company-pages.mjs`.
**Additional:**
- `StoriesListPage` at `/stories` — 9:16 thumbnail grid with title + category overlay, opens story in new tab.
- Footer "ابزارها" nav section: compare, stories, directory, glossary, tools.
- Profile badge display — 8 badge types from `engagementApi.getBadges()`.
- art37 `vibe-coding-mcp-2026` — 14-section Persian article on Vibe Coding + MCP (9 h2 sections, 14KB).