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

177 lines
13 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.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Directives
- **Zero CDN dependencies.** No external JS, CSS, fonts, images, or `cdn.*` URLs. `npm run build` fails on any CDN reference via `scripts/check-no-cdn.mjs`.
- **Persian/RTL first.** All UI copy is Persian. Layouts assume `direction: rtl`; use logical CSS properties, not left/right.
- **Frontend uses APIs only.** Never call the database from frontend code. All persistence goes through `/api/v1/*` at the backend. Frontend API clients may pass unversioned `/api/*` paths because `src/lib/api.js` rewrites them to `/api/v1/*`. `teknav-data.js` and `teknav-store.js` are seed/reference data — never use them as admin-panel fallbacks.
- **No mock admin data.** Admin/writer/reviewer/dashboard/media views must use real backend APIs and show empty/error states when data is missing.
- **Production is native Linux/systemd + nginx.** No Docker unless explicitly asked. See `DEPLOY.md`.
- **Protect credentials.** `ACCOUNTS.md` is gitignored and nginx-blocked. Never move it into `public/` or `dist/`. Seed credentials are in `backend/prisma/credentials.json`.
- **Port and registry are fixed.** Vite dev/preview → port `3009`; npm registry → `https://npm.devneeds.ir/`.
- **Reuse shared styling.** Use `src/styles/global.css` keyframes/utilities — do not redefine animation primitives.
- **Phase 15 is current.** Keep `ARCH.md`, `AGENTS.md`, `DEPLOY.md`, and `SECURITY.md` aligned when schema, SEO, trust, retention, or monetization flows change. Phase 14 Linux validation (pgvector + LMS) is still pending before full production go-live.
- **Production hardening.** Run `npm run preflight:prod` before deploy; run `TEST_REQUIRE_SERVER=1 npm test` in `backend/` against a live backend to enforce endpoint contracts.
## Commands
**Frontend** (repo root):
```bash
npm run dev # Vite dev server → port 3009, proxies /api → localhost:3010
npm run build # Full pipeline (see Build Pipeline Order)
npm run preview # Preview dist/ on port 4173
npm run preflight:prod # Static pre-deploy audit
npm run seo:sitemap # Regenerate sitemap.xml, robots.txt, feed.xml
npm run og:images # Generate OG images into public/images/og/ (Linux only)
npm run check:seo # Audit Persian articles for indexability gaps
npm run smoke:prod # Smoke-test all public endpoints
```
**Backend** (`cd backend` first):
```bash
npm run dev # tsx watch → port 3010
npm run build # TypeScript compile
npm run prisma:generate # Regenerate Prisma client after schema changes
npm run prisma:apply # Apply schema (migrations if present, else db push)
npm run seed # Seed PostgreSQL + Persian FTS
npm run publish:due # Publish scheduled articles + fan out notifications
npm test # Skips endpoint tests when no backend running
TEST_REQUIRE_SERVER=1 npm test # Strict contract tests against a live backend
```
**Startup order:** PostgreSQL + Redis → `cd backend && npm run dev` → `npm run dev`
**Schema change workflow:** edit schema → `npm run prisma:generate --prefix backend` → `npm run prisma:apply --prefix backend` → backend build.
**Article data change workflow:** edit `teknav-data.js` → `npm run check:seo` → `npm run seo:sitemap` → `npm run build`.
## Build Pipeline Order
```
seo:sitemap → og:images → vite build → check-no-cdn → check-responsive
→ generate-article-pages → generate-web-stories → generate-comparison-pages
→ generate-company-pages → generate-en-page → generate-author-pages
→ generate-semantic-pages → compress-dist
```
All `generate-*` scripts produce static HTML that nginx serves directly — never manually edit files under `dist/`. `generate-article-pages` must run after `vite build` (needs `dist/index.html` as template) and before `compress-dist` (so `.gz`/`.br` pairs are created). Phase 15 scripts output: `dist/stories/{slug}/` (web stories), `dist/compare/{slug}/` (comparisons), `dist/directory/{slug}/` (company directory).
## SEO Invariants
- **No `hreflang="en"`.** `?lang=en` is a UI preference only; canonical always points to the clean URL.
- **No placeholder verification codes.** Never commit `INSERT_GOOGLE_VERIFICATION_CODE` or similar strings.
- **Static article pages** under `dist/article/{slug}/index.html` are build-time generated — do not edit manually.
- **Sitemap lastmod must not be future-dated.** `capDate()` in `generate-seo.mjs` enforces this.
- **Organization schema:** `['Organization', 'NewsMediaOrganization']` — required for Google News.
- **Article schema:** `['NewsArticle', 'TechArticle']` — required for Google Article rich results.
- **Run `npm run check:seo`** after any article metadata or content change.
- **Proven content formula** (article `ai-data-centric-2026` ranked #1 on Google, above Wikipedia): `<p class="lead">` opening, numbered `<h2>` sections, `<strong>` entity highlighting, bilingual terminology (Persian + English inline), technical formulas/data inline, `factCheckedAt` timestamp, 8+ sections / ~3000 words.
## Architecture
**Frontend** — Vite 5 + React 18 ES modules, automatic JSX runtime (no `import React` needed). Route dispatch in `teknav-app.jsx`; pages in `teknav-home.jsx`, `teknav-articles.jsx`, `teknav-pages.jsx`, `teknav-admin.jsx`, `teknav-auth.jsx`, `teknav-profile.jsx`. Providers, header, footer, shared UI in `teknav-ui.jsx`. Styles/fonts/keyframes in `src/styles/global.css`.
**Backend** — Fastify 4 + Prisma 5 + PostgreSQL 16 (+ `pgvector` for semantic search) + Redis 7. Route modules in `backend/src/routes/`. Global error handler registered early in `backend/src/server.ts` — maps `FST_ERR_VALIDATION` to `'invalid_input'` uniformly. Config validated by Zod in `backend/src/config.ts`.
**Data layer** — `teknav-data.js` holds all articles (`art1`–`art35`), authors, categories, topic hub metadata, glossary reference data. Article content beyond art10 lives in `article-contents-{N}.js` files. `src/lib/content-api.js` merges API results over this local fallback (API wins). `teknav-store.js` handles client-side localStorage caching.
**Auth** — Argon2id passwords (m=19MiB, t=2, p=1), Redis sessions (`tek_sid`, 14-day sliding TTL), CSRF double-submit cookie (`tek_csrf`). Login by email or `@username`. Google/GitHub OAuth (authorization-code, state in Redis). SMS 2FA via Kavenegar OTP (`tek_2fa` ticket).
**Role-based access:**
| Role | Access |
|---|---|
| `reader` | View, save, react, manage own profile |
| `reviewer` | + Article review queue |
| `writer` | + Create/edit own articles |
| `editor` | + Edit any article, manage categories/tags |
| `admin` | + Delete articles, manage users |
**Real-time** — SSE at `/api/v1/auth/notifications/stream` (reader) and `/api/v1/admin/stream` (admin live signals). Redis pub/sub is the bus (`backend/src/lib/realtime.ts`).
**Web push** — RFC 8030/VAPID via `web-push`. `PushSubscription` table stores endpoint per user; `userId` nullable for guest topic subscriptions. `sendPushToUser()` checks `NotificationPreference` before delivering. VAPID keys in `/etc/teknav/backend.env` — missing keys make push a silent no-op, all other features unaffected.
**Storage** — `LocalStorageAdapter` active by default (writes to `UPLOAD_DIR`). S3 migration: set `STORAGE_BACKEND=s3` and wire the stub in `backend/src/lib/storage.ts`.
## Phase 14 — Farsi Knowledge & Ecosystem (current, Linux validation pending)
Requires `CREATE EXTENSION vector;` (PostgreSQL superuser) and `prisma:apply` before going live:
| Subsystem | Models | Key endpoints |
|---|---|---|
| **Semantic Search / RAG** | `ArticleEmbedding` | `POST /api/v1/search/semantic`, `GET /api/v1/rag/:slug` |
| **LMS** | `LearningPath`, `LearningModule`, `Quiz`, `UserCertification` | `POST /api/v1/lms/quiz/:quizId/submit`, `GET /api/v1/lms/me` — auto-cert at ≥80 |
| **Tech Directory** | `CompanyProfile`, `CompanyClaim` | Authenticated claim endpoint |
| **Wiki/Glossary Proposals** | `WikiProposal`, `GlossaryProposal` | `POST /api/v1/wiki/proposals`, `PATCH /api/v1/admin/wiki/proposals/:id` |
`link-engine.ts` uses `cheerio` to auto-inject `<a href="/glossary/:slug">` anchors into newly published articles.
## Key Files
| Path | Purpose |
|---|---|
| `teknav-app.jsx` | Root route dispatch |
| `teknav-ui.jsx` | Providers, header, footer, `PushNotificationPrompt` |
| `teknav-home.jsx` | Home page — hero, featured, latest, personalized feed, streaks |
| `teknav-articles.jsx` | Article detail — comments, TOC, reactions, Q&A, series nav |
| `teknav-pages.jsx` | Topic hubs, glossary, tag pages, author pages, series, newsletter archive, jobs, courses, directory |
| `teknav-admin.jsx` | CMS, `ArticleEditor` (role-aware, `RevisionDrawer`, presence chips), LMS panel, directory panel |
| `teknav-auth.jsx` | Login, signup, OAuth, 2FA, forgot-password |
| `teknav-profile.jsx` | `/profile/@username`, push toggle, notification preferences, history |
| `src/lib/api.js` | Fetch wrapper with credentials + CSRF |
| `src/lib/content-api.js` | Public content client — merges API over local fallback |
| `src/lib/admin-api.js` | Admin/CMS API client |
| `src/lib/engagement-api.js` | Comments, history, notifications, follows, streaks, badges, revisions, presence |
| `src/lib/seo.jsx` | Page-level meta tags and JSON-LD for all page types |
| `backend/src/server.ts` | Fastify bootstrap — error handler registered before all plugins |
| `backend/src/routes/admin.ts` | Role-gated article CRUD, publish quality gates, analytics, review, newsletter, series |
| `backend/src/routes/auth.ts` | Local auth, OAuth, 2FA, session, `/api/v1/auth/me` |
| `backend/src/routes/comments.ts` | Comments, replies, likes, upvotes, flags, bulk mod. Returns `{items:[],total:0}` (not 404) for unknown slugs. |
| `backend/src/routes/notifications.ts` | Notification list, SSE stream, VAPID key, push subscribe/unsubscribe |
| `backend/src/routes/revisions.ts` | Article revision list/get/restore (admin/editor only) |
| `backend/src/routes/monetization.ts` | Jobs, courses, Zarinpal subscribe/callback/status |
| `backend/src/routes/errors.ts` | `POST /api/v1/errors` → `ClientError` table; `GET /api/v1/admin/errors` |
| `backend/src/lib/push.ts` | VAPID, `sendPushToUser()` (checks prefs), `sendGuestPushByTopic()`, 410 cleanup |
| `backend/src/lib/storage.ts` | `StorageAdapter` — `LocalStorageAdapter` default, `S3StorageAdapter` stub |
| `backend/src/lib/realtime.ts` | Redis pub/sub, SSE helpers, visitor counter |
| `backend/prisma/schema.prisma` | Single source of truth for all models |
| `backend/prisma/seed.ts` | Seed data, staff users, Persian FTS setup |
| `scripts/production-readiness.mjs` | `npm run preflight:prod` static pre-deploy checklist |
| `.env.prod.example` | Production env template → copy to `/etc/teknav/backend.env` |
| `ACCOUNTS.md` | Operator credential sheet — gitignored, nginx-blocked |
| `deploy/systemd/` | Production systemd units and timers |
| `nginx/nginx.conf.example` | Production nginx template |
## Production Notes
- nginx must serve pre-rendered semantic folders (`/category/`, `/tag/`, `/glossary/`, `/topics/`, `/series/`, `/author/`, `/profile/`) with `gzip_static on; brotli_static on;` — avoids redirect loops and sub_filter cost.
- Never copy Windows-generated Prisma engine binaries (`query_engine*.node`) or local `node_modules` to the Linux server.
- Zarinpal requires `ZARINPAL_MERCHANT_ID` in env; until set, subscribe returns `payment_unavailable`. Use `ZARINPAL_SANDBOX=1` for testing.
- Phase 12 requires `cd backend && npm install web-push` and VAPID key generation once on Linux.
- Phase 14 requires `CREATE EXTENSION vector;` as PostgreSQL superuser before `prisma:apply`.
- After first production login, rotate writer-admin passwords via admin UI, then remove `resetPasswordOnSeed` from `backend/prisma/credentials.json`.
## Large Codebase Analysis (Gemini CLI)
When multiple large files exceed context, use `gemini -p` with `@` path syntax:
```bash
gemini -p "@src/ @backend/src/ List all API endpoints and their auth requirements"
gemini -p "@teknav-admin.jsx @backend/src/routes/admin.ts Trace the article publish flow end-to-end"
gemini --all_files -p "List all Prisma models and their relations"
```
Paths are relative to where you run `gemini`. Use for cross-file architecture questions or verifying feature coverage across many files.
## Memory
See `MEMORY.md` for full stack context and key paths. See `ARCH.md` for the active roadmap and Phase 14 Linux validation checklist. See `DEPLOY.md` for the full production runbook. See `SECURITY.md` for the pre-deploy security checklist and nginx/Fastify hardening details. See `PHASES.md` for completed phase history. See `PHASE16.md` for the planned English `/en/` subdirectory (blocked on LTR layout pass — not started).
Quick reference:
- **Stack:** Vite 5 + React 18 / Fastify 4 + Prisma 5 / PostgreSQL 16 + pgvector + Redis 7
- **Current phase:** 15 (implemented; Phase 14 Linux validation pending)
- **Writers:** آرسام صباغ (`arsam-sabbagh`), سیداحمدرضا محجوب (`ahmadreza-mahjoub`), رادمان قلیچی (`radman-ghelichi`)
- **Constraints:** Zero CDN · Persian-first RTL · native Linux/systemd · no mock admin data