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

20 KiB
Raw Permalink Blame History

ARCH.md

Living roadmap and current work status. Detailed completed phase history is in PHASES.md; durable project facts are in MEMORY.md.

Current Focus

Phase 15 implemented — Viewership & Top-of-Funnel Scaling. Next step: Linux production validation of Phase 14 schema (pgvector, LMS, Wiki), then content scaling (Phase 16 English /en/ directory blocked on LTR layout pass).

Core rules:

  • zero CDN dependencies
  • Persian/RTL UI
  • real backend APIs for all panels
  • no Docker deployment work unless explicitly requested
  • keep ACCOUNTS.md ignored and nginx-blocked

Recently Shipped

  • Phase 15 — Viewership & Top-of-Funnel Scaling:

    • 15A: Web Stories — CSS scroll-snap story pages for all 34 published articles at dist/stories/{slug}/, sitemap-stories.xml, OG + Twitter Card meta tags, keyboard navigation (arrow keys), <link rel="alternate"> on all article pages. Zero-CDN (AMP replaced with native scroll-snap format).
    • 15B1: Quote Card Sharer — src/components/QuoteSharer.jsx: Selection API floating tooltip, Canvas 1080×1080 branded card with RTL text wrapping, Web Share API (with PNG download fallback), copy-to-clipboard (Persian text + article URL), Escape-to-close, analytics event via contentApi.trackEvent.
    • 15B2: Embeddable Widget System — embed.html second Vite entry, src/embed.jsx bootstrapper, 3 widgets (GlossaryWidget, ArticleCardWidget, CompanyWidget) with dark mode (prefers-color-scheme) and postMessage resize only on height change; public/embed-loader.js third-party snippet; nginx /embed/ X-Frame-Options exception.
    • 15C1: Comparison Pages — 10 comparisons in TeknavData.comparisons (react-vs-vue, postgresql-vs-mongodb, docker-vs-podman, next-js-vs-remix, claude-vs-gpt, python-vs-rust, postgresql-vs-mysql, fastapi-vs-django, kubernetes-vs-docker-compose, tailwind-vs-css-modules); dist/compare/{slug}/ with ItemList + FAQPage + BreadcrumbList JSON-LD; ComparisonsListPage; ComparisonPage with localStorage vote widget (no backend) and share button; factCheckedAt display; related comparisons block on article pages.
    • 15C2: Tech Directory — 10 companies in TeknavData.companies (virgool, divar, snapp, zarinpal, faraname, quera, cafebazaar, tapsi, basalam, sheypoor); dist/directory/{slug}/ with Organization + BreadcrumbList JSON-LD; DirectoryListPage + CompanyProfilePage; GET /api/v1/directory/companies and GET /api/v1/directory/companies/:slug public endpoints; CompanyWidget with static fallback.
    • Content: art37 vibe-coding-mcp-2026 — 14-section Persian article on Vibe Coding + MCP protocol.
    • StoriesListPage at /stories — 9:16 thumbnail grid with title + category overlay.
    • Footer nav updated with Tools section (compare, stories, directory, glossary, tools).
    • Profile badges — engagementApi.getBadges() displays 8 badge types on user profiles.
    • preflight:prod: 0 failures.
  • Production hardening & validation pass:

    • Fixed Fastify schema validation error mapping: Moved app.setErrorHandler early in the fastify server lifecycle to ensure it propagates down to routes/plugins. Added validation error mapping so FST_ERR_VALIDATION / err.validation !== undefined errors return invalid_input to comply with frontend API requirements and contract tests.
    • Resolved public mutating endpoints test failures; all contract tests are now passing 100% on Linux.
    • Updated production Nginx site configurations (/etc/nginx/sites-available/teknav) to serve all pre-rendered semantic folders (/category/, /tag/, /glossary/, /topics/, /series/, /author/, /profile/) and static pages (/en/, /articles/, /privacy/, etc.) directly from disk using gzip_static on and brotli_static on, avoiding redirect loops and dynamic sub_filter cost.
    • Added root .env.prod.example aligned with /etc/teknav/backend.env for PostgreSQL, Redis, sessions, CORS, uploads, SMTP, SMS, VAPID, Zarinpal, and storage.
    • Added npm run preflight:prod (scripts/production-readiness.mjs) to check env/docs/nginx/script readiness, credential exposure, generated Prisma engine artifacts, and migration/test posture.
    • Added backend public contract tests in backend/tests/public-contract.test.mjs; existing smoke tests now auto-skip when no API is running and become strict with TEST_REQUIRE_SERVER=1.
    • /api/v1/health returns minimal public health; /api/v1/ready returns 503 when PostgreSQL or Redis is unavailable; /api/v1/admin/health exposes authenticated diagnostics, feature flags, and uptime.
  • Phase 14 — Farsi Knowledge & Tech Ecosystem (implemented this session):

    • Wiki & Glossary Proposals: WikiProposal and GlossaryProposal Prisma models; POST /api/v1/wiki/proposals and PATCH /api/v1/admin/wiki/proposals/:id; DiffViewer React component highlighting additions/deletions.
    • Automated Internal Linking Engine: link-engine.ts utilizing cheerio to scan HTML content of newly published articles and inject <a href="/glossary/:slug"> anchors to glossary terms safely.
    • Semantic Search & RAG: ArticleEmbedding Prisma model; pgvector extension; POST /api/v1/search/semantic for context-aware related articles; GET /api/v1/rag/:slug for machine-readable raw Markdown context extraction.
    • Learning Management System (LMS): LearningPath, LearningModule, Quiz, and UserCertification Prisma models; POST /api/v1/lms/quiz/:quizId/submit and GET /api/v1/lms/me; auto-issued student certificates (>=80 pass score); LmsPanel student dashboard UI.
    • Tech & Startup Directory: CompanyProfile and CompanyClaim Prisma models; interactive Farsi directory UI (DirectoryPanel); authenticated endpoint to claim company profiles with verification proof.
  • Phase 13 — Community depth + writer tools:

    • Guest push subscriptions: nullable userId on PushSubscription, topics String[], POST /api/v1/push/guest-subscribe (IP-rate-limited), sendGuestPushByTopic() in push.ts, publish-due.mjs fans out to guest subs, "🔔 دریافت اعلان" button on topic hub pages.
    • Fine-grained notification center: NotificationPreference model + GET/PUT /api/v1/auth/notifications/preferences; sendPushToUser() checks push preference before delivery; collapsible toggle grid in ProfileSettingsModal.
    • Verified reader badges: UserBadge model + 8 badge rules evaluated in publish-due.mjs cron; GET /api/v1/auth/badges + GET /api/v1/admin/users/:id/badges.
    • Article version history: ArticleRevision snapshot on every PATCH (capped at 20); GET/GET/POST /api/v1/admin/articles/:id/revisions[/:id[/restore]] in revisions.ts; RevisionDrawer side-panel in ArticleEditor with content preview and restore.
    • Collaborative presence: Redis TTL keys (presence:article:{id}:user:{uid}, 45s); POST /api/v1/admin/articles/:id/heartbeat + GET /api/v1/admin/articles/:id/presence; ArticleEditor polls every 30s; avatar chips shown when 2+ editors online.
  • Phase 12 — Web push notifications + published article editing:

    • Browser web push (RFC 8030/VAPID): PushSubscription Prisma model + relation on User; backend/src/lib/push.ts with sendPushToUser() fanning out to all user subscriptions, auto-cleaning expired (410) endpoints; GET /api/v1/auth/push/vapid-key, POST /api/v1/auth/push/subscribe, DELETE /api/v1/auth/push/unsubscribe routes in notifications.ts; createNotification() in realtime.ts extended with non-blocking push fan-out; service worker push + notificationclick handlers with Persian RTL options; pushApi client in engagement-api.js; PushNotificationPrompt dismissible banner in teknav-ui.jsx; push toggle (enabled/blocked/unsupported states) in ProfileSettingsModal.
    • Published article editing: ArticleEditor now accepts role prop and derives isPublished / canPublishDirectly; shows role-appropriate info banner and button set (admin/editor: "بروزرسانی و انتشار" / "تبدیل به پیش‌نویس" / "زمان‌بندی مجدد"; writer: "ذخیره پیش‌نویس" / "ارسال برای بررسی مجدد"); fixed critical backend bug in admin.ts PATCH route (was converting PUBLISHED → PENDING before the Phase10 quality-gate block, now skips status in the bulk update and lets publishArticleWithPhase10Checks() handle it cleanly); quality_check_failed error now surfaced in the editor save handler.
    • scripts/generate-seo.mjs variable-shadow bug fixed: local xml array inside url() renamed to lines so the outer xml() escape function is no longer shadowed.
    • DEPLOY.md updated: VAPID key generation block, three VAPID env vars in Section 6, VAPID private key security note, and "Web push not delivering" troubleshooting block.
  • Phase 11 — Platform completeness (implemented this session):

    • Track 1 admin quick wins: sponsored/premiumOnly/featured toggles in ArticleEditor; content freshness filter in article list; dedicated SEO audit tab (full paginated table); dedicated engagement analytics sub-tab with bar chart and event breakdown; bulk comment moderation with checkbox selection and floating action bar.
    • Track 2 reader UX: article card save-list picker (ReadingListModal wired to bookmark button); continue-reading progress overlay on home feed cards (progress bar + "ادامه مطالعه" chip); scheduled-publish notifications extended to topic followers; Google/Bing webmaster verification placeholder files in public/.
    • Track 3 monetization: premium gate card redesigned (blurred fade + crown icon + benefit list + dual CTA); Zarinpal membership subscription flow end-to-end (POST /api/v1/membership/subscribe → gateway redirect → GET /api/v1/membership/callback → tier upgrade + notification → /membership/success); job listing admin panel with approve/reject/featured actions; premium content enforcement confirmed in publicArticle().
    • Track 4 reliability: ClientError Prisma model + GET /api/v1/admin/errors aggregated admin view + admin "خطاهای کلاینت" tab with daily sparkline and top-errors table; StorageAdapter interface in backend/src/lib/storage.ts — LocalStorageAdapter is active (default, no env var needed), S3StorageAdapter stub activates with STORAGE_BACKEND=s3; upload route in admin.ts switched to use the adapter.
    • Schema additions: ClientError, MembershipPayment, JobListing.featuredUntil, NotificationType.system enum value.
    • 32 articles with complete metadata now in teknav-data.js; all contentFreshnessStatus values corrected to enum-valid values.
  • Phase 10 foundation: /topics/* authority hubs, public tag pages, topic/series/newsletter structured data, sitemap topic/profile/newsletter/tag coverage, topic follows, newsletter archive pages, share tracking, role-aware panel metrics, approval-to-publish quality gates, production smoke script, editorial quality fields, first-party analytics events, and admin SEO/analytics endpoints.

  • Writer Studio V5 polish (Phase 10 close-out): HtmlEditor grouped toolbar with hover states and keyboard shortcuts (Ctrl+B/I/S); live word/char count footer; WritingTipCard prev/next nav with timer reset; ArtifactStudio diagram library replaced gradient placeholders with live scaled mini-previews; analytics sparklines upgraded to filled-area SVG with gradient and date labels; analytics table gains prefetched inline mini-sparklines per row and a totals footer; dirty-state indicator; reviewer feedback banner; articles list pagination; backend articleInclude joins review { note, status } and publicArticle exposes reviewNote.

  • Phase 9 publication features: SEO article fields, daily view logs, related articles, article series, comment likes, reading lists, newsletter campaigns, review workflow, and admin analytics.

  • Phase 8 reader engagement: article comments/replies, comment flagging, reading history, in-app notifications, writer follows, and SSE-powered live admin signals.

  • Username login: users can authenticate with email or @username.

  • Signup finalization: display name, username, password, and email/phone are collected.

  • Profile finalization: every role can edit display name, username, bio, avatar, verification data, and password.

  • Seed finalization: every seeded user gets a username.

  • Writer-admin accounts: آرسام صباغ, رادمان قلیچی, سیداحمدرضا محجوب in backend/prisma/credentials.json; operator credentials in ignored ACCOUNTS.md.

  • Native deployment docs: DEPLOY.md covers systemd, nginx, TLS, env, backups, schema apply, scheduled publishing, and health checks.

  • Phase 7 CMS readiness: media library, scheduled publishing, activity CSV export, real dashboard metrics, SMTP email flows, Kavenegar OTP.

Active Checklist

Phase 14 — Linux production setup (required before new features go live)

  • Install PostgreSQL vector extension as superuser (sudo -u postgres psql -c 'CREATE EXTENSION vector;')
  • Rebuild Persian FTS structure: run node scripts/setup-fts.js (or via seed.ts) if schema pushes drop generated columns.
  • cd backend && npm run prisma:apply — apply Phase 14 schema additions
  • cd backend && npm run prisma:generate — regenerate Prisma client
  • Verify LMS functionality: take quiz, pass with >=80, and verify certificate issues on /api/v1/lms/me.
  • Verify Semantic Search: query /api/v1/search/semantic and check for vector distance calculation correctness.

Phase 13 — Linux production setup

  • cd backend && npm run prisma:generate — regenerate Prisma client
  • Verify guest push: visit topic hub → click "🔔 دریافت اعلان" → grant permission → push subscription in DB with userId=null
  • Verify notification preferences: profile settings → "تنظیمات اعلان‌ها" → toggle push channel → notification skipped on next trigger
  • Verify revision history: edit any article → save → open "تاریخچه" drawer → revision appears → restore works
  • Verify presence: open same article in two tabs → both show avatar chip in editor header

Phase 12 — Linux production setup (required before push goes live)

  • cd backend && npm install web-push — install web-push package (can't install on Windows)
  • Generate VAPID keys: node -e "const wp=require('web-push');const k=wp.generateVAPIDKeys();console.log(JSON.stringify(k,null,2))"
  • Add to /etc/teknav/backend.env: VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY, VAPID_SUBJECT=mailto:admin@teknav.ir
  • cd backend && npm run prisma:generate — regenerate client for PushSubscription model
  • cd backend && npm run prisma:apply — apply all Phase 11+12 schema additions
  • cd backend && npm run seed — reseed if needed

Full Linux production verification

  • npm run preflight:prod — static production-readiness audit before build/deploy
  • npm run seo:sitemap — regenerate sitemaps
  • npm run check:seo — audit Persian article SEO quality gate
  • npm run build — frontend build
  • cd backend && npm run build — backend TypeScript build
  • Start backend and run cd backend && TEST_REQUIRE_SERVER=1 npm test — strict endpoint contract smoke suite
  • npm run smoke:prod — smoke test all endpoints
  • Verify /api/v1/ready returns 200 when PostgreSQL and Redis are healthy and 503 during dependency failure.
  • Verify Phase 8–10 flows: comments, history, notifications/SSE, reading lists, follows, analytics, review workflow, newsletter campaigns.
  • Verify Phase 11 flows: /membership subscribe → Zarinpal callback → success page; /api/v1/admin/jobs approve/reject; /api/v1/admin/errors aggregated view; premium gate card on premium articles; article card bookmark → reading list picker; continue-reading overlay on home feed.
  • Verify Phase 12 push flow: log in as reader → PushNotificationPrompt banner appears → grant permission → PushSubscription row in DB → profile toggle shows "فعال" → publish article or trigger comment reply → browser push notification arrives → click notification navigates correctly.
  • Verify published article editing: admin opens published article → sees green "بروزرسانی و انتشار" button → save updates content and keeps status published; writer opens own published article → sees draft/re-review buttons → save demotes to draft/pending.
  • Verify /api/v1/errors persists to ClientError table (was logging-only before Phase 11).
  • Verify STORAGE_BACKEND is unset or local on server — uploads go to /var/lib/teknav/uploads.
  • Verify /ACCOUNTS.md returns 404/403 through nginx.
  • Rotate production passwords after first login.
  • Set ZARINPAL_MERCHANT_ID in /etc/teknav/backend.env when payment goes live.
  • Remove resetPasswordOnSeed from writer-admin accounts after rotation.
  • Confirm SMTP and Kavenegar credentials on the server.

Roadmap

Done

  • Phase 1: Vite/React conversion and zero-CDN frontend.
  • Phase 2: PostgreSQL/Prisma/Redis backend seed and Persian FTS.
  • Phase 3: Argon2id auth, Redis sessions, CSRF, captcha, login/signup.
  • Phase 4: public REST API, caching, search, newsletter, reactions/saves.
  • Phase 5: role-gated Admin/CMS API and API-backed admin panel.
  • Phase 6: native nginx/systemd deployment assets and runbook.
  • Phase 7: profiles, media, scheduled publishing, verification delivery, SEO/crawler artifacts, account finalization.
  • Phase 8: reader engagement and real-time admin over SSE.
  • Phase 9: content modernization, SEO enrichment, publication workflow, reading lists, newsletter campaigns, article series, and analytics.
  • Phase 10: topic authority hubs, tag pages, newsletter archive, topic/writer follows, share tracking, role-aware panel metrics, approval-to-publish quality gates, editorial fields, first-party analytics events, admin SEO/analytics endpoints, production smoke checks, PWA, reading streaks, personalized feed, comment upvoting, reactions, Q&A, glossary, comparison templates, OAuth, 2FA, verified expert badges, errata, monetization foundations (jobs/courses/membership/premium), Writer Studio V5 full polish, and series article navigation. Linux production validation pending.

Future

Phases 11–14 are implemented. Remaining deferred items:

  • 4.1 Automated test suite [L] — expand backend/tests/ to ~40 tests covering auth edge cases, profiles, reading lists, comment moderation, analytics, and review workflow.
  • 4.4 Meilisearch evaluation [S] — stand up Meilisearch on staging, index articles, compare Persian FTS quality and latency vs PostgreSQL; write evaluation note in docs/meilisearch-eval.md.

Phase 15 candidates:

  • Expand structured public feeds: topic/tag/author feeds plus machine-readable JSON exports for approved public content only; never include drafts, private analytics, credentials, comments, or account data.
  • Wire S3StorageAdapter with a real S3 client when upload volume requires it (activate with STORAGE_BACKEND=s3).
  • Expand Zarinpal flow to cover renewal/expiry reminders.
  • Surface earned badges on public profile pages and article comment bylines.
  • Email/SMS channel enforcement in createNotification() — currently only push channel is gated by preferences.

Known Risks

  • Production email/SMS requires correct SMTP and Kavenegar credentials.
  • ACCOUNTS.md intentionally contains plaintext operator credentials; it must remain ignored and inaccessible over HTTP.
  • This repo currently uses prisma:apply because no Prisma migration directory is present.
  • teknav-store.js and teknav-data.js still exist for seed/reference paths; do not reintroduce them as admin-panel data fallbacks.