11 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What this is
Two independent apps in one repo:
- Frontend (
frontend/) — a Vite + React 19 + TypeScript marketing/content site for "اندیشکده فولاد آینده" (a steel-industry think tank). Persian-first, RTL, bilingual (fa/en). Deploys as a static build via Docker to Hugging Face Spaces on port 7860. - Admin panel (
panel/) — a standalone Node/Express + Postgres app with its ownpackage.jsonandnode_modules, that is BOTH the backend API and the CMS admin UI (served frompanel/public/). Manages content the site publishes.
These two have no shared build or dependency tree. frontend/ and panel/ are sibling folders at the repo root — neither references the other at build time (the frontend reads the panel only at runtime via VITE_PANEL_API).
Commands
Frontend (run from frontend/):
cd frontend
npm run dev # Vite dev server (HMR)
npm run build # tsc -b && vite build (type-checks then bundles)
npm run lint # eslint .
npm run preview # serve the production build
npx tsc -b --noEmit # type-check only — the fast inner loop; use after every edit
There is no test framework configured. "Verifying" a change means npx tsc -b --noEmit (must be clean) and looking at the running dev server.
Admin panel (run from panel/):
cd panel
npm install # first time only
npm run seed # create the admin user from .env (ADMIN_USERNAME/PASSWORD)
npm start # node server.js → http://localhost:3001
npm run dev # node --watch server.js
The panel uses Postgres (pg Pool over DATABASE_URL) behind a better-sqlite3-style db.prepare().get/all/run() facade — every call is async and must be awaited.
Frontend architecture
- Routing:
src/app/router.tsx(createBrowserRouter).RootLayout(src/app/layout/RootLayout.tsx) wraps every page withHeader,Footer, and the smooth-scroll engine. Pages live insrc/pages/<Name>/<Name>.tsx; the homepage composes section components fromsrc/pages/Home/sections/. - Language:
useLang()fromsrc/context/LangContextreturns{ lang: 'fa'|'en', toggle }. Components hold inline{ fa: {...}, en: {...} }objects and index bylang. RTL is driven bydir={lang==='fa'?'rtl':'ltr'}near the page root; many flex containers forcedirection:'ltr'locally to stop RTL from reversing their child order, then set inner text back tortl. - Smooth scroll:
RootLayoutruns Lenis synced to the GSAP ticker (the joinspread.app recipe) — one shared RAF clock so scroll-driven animations don't stutter. It is desktop-only: on touch/coarse pointers it hands off to native momentum (avoids the iOS double-smoothing lag). Do not re-add CSSscroll-behavior: smooth— it fights Lenis. - Hero (
src/pages/Home/sections/HeroSection.tsx): a GSAPScrollTriggerscrub timeline pinned over a200vhsection (de-zoom + satellite scatter). This is GSAP, not framer-motion. - Styling: mostly inline
styleobjects, with Tailwind utility classes for responsive overrides (max-md:,max-lg:) and a few!importantoverrides. Global CSS variables insrc/index.css(--ink,--paper,--red,--color-orange, etc.). Brand colors are gold#CD9E53and navy#032340— these are also hardcoded asconst GOLD/const NAVYin many section files, so a rebrand is a repo-wide find-and-replace, not just a CSS-var change. - Globe (
src/components/ui/globe.tsx): three-globe mounted in react-three-fiber via<primitive>(NOT viaextend/JSX-element augmentation — that augmentation poisons global JSX types and breaks unrelated components likeReact.ElementTypeicons). Country polygons load at runtime frompublic/globe-countries.geojson(bundled, public-domain Natural Earth). - Calendar (
src/components/ui/EventCalendar.tsx): a native Jalali (Persian) month grid built withIntl.DateTimeFormat('en-US-u-ca-persian', …)— no date library. It walks GregorianDates and reads their Persian parts to lay out the grid. - Content layer:
src/content/*.tsand inline arrays hold all section data. These are mock/seed data and are explicitly intended to be replaced byfetchcalls to the panel API later (see "Wiring", below). Keep new editorial data in this shape so the swap stays mechanical. - Generator shape: editorial automation must treat
در یک نگاهandرادار آیندهas separate products.در یک نگاهis short card copy.رادار آیندهis long-form analysis with multiple inputs, in-text citations, intro/build-up/conclusion, and article blocks that map to/radar/post/:id.
Admin panel architecture (panel/)
- Stack: Express 4 +
better-sqlite3(single filepanel/data.db),bcryptjs+jsonwebtoken(HTTP-only cookie namedsession),multeruploads topanel/uploads/. Admin UI is a vanilla-JS SPA inpanel/public/(app.js, no build step). - Schema:
panel/db.js(users,articles,risk_signals,prices) plus row→object mappers.articlesis a flexible universal content model discriminated bycategory/type. - API (
panel/server.js): public reads (GET /api/articles,/api/risks,/api/prices) + auth-gated writes via theauthRequiredmiddleware. CRUD for articles, risk signals, and users;/api/uploads;/api/contact. CORS is gated by theALLOWED_ORIGINSenv var. - Prices are scraped from tgju.org by
panel/scraper.json a 120s interval when the server runs. - Config:
panel/.env(copy from.env.example) —JWT_SECRET,ADMIN_*,PORT(3001),ALLOWED_ORIGINS, mail creds.
Wiring the panel to the site (not done yet)
When asked to make published content appear on the site: add a frontend fetch client (e.g. src/lib/api.ts reading import.meta.env.VITE_API_URL), replace a section's src/content/* import with a hook that calls GET /api/articles?category=<section>, and keep the static file as the loading fallback. Do it one section at a time. The articles table's category column is the per-section discriminator. Recommended schema additions before going live: a status (draft/published) column, and an events resource for the calendar.
RTK (Rust Token Killer) - Token-Optimized Commands
Golden Rule
Always prefix commands with rtk. If RTK has a dedicated filter, it uses it. If not, it passes through unchanged. This means RTK is always safe to use.
Important: Even in command chains with &&, use rtk:
# ❌ Wrong
git add . && git commit -m "msg" && git push
# ✅ Correct
rtk git add . && rtk git commit -m "msg" && rtk git push
RTK Commands by Workflow
Build & Compile (80-90% savings)
rtk cargo build # Cargo build output
rtk cargo check # Cargo check output
rtk cargo clippy # Clippy warnings grouped by file (80%)
rtk tsc # TypeScript errors grouped by file/code (83%)
rtk lint # ESLint/Biome violations grouped (84%)
rtk prettier --check # Files needing format only (70%)
rtk next build # Next.js build with route metrics (87%)
Test (60-99% savings)
rtk cargo test # Cargo test failures only (90%)
rtk go test # Go test failures only (90%)
rtk jest # Jest failures only (99.5%)
rtk vitest # Vitest failures only (99.5%)
rtk playwright test # Playwright failures only (94%)
rtk pytest # Python test failures only (90%)
rtk rake test # Ruby test failures only (90%)
rtk rspec # RSpec test failures only (60%)
rtk test <cmd> # Generic test wrapper - failures only
Git (59-80% savings)
rtk git status # Compact status
rtk git log # Compact log (works with all git flags)
rtk git diff # Compact diff (80%)
rtk git show # Compact show (80%)
rtk git add # Ultra-compact confirmations (59%)
rtk git commit # Ultra-compact confirmations (59%)
rtk git push # Ultra-compact confirmations
rtk git pull # Ultra-compact confirmations
rtk git branch # Compact branch list
rtk git fetch # Compact fetch
rtk git stash # Compact stash
rtk git worktree # Compact worktree
Note: Git passthrough works for ALL subcommands, even those not explicitly listed.
GitHub (26-87% savings)
rtk gh pr view <num> # Compact PR view (87%)
rtk gh pr checks # Compact PR checks (79%)
rtk gh run list # Compact workflow runs (82%)
rtk gh issue list # Compact issue list (80%)
rtk gh api # Compact API responses (26%)
JavaScript/TypeScript Tooling (70-90% savings)
rtk pnpm list # Compact dependency tree (70%)
rtk pnpm outdated # Compact outdated packages (80%)
rtk pnpm install # Compact install output (90%)
rtk npm run <script> # Compact npm script output
rtk npx <cmd> # Compact npx command output
rtk prisma # Prisma without ASCII art (88%)
Files & Search (60-75% savings)
rtk ls <path> # Tree format, compact (65%)
rtk read <file> # Code reading with filtering (60%)
rtk grep <pattern> # Search grouped by file (75%). Format flags (-c, -l, -L, -o, -Z) run raw.
rtk find <pattern> # Find grouped by directory (70%)
Analysis & Debug (70-90% savings)
rtk err <cmd> # Filter errors only from any command
rtk log <file> # Deduplicated logs with counts
rtk json <file> # JSON structure without values
rtk deps # Dependency overview
rtk env # Environment variables compact
rtk summary <cmd> # Smart summary of command output
rtk diff # Ultra-compact diffs
Infrastructure (85% savings)
rtk docker ps # Compact container list
rtk docker images # Compact image list
rtk docker logs <c> # Deduplicated logs
rtk kubectl get # Compact resource list
rtk kubectl logs # Deduplicated pod logs
Network (65-70% savings)
rtk curl <url> # Compact HTTP responses (70%)
rtk wget <url> # Compact download output (65%)
Meta Commands
rtk gain # View token savings statistics
rtk gain --history # View command history with savings
rtk discover # Analyze Claude Code sessions for missed RTK usage
rtk proxy <cmd> # Run command without filtering (for debugging)
rtk init # Add RTK instructions to CLAUDE.md
rtk init --global # Add RTK to ~/.claude/CLAUDE.md
Token Savings Overview
| Category | Commands | Typical Savings |
|---|---|---|
| Tests | vitest, playwright, cargo test | 90-99% |
| Build | next, tsc, lint, prettier | 70-87% |
| Git | status, log, diff, add, commit | 59-80% |
| GitHub | gh pr, gh run, gh issue | 26-87% |
| Package Managers | pnpm, npm, npx | 70-90% |
| Files | ls, read, grep, find | 60-75% |
| Infrastructure | docker, kubectl | 85% |
| Network | curl, wget | 65-70% |
Overall average: 60-90% token reduction on common development operations.