# Worklenz Cursor Rules for AI Assistants ## ๐ŸŽฏ Project Overview Worklenz is a full-stack project management application with React frontend, Node.js/Express backend, and PostgreSQL database. This document provides cursor rules for AI assistants working on this codebase. ## ๐Ÿ“‹ General Development Rules ### ๐ŸŽจ UI/UX Guidelines - **Always consider dark/light theme compatibility** when creating or modifying UI components - **No hardcoded text** - all user-facing strings must use i18next localization - **Follow Ant Design patterns** - use existing components and design tokens consistently - **Responsive design** - ensure components work on mobile, tablet, and desktop - **Accessibility first** - include proper ARIA labels, keyboard navigation, and screen reader support ### ๐Ÿ”ง Code Quality Standards - **TypeScript strict mode** - use strict typing, avoid `any` types - **Functional programming** - prefer functional patterns over classes - **Descriptive naming** - use auxiliary verbs (e.g., `isLoading`, `hasError`, `canEdit`) - **Modular structure** - break down complex components into smaller, reusable pieces - **Performance conscious** - use React.memo, useMemo, useCallback appropriately ### ๐Ÿ“ File Organization ``` # Component file structure pattern export const MainComponent = () => { /* main component */ }; const SubComponent = () => { /* subcomponent */ }; const AnotherSubComponent = () => { /* another subcomponent */ }; // Helper functions const formatData = (data: DataType) => { /* helper logic */ }; const validateInput = (input: string) => { /* validation logic */ }; // Static content const DEFAULT_CONFIG = { /* static configuration */ }; const ERROR_MESSAGES = { /* error messages */ }; // Types and interfaces interface ComponentProps { data: DataType; onSubmit: (value: string) => void; } ``` ## ๐Ÿš€ Frontend-Specific Rules ### React/TypeScript Patterns - **Prefer interfaces over types** for object shapes - **Use custom hooks** for reusable logic (auth, API calls, socket connections) - **Implement error boundaries** for graceful error handling - **Follow Redux Toolkit patterns** for state management - **Use React 18 features** (Suspense, concurrent rendering) ### Component Development ```typescript // โœ… Preferred: Named export with proper typing interface TaskCardProps { task: IProjectTask; onUpdate: (taskId: string, updates: Partial) => void; isSelected?: boolean; } export const TaskCard: React.FC = ({ task, onUpdate, isSelected = false }) => { // Component logic }; // โŒ Avoid: Default export, unnecessary React.FC const TaskCard = (props: any) => { // Component logic }; export default TaskCard; ``` ### State Management - **Use Redux Toolkit** for global state management - **Feature-based organization** - group related actions, reducers, selectors - **Typed selectors** with proper error handling - **Optimistic updates** for better UX, with rollback on failure ### API Integration - **RTK Query for server state** - use existing API services pattern - **Proper error handling** - use try/catch with user-friendly error messages - **Loading states** - always show loading indicators for async operations - **Cache management** - invalidate cache appropriately on mutations ## ๐Ÿ—๏ธ Backend-Specific Rules ### Express.js Patterns - **MVC structure** - controllers handle business logic, routes define endpoints - **Middleware chain** - authentication, validation, error handling - **Consistent response format** - use established response patterns - **Input validation** - validate all inputs, never trust client data ### Database Operations - **Use transactions** for multi-table operations - **Prepared statements** - prevent SQL injection - **Proper indexing** - consider query performance - **Migration safety** - ensure migrations are reversible - **Primary keys must be UUIDs** - use `UUID` for table PK columns, not serial/integer IDs - **UUID default generation** - define PK defaults as `uuid_generate_v4()` (ensure `uuid-ossp` extension is available in migrations) ### Socket.IO Implementation - **Namespace organization** - use appropriate namespaces for different features - **Event naming** - consistent, descriptive event names - **Error handling** - handle socket errors gracefully - **Connection management** - handle disconnects and reconnections ## ๐Ÿ”„ Real-time Features ### WebSocket Events - **Consistent event naming** - use established patterns - **Proper typing** - type all event payloads - **Error handling** - handle connection failures - **Performance** - avoid sending unnecessary updates ### Collaboration Features - **Optimistic updates** - update UI immediately, rollback on failure - **Conflict resolution** - handle concurrent modifications - **User feedback** - show who made changes and when ## ๐ŸŽจ Styling Guidelines ### Tailwind CSS Usage - **Utility-first approach** - use Tailwind classes primarily - **Consistent spacing** - use established spacing scale - **Dark mode support** - test all components in both themes - **Responsive design** - use responsive utilities appropriately ### Ant Design Integration - **Follow design tokens** - use theme variables, not hardcoded colors - **Consistent component usage** - use established component patterns - **Custom styling** - extend rather than override Ant Design styles - **Theme awareness** - respect user's theme preference ## ๐Ÿ“ Localization Rules ### i18next Integration - **No hardcoded strings** - all user text must be localized - **Always include defaultValue** - every `t()` call must include a `defaultValue` parameter for fallback text - Example: `t('taskNameColumn', { defaultValue: 'Task' })` - This ensures graceful degradation when translation keys are missing - **Namespace organization** - group related strings by feature - **Pluralization support** - use i18next pluralization features - **Interpolation** - use variables safely with proper escaping ### Translation Structure ``` public/locales/en/ โ”œโ”€โ”€ common.json # Shared strings โ”œโ”€โ”€ auth.json # Authentication โ”œโ”€โ”€ tasks.json # Task management โ”œโ”€โ”€ projects.json # Project management โ””โ”€โ”€ settings.json # User settings ``` ## ๐Ÿงช Testing Guidelines ### Component Testing - **React Testing Library** for component testing - **User-centric testing** - test user interactions, not implementation details - **Accessibility testing** - include a11y checks - **Visual regression** - test component appearance ### API Testing - **Integration tests** for API endpoints - **Database isolation** - use test database or transactions - **Authentication testing** - test protected routes - **Error scenarios** - test error conditions and edge cases ## ๐Ÿš€ Performance Optimization ### Frontend Performance - **Code splitting** - use dynamic imports for large components - **Virtualization** - for large lists (react-window) - **Image optimization** - use appropriate formats and sizes - **Bundle analysis** - monitor bundle size and dependencies ### Backend Performance - **Database optimization** - use proper indexes and query optimization - **Caching strategy** - implement appropriate caching layers - **Rate limiting** - protect against abuse - **Monitoring** - implement performance monitoring ## ๐Ÿ”’ Security Guidelines ### Frontend Security - **XSS prevention** - sanitize user input, use React's built-in protection - **CSRF protection** - use established CSRF tokens - **Secure storage** - never store sensitive data in localStorage - **Input validation** - validate all user inputs ### Backend Security - **Authentication** - use established auth patterns - **Authorization** - check permissions on all protected routes - **Data validation** - validate and sanitize all inputs - **SQL injection prevention** - use prepared statements ## ๏ฟฝ Authentication & Security Configuration ### CSRF Protection Worklenz uses CSRF (Cross-Site Request Forgery) protection for the main application API routes. #### Backend Configuration **Location**: `worklenz-backend/src/app.ts` ```typescript // CSRF protection is applied to /api/v1 routes app.use("/api/v1", apiLimiter, isLoggedIn, apiRouter); // Client portal routes are EXCLUDED from CSRF protection app.use("/api/client-portal", apiLimiter, clientPortalApiRouter); ``` **CSRF Exclusion Middleware**: ```typescript app.use((req, res, next) => { // Exclude client portal endpoints (they use client token authentication) if (req.path.startsWith("/client-portal") || req.originalUrl.startsWith("/api/client-portal")) { return next(); } // Apply CSRF protection to state-changing operations const isStateChanging = ['POST', 'PUT', 'DELETE', 'PATCH'].includes(req.method); if (isStateChanging) { csrfSynchronisedProtection(req, res, next); } else { next(); } }); ``` #### Frontend Configuration (Main App) **Location**: `worklenz-frontend/src/api/api-client.ts` ```typescript // CSRF token management export const getCsrfToken = (): string | null => { return localStorage.getItem('csrfToken'); }; export const refreshCsrfToken = async (): Promise => { // Fetch new CSRF token from backend const response = await fetch('/api/v1/csrf-token'); const { token } = await response.json(); localStorage.setItem('csrfToken', token); return token; }; // RTK Query configuration with CSRF prepareHeaders: async headers => { let token = getCsrfToken(); if (!token) { token = await refreshCsrfToken(); } if (token) { headers.set('X-CSRF-Token', token); } return headers; } ``` **Key Points**: - CSRF tokens are stored in `localStorage` - Tokens are automatically refreshed when missing - All state-changing requests include `X-CSRF-Token` header - CSRF protection applies to `/api/v1/*` routes only ### Client Portal Authentication The Client Portal uses a **separate authentication mechanism** with client-specific tokens. #### Two Frontend Applications 1. **Main Admin App** (`worklenz-frontend`) - For organization/admin users - Uses session-based auth + CSRF tokens - Manages client portal data from admin perspective - Base URL: `/api/v1` or `/api` (depending on API) 2. **Client Portal App** (`worklenz-client-portal`) - For client users - Uses `x-client-token` authentication - Direct client access to their data - Base URL: `/api/client-portal` #### Client Portal Backend Routes **Location**: `worklenz-backend/src/routes/apis/client-portal-api-router.ts` ```typescript const router = express.Router(); // Public routes (no authentication) router.post("/auth/login", safeControllerFunction(ClientPortalAuthController.clientLogin)); router.get("/invitation/validate", safeControllerFunction(ClientPortalAuthController.validateInvitation)); // Protected routes (require client authentication) router.use(authenticateClient); router.get("/dashboard", safeControllerFunction(ClientPortalDashboardController.getDashboard)); router.get("/invoices", safeControllerFunction(ClientPortalInvoicesController.getInvoices)); router.post("/invoices", safeControllerFunction(ClientPortalInvoicesController.createInvoice)); router.delete("/invoices/:id", safeControllerFunction(ClientPortalInvoicesController.deleteInvoice)); // ... more routes ``` #### Client Authentication Middleware **Location**: `worklenz-backend/src/middlewares/client-auth-middleware.ts` ```typescript export const authenticateClient = async ( req: AuthenticatedClientRequest, res: Response, next: NextFunction ) => { // Get client token from headers or query params const clientToken = req.headers["x-client-token"] || req.query.clientToken; if (!clientToken) { return res.status(401).json( new ServerResponse(false, null, "Client token is required") ); } // Verify client token const tokenPayload = TokenService.verifyClientToken(clientToken as string); if (!tokenPayload) { return res.status(401).json( new ServerResponse(false, null, "Invalid or expired client token") ); } // Attach client info to request req.clientId = tokenPayload.clientId; req.organizationId = tokenPayload.organizationId; next(); }; ``` #### Client Portal Frontend Configuration **For Client Portal App** (`worklenz-client-portal/src/store/api.ts`): ```typescript export const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: '/api/client-portal', prepareHeaders: (headers) => { const token = localStorage.getItem('clientToken'); if (token) { headers.set('x-client-token', token); } return headers; }, }), }); ``` **For Admin App** (`worklenz-frontend/src/api/client-portal/client-portal-api.ts`): ```typescript export const clientPortalApi = createApi({ reducerPath: 'clientPortalApi', baseQuery: fetchBaseQuery({ baseUrl: `${config.apiUrl}${API_BASE_URL}`, // /api/v1 prepareHeaders: async headers => { // Admin app uses CSRF tokens let token = getCsrfToken(); if (!token) { token = await refreshCsrfToken(); } if (token) { headers.set('X-CSRF-Token', token); } return headers; }, credentials: 'include', }), endpoints: builder => ({ // Endpoints use /clients/portal/* paths for admin management getInvoices: builder.query({ query: () => '/clients/portal/invoices', // Becomes /api/v1/clients/portal/invoices }), }), }); ``` ### API Path Configuration Summary | Frontend App | Base URL | Auth Method | Backend Route | Example Full URL | |--------------|----------|-------------|---------------|------------------| | Main Admin | `/api/v1` | CSRF Token + Session | `/api/v1/*` | `/api/v1/projects` | | Admin (Client Portal Mgmt) | `/api/v1` | CSRF Token + Session | `/api/v1/clients/portal/*` | `/api/v1/clients/portal/invoices` | | Client Portal App | `/api/client-portal` | x-client-token | `/api/client-portal/*` | `/api/client-portal/dashboard` | ### Common Authentication Issues #### Issue: 401 Unauthorized on Client Portal Routes **Cause**: Missing or invalid `x-client-token` header **Solution**: ```typescript // Ensure token is stored after login localStorage.setItem('clientToken', token); // Ensure token is sent in requests headers.set('x-client-token', localStorage.getItem('clientToken')); ``` #### Issue: 404 Not Found on API Calls **Cause**: Incorrect base URL or endpoint path configuration **Solution**: - **Admin managing client portal**: Use base URL `/api/v1` with endpoint paths `/clients/portal/*` - Example: `/api/v1/clients/portal/invoices` - **Client portal app**: Use base URL `/api/client-portal` with endpoint paths starting with `/` - Example: `/api/client-portal/dashboard` - **Main admin app**: Use base URL `/api/v1` with standard paths - Example: `/api/v1/projects` #### Issue: CSRF Token Mismatch **Cause**: Client portal routes receiving CSRF protection **Solution**: Ensure client portal routes are excluded in `app.ts`: ```typescript if (req.path.startsWith("/client-portal") || req.originalUrl.startsWith("/api/client-portal")) { return next(); // Skip CSRF protection } ``` ### Security Best Practices 1. **Never mix authentication methods** - Main app routes: Use CSRF tokens - Client portal routes: Use x-client-token - Don't apply CSRF to client portal routes 2. **Token storage** - CSRF tokens: `localStorage.getItem('csrfToken')` - Client tokens: `localStorage.getItem('clientToken')` - Never expose tokens in URLs or logs 3. **Route organization** - Client-facing portal routes: `/api/client-portal/*` (uses x-client-token) - Admin portal management routes: `/api/v1/clients/portal/*` (uses session + CSRF) - Main app routes: `/api/v1/*` (uses session + CSRF) - Use clear separation in route files 4. **Error handling** - Return 401 for authentication failures - Return 403 for authorization failures - Provide clear error messages for debugging ## ๏ฟฝ๐Ÿ“š Documentation Standards ### Code Documentation - **JSDoc comments** for complex functions and components - **Interface documentation** - document props and return types - **Usage examples** - provide examples for complex APIs - **README updates** - update documentation for significant changes ### API Documentation - **OpenAPI/Swagger** for API endpoints - **Request/response examples** - provide clear examples - **Error responses** - document error conditions - **Authentication** - document auth requirements ## ๐Ÿ”ง Development Workflow ### Git Practices - **Feature branches** - create branches for new features - **Descriptive commits** - write clear, concise commit messages - **Code review** - follow established review process - **Testing** - ensure tests pass before merging ### Code Review Checklist - [ ] TypeScript types are correct and complete - [ ] Component follows established patterns - [ ] No hardcoded strings (i18n used) - [ ] Dark/light theme compatibility - [ ] Responsive design implemented - [ ] Tests included for new functionality - [ ] Performance considerations addressed - [ ] Security implications reviewed ## ๐ŸŽฏ Task-Specific Rules ### New Feature Development 1. **Understand requirements** - clarify acceptance criteria 2. **Explore existing code** - find similar patterns to follow 3. **Plan implementation** - consider all affected components 4. **Implement incrementally** - build and test small pieces 5. **Add tests** - ensure new functionality is tested 6. **Update documentation** - document any API changes ### Bug Fixes 1. **Reproduce the issue** - understand the problem 2. **Identify root cause** - trace through the code 3. **Fix the issue** - implement the minimal fix 4. **Add regression test** - prevent future occurrences 5. **Verify fix** - test in multiple scenarios ### Refactoring 1. **Understand impact** - identify all affected code 2. **Plan incrementally** - avoid large breaking changes 3. **Maintain tests** - ensure tests still pass 4. **Update types** - keep TypeScript definitions current 5. **Document changes** - explain the refactoring rationale --- ## ๐Ÿšจ Critical Rules ### Never Do These Things: - โŒ **Hardcode user-facing text** - always use i18next - โŒ **Use `any` type** - maintain strict TypeScript typing - โŒ **Ignore theme compatibility** - all UI must support dark/light modes - โŒ **Skip error handling** - always handle errors gracefully - โŒ **Break existing API contracts** - maintain backward compatibility - โŒ **Ignore accessibility** - all features must be accessible - โŒ **Skip testing** - all features must be tested ### Always Do These Things: - โœ… **Follow established patterns** - maintain consistency - โœ… **Add proper TypeScript types** - ensure type safety - โœ… **Test in both themes** - verify dark/light mode compatibility - โœ… **Include error handling** - handle failures gracefully - โœ… **Add loading states** - provide user feedback - โœ… **Document complex logic** - help future developers - โœ… **Consider performance impact** - optimize where possible - โœ… **Use UUID PKs in DB tables** - standardize on `UUID` primary keys with `uuid_generate_v4()` defaults --- ## ๐ŸŽ‰ Best Practices Summary 1. **Quality First** - Write clean, well-typed, tested code 2. **User Experience** - Consider accessibility, performance, and usability 3. **Consistency** - Follow established patterns and conventions 4. **Collaboration** - Write code that's easy for others to understand 5. **Maintenance** - Consider long-term maintainability and scalability Remember: Good code is not just functional, but also maintainable, accessible, and delightful to work with! ๐Ÿš€ --- ## ๐ŸŽจ UI Design Instructions (Synced from `design.md`) The section below is copied from `/design.md` and is the default UI design guidance for this repository. # Worklenz UI Design Instructions Last updated: 2026-04-23 This file defines the UI design rules for this repository. Use it as the source of truth when creating or modifying UI in: - `worklenz-frontend` - `worklenz-client-portal` ## 1. Design Principles - Build for clarity first: dense product UI is acceptable, confusion is not. - Preserve consistency with existing Worklenz patterns before introducing new visual language. - Prefer Ant Design components and design tokens over custom primitives. - Every UI change must work in both `light` and `dark` themes. - Every user-facing string must be localized; no hardcoded UI text. ## 2. Theming and Tokens Use theme tokens from Ant Design `ConfigProvider` and `theme.useToken()`. Baseline repo tokens currently include: - `colorPrimary: #1890ff` - `borderRadius: 6` - `colorBgLayout`: `#f5f5f5` (light), `#141414` (dark) - `colorBgContainer`: `#ffffff` (light), `#1f1f1f` (dark) - `colorText`: `rgba(0,0,0,0.88)` (light), `rgba(255,255,255,0.85)` (dark) - `colorTextSecondary`: `rgba(0,0,0,0.65)` (light), `rgba(255,255,255,0.65)` (dark) ### Rules - Do not hardcode one-off hex colors inside components when an existing token can express the same intent. - For conditional theme values, prefer token-driven variants or centralized helper utilities. - Keep component radii aligned with the system (`6` for controls, `8` for larger containers/cards/tables). ## 3. Typography - Primary typeface is Inter/system stack configured in theme. - Maintain readable hierarchy: - Page title: `20-28px` - Section title: `16-20px` - Body text: `13-15px` - Meta/helper text: `12-13px` - Avoid ultra-light weights for core information. - Keep line-length practical for data-heavy screens. ## 4. Layout and Spacing - Use existing layout shells and Ant Design layout primitives (`Layout`, `Row`, `Col`, `Flex`, `Space`). - Follow an 8px rhythm where practical (`4/8/12/16/24/32`). - Prefer consistent gutter/padding values within a screen. - Keep table/filter/action bars sticky only when it solves a real navigation problem. ## 5. Component Rules ### Forms - Use Ant Design `Form` validation patterns. - Show validation feedback near the field and keep error copy actionable. - Required fields must be clearly indicated. ### Tables and Lists - Optimize for scanning: - stable column alignment - predictable action locations - restrained row hover/focus styles - Row actions should not jump layout when revealed. - For large data sets, use pagination or virtualization patterns already present in the repo. ### Buttons and Actions - One clear primary action per section/modal. - Avoid multiple high-emphasis buttons in the same action group. - Destructive actions require confirmation. ### Empty, Loading, Error States - Every async screen must define all three states. - Empty states should explain next action. - Error states should provide recovery action (retry/back/contact). ## 6. Responsive Behavior - Must support desktop, tablet, and mobile breakpoints. - On narrower screens: - collapse non-critical columns/content - keep primary actions reachable - avoid horizontal scrolling unless data-table context requires it - Validate modal/drawer behavior for small screens. ## 7. Accessibility - Ensure keyboard navigation for interactive controls. - Preserve visible focus states; do not remove focus outline without replacement. - Use semantic controls and ARIA attributes when semantics are not implicit. - Maintain adequate text/background contrast in both themes. - Icon-only buttons require accessible labels/tooltips. ## 8. Motion and Feedback - Keep motion subtle and functional (`150-300ms` for most transitions). - Prefer opacity/transform transitions over expensive layout-affecting animation. - Use progress indicators for operations above ~300ms. - Do not animate large surfaces unnecessarily in data-dense workflows. ## 9. Localization Rules (Mandatory) - No hardcoded user-facing text in JSX/TSX. - Use i18next for all labels, buttons, placeholders, messages, and headings. - Always include `defaultValue` in translation calls. - Use interpolation/pluralization features for dynamic content. ## 10. Implementation Do/Don't ### Do - Reuse existing components/patterns before introducing new ones. - Use token-based colors and spacing. - Test in both themes and at multiple viewport sizes. - Keep UX consistent between `worklenz-frontend` and `worklenz-client-portal` where behavior overlaps. ### Don't - Introduce theme-breaking hardcoded colors. - Add new visual patterns for common controls without a product-level reason. - Ship UI that only looks correct in one theme. - Merge features with missing loading/error/empty states. ## 11. PR Checklist for UI Changes - [ ] Works in light theme - [ ] Works in dark theme - [ ] Uses i18n (no hardcoded strings) - [ ] Uses Ant Design patterns and tokens - [ ] Keyboard and focus behavior verified - [ ] Responsive behavior verified - [ ] Loading, empty, and error states covered - [ ] No obvious layout shift or performance regressions