Imported from diamondzm67/all-torvo (
xtramed/fr/AGENTS.md). Install upstream withnpx skills add diamondzm67/all-torvo --skill fr. Copyright stays with the author.
AGENTS.md — XTRAMED Frontend
First commands
pnpm install # install deps (pnpm, not npm)
cp .env.example .env.local
pnpm dev # next dev --webpack on localhost:3000 (Turbopack hangs on Tailwind v4 + next-intl in dev)
pnpm build # must pass before any commit (strict TS, zero errors)
Verify before committing
pnpm build # primary gate — strict TS, no errors tolerated
pnpm lint # ESLint (flat config, next core-web-vitals + TS)
pnpm test # Vitest (jsdom)
pnpm format:check # Prettier (double quotes, trailing commas, 100 width)
Pre-commit hook runs npx lint-staged (ESLint --fix + Prettier --write on staged files).
Architecture
- Next.js 16 App Router with
[locale]route group →(public),(auth),(account),(admin)subgroups - pnpm workspace (single project, not a monorepo)
- Tailwind CSS v4 with
@tailwindcss/postcss; shadcn/ui (style:base-nova); custom "Desert Wellness" theme with custom color tokens (terracotta, sage, gold, earth) - Path alias:
@/*→./src/*(tsconfig:baseUrl: "src",paths: { "@/*": ["./*"] }) - Real backend API — all calls go through axios client to
NEXT_PUBLIC_API_URL
State management
| Layer | Tool | Notes |
|---|---|---|
| Server state | TanStack Query v5 | Query keys: ['products', filters], ['products', slug], ['cart'], etc. |
| Auth / UI / guest cart | Zustand v5 | authStore persisted to localStorage; guestCartStore persisted; preferencesStore persisted; adminStore not persisted |
| Forms | React Hook Form v7 + Zod + @hookform/resolvers |
|
| i18n | next-intl | 10 namespaces (common, products, cart, checkout, auth, account, blog, admin, errors, validation) |
Key convention: Feature modules live in src/features/<name>/ with subdirs api/ (TanStack Query hooks), components/, hooks/, schemas/. Barrel exports from index.ts.
i18n & RTL
- Default locale:
"ar"(Arabic). Locale prefix"always"— all URLs shaped/en/...or/ar/... - All components use logical CSS properties (
ps-4,pe-4,text-start,text-end,border-e-0) — neverleft/right - Translation audit:
npx tsx scripts/check-translations.tsscans source foruseTranslations('ns')+t('key')and verifies every key exists in bothen/andar/JSON
Testing
- Vitest tests in
src/__tests__/**/*.test.{ts,tsx} jsdomenvironment- Run single file:
pnpm test -- src/__tests__/components/smoke.test.tsx
Env vars (Zod-validated in src/lib/env.ts)
NEXT_PUBLIC_API_URL (default: http://localhost:3000/api)
NEXT_PUBLIC_SITE_URL (default: http://localhost:3000)
NEXT_PUBLIC_INSTAPAY_KEY (optional)
Important conventions
- Use
cn()from@/lib/utils(clsx + tailwind-merge) for conditional classes - All data types in
src/types/with barrel export fromindex.ts— never inline type definitions - Service functions in
src/services/(barrel export) — API hooks call services - Axios client in
src/lib/api-client.tswith 401 refresh interceptor and global error toast - Stale times in
src/lib/query-client.ts: products 5min, orders 30s, cart/search 0ms
Project structure (top-level src/)
src/
app/ Next.js App Router + [locale]/ route groups
components/ ui/ (shadcn), shared/ (custom), layouts/, homepage/
features/ 16 feature modules, each with api/ components/ hooks/ schemas/
hooks/ Shared custom hooks (useDebounce, useMediaQuery, ...)
i18n/ en/ + ar/ translation JSON files, routing.ts, request.ts
lib/ utils, constants, routes, env, api-client, query-client
services/ API service functions (barrel export)
store/ Zustand stores (authStore, guestCartStore, preferencesStore, adminStore)
types/ 11 type files + barrel export
stories/ Storybook stories
__tests__/ Vitest tests