Skip to content

Commit aa36dd6

Browse files
authored
docs: add CLAUDE.md with project conventions and codebase guide (#210)
1 parent 1440bab commit aa36dd6

1 file changed

Lines changed: 268 additions & 0 deletions

File tree

CLAUDE.md

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
# CLAUDE.md - PolyPay App
2+
3+
## Project Overview
4+
5+
PolyPay is a privacy-preserving payroll platform built on Horizen blockchain. It enables organizations, DAOs, and global teams to run payroll privately using zero-knowledge proofs (Noir circuits). Key features: private payments, private multisig approvals, escrow/milestone-based transfers, real-time notifications via WebSocket, and JWT authentication.
6+
7+
## Tech Stack
8+
9+
**Monorepo** (Yarn Workspaces, Node.js >= 20.18.3)
10+
11+
| Layer | Stack |
12+
|-------|-------|
13+
| Frontend | Next.js 15, React 19, TypeScript 5.8, Tailwind CSS 4 + DaisyUI 5 |
14+
| State | Zustand 5 (persist middleware), TanStack React Query 5 |
15+
| Forms | React Hook Form 7 + Zod 3 |
16+
| Web3 | wagmi 2, viem 2, RainbowKit 2, Uniswap SDK |
17+
| ZK | @noir-lang/noir_js, @aztec/bb.js |
18+
| UI | Radix UI + shadcn/ui pattern, CVA for variants, Lucide React icons |
19+
| Notifications | Sonner (primary), react-hot-toast (secondary) |
20+
| Real-time | socket.io-client |
21+
| Backend | NestJS 11, TypeScript 5.7, Prisma 7 (PostgreSQL), JWT auth |
22+
| Smart Contracts | Hardhat 2, Solidity, OpenZeppelin 5, Poseidon circuits |
23+
| Shared | @polypay/shared - DTOs with class-validator/class-transformer |
24+
25+
## Folder Structure
26+
27+
```
28+
/
29+
├── docker/ # Docker Compose, Dockerfiles, .env.example
30+
├── docs/ # Gitbook documentation
31+
├── packages/
32+
│ ├── nextjs/ # Frontend (Next.js App Router)
33+
│ │ ├── app/ # Pages (dashboard, transfer, batch, contact-book, quest, leaderboard)
34+
│ │ ├── components/
35+
│ │ │ ├── ui/ # Base UI components (shadcn pattern: button, input, dialog...)
36+
│ │ │ ├── form/ # Form components (Form, FormField, FormInput, FormTextarea)
37+
│ │ │ ├── Common/ # Shared components (Sidebar, DisclaimerChecker)
38+
│ │ │ ├── Dashboard/ # Dashboard feature components
39+
│ │ │ ├── Transfer/ # Transfer flow components
40+
│ │ │ ├── Batch/ # Batch operation components
41+
│ │ │ ├── NewAccount/ # Account creation components
42+
│ │ │ ├── modals/ # Modal dialogs (~22 modals, lazy-loaded via ModalRegistry)
43+
│ │ │ ├── skeletons/ # Loading skeleton components
44+
│ │ │ └── icons/ # Custom icon components
45+
│ │ ├── hooks/
46+
│ │ │ ├── api/ # React Query hooks (useTransaction, useAccount, useNotifications...)
47+
│ │ │ ├── app/ # App logic hooks (useAuth, useGenerateProof, useSocketEvent...)
48+
│ │ │ ├── form/ # Form hooks (useZodForm)
49+
│ │ │ └── scaffold-eth/ # Scaffold-eth hooks
50+
│ │ ├── services/
51+
│ │ │ ├── api/ # Axios API services (apiClient, authApi, transactionApi...)
52+
│ │ │ ├── store/ # Zustand stores (useIdentityStore, useAccountStore...)
53+
│ │ │ ├── web3/ # Web3 utilities
54+
│ │ │ ├── socket/ # Socket.io client
55+
│ │ │ └── queryClient.ts # React Query config
56+
│ │ ├── utils/ # Utilities (formatError, errorHandler, signer, network...)
57+
│ │ ├── lib/form/ # Form schemas (Zod) and validation helpers
58+
│ │ ├── types/ # TypeScript types (modal, form, abitype)
59+
│ │ ├── constants/ # Constants (API_BASE_URL, timing)
60+
│ │ ├── configs/ # Route config, scaffold config
61+
│ │ └── contracts/ # Contract ABIs
62+
│ ├── backend/ # NestJS Backend
63+
│ │ └── src/
64+
│ │ ├── auth/ # JWT authentication module
65+
│ │ ├── account/ # Multi-sig account management
66+
│ │ ├── transaction/ # Transaction CRUD & voting
67+
│ │ ├── user/ # User management with ZK commitments
68+
│ │ ├── notification/ # Real-time notifications (WebSocket)
69+
│ │ ├── quest/ # Quest/gamification system
70+
│ │ ├── admin/ # Admin analytics
71+
│ │ ├── zkverify/ # ZK proof verification (Horizen)
72+
│ │ ├── common/ # Shared utilities & middleware
73+
│ │ ├── database/ # Prisma module
74+
│ │ └── ... # ~24 feature modules total
75+
│ ├── shared/ # Shared DTOs and types (@polypay/shared)
76+
│ └── hardhat/ # Smart contracts & deployment
77+
```
78+
79+
## Validation Commands
80+
81+
```bash
82+
# Root level
83+
yarn lint # ESLint (frontend + hardhat)
84+
yarn next:check-types # TypeScript type checking (frontend)
85+
yarn next:build # Production build (frontend)
86+
yarn build # Build all packages (shared → backend → frontend)
87+
yarn test # Run hardhat tests
88+
yarn format # Prettier format all packages
89+
90+
# Frontend (packages/nextjs)
91+
yarn dev # Dev server (port 3000)
92+
yarn build # Next.js production build
93+
yarn lint # ESLint
94+
yarn check-types # TypeScript check
95+
yarn format # Prettier
96+
97+
# Backend (packages/backend)
98+
yarn start:dev # Dev server with watch (port 4000)
99+
yarn lint # ESLint
100+
yarn format # Prettier
101+
yarn test # Jest unit tests
102+
yarn test:cov # Jest with coverage
103+
yarn test:e2e # End-to-end tests
104+
yarn test:e2e:staging # Staging E2E tests
105+
106+
# Smart Contracts (packages/hardhat)
107+
yarn chain # Local Hardhat node
108+
yarn compile # Compile contracts
109+
yarn deploy # Deploy contracts
110+
yarn test # Hardhat tests
111+
```
112+
113+
## Code Style & Conventions
114+
115+
### Naming
116+
- **Components**: PascalCase files and exports (`FormField.tsx`, `NotificationPanel.tsx`)
117+
- **Hooks**: camelCase with `use` prefix (`useZodForm.ts`, `useTransaction.ts`)
118+
- **Utils/Services**: camelCase (`apiClient.ts`, `formatError.ts`)
119+
- **Types/Interfaces**: PascalCase (`ModalProps`, `IdentityState`)
120+
- **Stores**: camelCase with `use` prefix (`useIdentityStore.ts`, `useAccountStore.ts`)
121+
- **API services**: camelCase with `Api` suffix (`transactionApi`, `authApi`)
122+
- **Constants**: UPPER_SNAKE_CASE (`API_BASE_URL`, `DEFAULT_PAGE_SIZE`)
123+
124+
### Import Order
125+
1. React / Next.js
126+
2. Third-party libraries
127+
3. @heroicons
128+
4. @polypay/shared
129+
5. Local imports (`~~/...`)
130+
131+
### Formatting (Prettier)
132+
- Print width: 120
133+
- Tab width: 2 spaces
134+
- Arrow parens: avoid
135+
- Trailing comma: all
136+
- Path alias: `~~/*` → project root, `@polypay/shared` → shared package
137+
138+
### Component Pattern
139+
- "use client" directive for client-side components
140+
- Functional components with hooks
141+
- Named exports for UI components, default exports for pages
142+
- Props interfaces defined inline in component files
143+
144+
## Common Patterns
145+
146+
### Design Tokens & Colors
147+
- **Source of truth**: `packages/nextjs/styles/tokens.ts` — all color definitions live here
148+
- **Sync script**: `packages/nextjs/styles/sync-colors.ts` — generates CSS variables into `globals.css` and Tailwind color config into `tailwind.config.ts`
149+
- **Command**: `yarn sync-colors` (from `packages/nextjs`)
150+
- **Flow**: Edit `tokens.ts` → run `yarn sync-colors` → CSS vars + Tailwind config auto-updated
151+
- **Never edit colors directly** in `globals.css` or `tailwind.config.ts` — they will be overwritten by the sync script
152+
153+
### State Management (Zustand)
154+
```typescript
155+
// services/store/useIdentityStore.ts
156+
// All stores use create() with persist middleware for localStorage
157+
const useIdentityStore = create<IdentityState>()(
158+
persist(
159+
(set) => ({
160+
accessToken: null,
161+
// ...state and actions
162+
setTokens: (access, refresh) => set({ accessToken: access, refreshToken: refresh }),
163+
logout: () => set({ accessToken: null, isAuthenticated: false }),
164+
}),
165+
{ name: "identity-storage" }
166+
)
167+
);
168+
// Use getState() for sync access outside React (e.g., in Axios interceptors)
169+
```
170+
171+
### API Services
172+
```typescript
173+
// services/api/transactionApi.ts
174+
// Object export pattern with typed async methods
175+
export const transactionApi = {
176+
getAll: async (params) => { const { data } = await apiClient.get(...); return data; },
177+
create: async (dto) => { const { data } = await apiClient.post(...); return data; },
178+
};
179+
```
180+
181+
### React Query Hooks
182+
```typescript
183+
// hooks/api/useTransaction.ts
184+
// Query key factory pattern for cache invalidation
185+
const transactionKeys = { all: ["transactions"], list: (filters) => [...] };
186+
// useInfiniteQuery for pagination, useMutation with onSuccess invalidation
187+
```
188+
189+
### Forms (React Hook Form + Zod)
190+
```typescript
191+
// useZodForm hook → Form component → FormField with Controller
192+
const form = useZodForm({ schema: contactSchema });
193+
// Zod schemas in lib/form/schemas.ts, reusable validators in lib/form/validation.ts
194+
```
195+
196+
### Error Handling
197+
```typescript
198+
// utils/formatError.ts - pattern matching for friendly error messages
199+
// utils/errorHandler.ts - ErrorCode enum, parseError(), handleError()
200+
// Axios interceptor handles 401 auto-refresh with token rotation
201+
```
202+
203+
### Notifications
204+
```typescript
205+
import { notification } from "~~/utils/scaffold-eth";
206+
notification.success("Transaction submitted!");
207+
notification.error(formatErrorMessage(error));
208+
```
209+
210+
### Real-time (Socket.io)
211+
```typescript
212+
// hooks/app/useSocketEvent.ts - wrapper with auto-cleanup on unmount
213+
useSocketEvent("transaction:updated", (data) => { /* handle */ });
214+
```
215+
216+
### Modals
217+
```typescript
218+
// Lazy-loaded via ModalRegistry with dynamic imports to prevent SSR issues
219+
// components/modals/ - ~22 modal components
220+
```
221+
222+
### Authenticated Queries
223+
```typescript
224+
// hooks/api/useAuthenticatedQuery.ts
225+
// Wrapper that auto-disables queries when user is not authenticated
226+
```
227+
228+
### Routes
229+
```typescript
230+
// configs/routes.config.ts - centralized route definitions
231+
// hooks/app/useAppRouter.ts - type-safe navigation (goToDashboard, goToTransfer, etc.)
232+
```
233+
234+
## Environment Setup
235+
236+
### Prerequisites
237+
- Node.js >= 20.18.3
238+
- Yarn (workspaces)
239+
- Docker & Docker Compose (for PostgreSQL)
240+
241+
## Do's and Don'ts
242+
243+
### Do's
244+
- Use `@polypay/shared` DTOs for API contracts between frontend and backend
245+
- Use `useZodForm` hook for all forms with Zod schemas
246+
- Use `notification.success/error/info` for user feedback
247+
- Use `formatErrorMessage()` for user-friendly error messages
248+
- Use `useAuthenticatedQuery` wrapper for queries requiring auth
249+
- Use query key factory pattern for React Query cache management
250+
- Use `useSocketEvent` hook for real-time subscriptions (auto-cleanup)
251+
- Use `~~/*` path alias for local imports
252+
- Use Zustand `persist` middleware for state that needs to survive refresh
253+
- Use `apiClient` (configured Axios instance) for all API calls
254+
- Follow feature-based component organization
255+
- Use Radix UI + CVA for new UI components (shadcn pattern)
256+
257+
### Don'ts
258+
- Don't import from `@polypay/shared` directly in smart contracts
259+
- Don't make API calls without going through `apiClient` (it handles auth tokens)
260+
- Don't create new notification systems - use existing `notification` utility or Sonner
261+
- Don't hardcode API URLs - use `API_BASE_URL` from constants
262+
- Don't skip Zod validation for forms - always define schemas
263+
- Don't store auth tokens manually - use `useIdentityStore`
264+
- Don't create new Zustand stores without `persist` middleware unless state is truly ephemeral
265+
- Don't use `useQuery` directly for authenticated endpoints - use `useAuthenticatedQuery`
266+
- Don't put business logic in components - extract to custom hooks in `hooks/app/`
267+
- Don't use inline styles - use Tailwind CSS classes
268+
- Don't commit `.env` files or expose secrets

0 commit comments

Comments
 (0)