Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
20 KiB
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.mdignored 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 viacontentApi.trackEvent. - 15B2: Embeddable Widget System —
embed.htmlsecond Vite entry,src/embed.jsxbootstrapper, 3 widgets (GlossaryWidget, ArticleCardWidget, CompanyWidget) with dark mode (prefers-color-scheme) and postMessage resize only on height change;public/embed-loader.jsthird-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;ComparisonPagewith localStorage vote widget (no backend) and share button;factCheckedAtdisplay; 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/companiesandGET /api/v1/directory/companies/:slugpublic 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.
- 15A: Web Stories — CSS scroll-snap story pages for all 34 published articles at
-
Production hardening & validation pass:
- Fixed Fastify schema validation error mapping: Moved
app.setErrorHandlerearly in the fastify server lifecycle to ensure it propagates down to routes/plugins. Added validation error mapping soFST_ERR_VALIDATION/err.validation !== undefinederrors returninvalid_inputto 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 usinggzip_static onandbrotli_static on, avoiding redirect loops and dynamic sub_filter cost. - Added root
.env.prod.examplealigned with/etc/teknav/backend.envfor 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 withTEST_REQUIRE_SERVER=1. /api/v1/healthreturns minimal public health;/api/v1/readyreturns 503 when PostgreSQL or Redis is unavailable;/api/v1/admin/healthexposes authenticated diagnostics, feature flags, and uptime.
- Fixed Fastify schema validation error mapping: Moved
-
Phase 14 — Farsi Knowledge & Tech Ecosystem (implemented this session):
- Wiki & Glossary Proposals:
WikiProposalandGlossaryProposalPrisma models;POST /api/v1/wiki/proposalsandPATCH /api/v1/admin/wiki/proposals/:id;DiffViewerReact component highlighting additions/deletions. - Automated Internal Linking Engine:
link-engine.tsutilizingcheerioto scan HTML content of newly published articles and inject<a href="/glossary/:slug">anchors to glossary terms safely. - Semantic Search & RAG:
ArticleEmbeddingPrisma model;pgvectorextension;POST /api/v1/search/semanticfor context-aware related articles;GET /api/v1/rag/:slugfor machine-readable raw Markdown context extraction. - Learning Management System (LMS):
LearningPath,LearningModule,Quiz, andUserCertificationPrisma models;POST /api/v1/lms/quiz/:quizId/submitandGET /api/v1/lms/me; auto-issued student certificates (>=80pass score);LmsPanelstudent dashboard UI. - Tech & Startup Directory:
CompanyProfileandCompanyClaimPrisma models; interactive Farsi directory UI (DirectoryPanel); authenticated endpoint to claim company profiles with verification proof.
- Wiki & Glossary Proposals:
-
Phase 13 — Community depth + writer tools:
- Guest push subscriptions: nullable
userIdonPushSubscription,topics String[],POST /api/v1/push/guest-subscribe(IP-rate-limited),sendGuestPushByTopic()inpush.ts,publish-due.mjsfans out to guest subs, "🔔 دریافت اعلان" button on topic hub pages. - Fine-grained notification center:
NotificationPreferencemodel +GET/PUT /api/v1/auth/notifications/preferences;sendPushToUser()checks push preference before delivery; collapsible toggle grid inProfileSettingsModal. - Verified reader badges:
UserBadgemodel + 8 badge rules evaluated inpublish-due.mjscron;GET /api/v1/auth/badges+GET /api/v1/admin/users/:id/badges. - Article version history:
ArticleRevisionsnapshot on every PATCH (capped at 20);GET/GET/POST /api/v1/admin/articles/:id/revisions[/:id[/restore]]inrevisions.ts;RevisionDrawerside-panel inArticleEditorwith 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;ArticleEditorpolls every 30s; avatar chips shown when 2+ editors online.
- Guest push subscriptions: nullable
-
Phase 12 — Web push notifications + published article editing:
- Browser web push (RFC 8030/VAPID):
PushSubscriptionPrisma model + relation onUser;backend/src/lib/push.tswithsendPushToUser()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/unsubscriberoutes innotifications.ts;createNotification()inrealtime.tsextended with non-blocking push fan-out; service workerpush+notificationclickhandlers with Persian RTL options;pushApiclient inengagement-api.js;PushNotificationPromptdismissible banner inteknav-ui.jsx; push toggle (enabled/blocked/unsupported states) inProfileSettingsModal. - Published article editing:
ArticleEditornow acceptsroleprop and derivesisPublished/canPublishDirectly; shows role-appropriate info banner and button set (admin/editor: "بروزرسانی و انتشار" / "تبدیل به پیشنویس" / "زمانبندی مجدد"; writer: "ذخیره پیشنویس" / "ارسال برای بررسی مجدد"); fixed critical backend bug inadmin.tsPATCH route (was convertingPUBLISHED → PENDINGbefore the Phase10 quality-gate block, now skips status in the bulk update and letspublishArticleWithPhase10Checks()handle it cleanly);quality_check_failederror now surfaced in the editor save handler. scripts/generate-seo.mjsvariable-shadow bug fixed: localxmlarray insideurl()renamed tolinesso the outerxml()escape function is no longer shadowed.DEPLOY.mdupdated: VAPID key generation block, three VAPID env vars in Section 6, VAPID private key security note, and "Web push not delivering" troubleshooting block.
- Browser web push (RFC 8030/VAPID):
-
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 inpublicArticle(). - Track 4 reliability:
ClientErrorPrisma model +GET /api/v1/admin/errorsaggregated admin view + admin "خطاهای کلاینت" tab with daily sparkline and top-errors table;StorageAdapterinterface inbackend/src/lib/storage.ts—LocalStorageAdapteris active (default, no env var needed),S3StorageAdapterstub activates withSTORAGE_BACKEND=s3; upload route inadmin.tsswitched to use the adapter. - Schema additions:
ClientError,MembershipPayment,JobListing.featuredUntil,NotificationType.systemenum value. - 32 articles with complete metadata now in
teknav-data.js; allcontentFreshnessStatusvalues 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
articleIncludejoinsreview { note, status }andpublicArticleexposesreviewNote. -
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 ignoredACCOUNTS.md. -
Native deployment docs:
DEPLOY.mdcovers 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
vectorextension as superuser (sudo -u postgres psql -c 'CREATE EXTENSION vector;') - Rebuild Persian FTS structure: run
node scripts/setup-fts.js(or viaseed.ts) if schema pushes drop generated columns. cd backend && npm run prisma:apply— apply Phase 14 schema additionscd 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/semanticand 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 forPushSubscriptionmodelcd backend && npm run prisma:apply— apply all Phase 11+12 schema additionscd backend && npm run seed— reseed if needed
Full Linux production verification
npm run preflight:prod— static production-readiness audit before build/deploynpm run seo:sitemap— regenerate sitemapsnpm run check:seo— audit Persian article SEO quality gatenpm run build— frontend buildcd 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/readyreturns 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:
/membershipsubscribe → Zarinpal callback → success page;/api/v1/admin/jobsapprove/reject;/api/v1/admin/errorsaggregated 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 →
PushNotificationPromptbanner appears → grant permission →PushSubscriptionrow 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/errorspersists toClientErrortable (was logging-only before Phase 11). - Verify
STORAGE_BACKENDis unset orlocalon server — uploads go to/var/lib/teknav/uploads. - Verify
/ACCOUNTS.mdreturns 404/403 through nginx. - Rotate production passwords after first login.
- Set
ZARINPAL_MERCHANT_IDin/etc/teknav/backend.envwhen payment goes live. - Remove
resetPasswordOnSeedfrom 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]— expandbackend/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 indocs/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
S3StorageAdapterwith a real S3 client when upload volume requires it (activate withSTORAGE_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.mdintentionally contains plaintext operator credentials; it must remain ignored and inaccessible over HTTP.- This repo currently uses
prisma:applybecause no Prisma migration directory is present. teknav-store.jsandteknav-data.jsstill exist for seed/reference paths; do not reintroduce them as admin-panel data fallbacks.