# Claude Code Guidelines for Atlas CMMS This document provides guidelines for Claude Code when working on this Vue.js 3 CMMS application. ## ⚠️ CRITICAL: STRICT ENFORCEMENT OF PATTERNS **NEVER REINVENT THE WHEEL - ALWAYS COPY EXISTING WORKING IMPLEMENTATIONS** Before writing ANY new code: 1. **SEARCH for existing similar implementations** in the codebase 2. **COPY the exact pattern** from working examples 3. **DO NOT modify or "improve" existing patterns** 4. **DO NOT mix business logic with view components** **Token Conservation Rules:** - Violating separation of concerns = wasted tokens on rewrites - Reinventing existing patterns = wasted tokens on rewrites - Not following established UI patterns = wasted tokens on rewrites **When implementing any new feature:** 1. Find the most similar existing feature (vendors, assets, work orders, etc.) 2. Copy the EXACT file structure and implementation 3. Only change the entity-specific details (names, fields, etc.) 4. NEVER change the architectural patterns **If you violate these rules, you are wasting the user's tokens and usage limits.** ## Architecture Guidelines ### Separation of Concerns - **Always create composables for business logic** - Use the `use*` pattern (e.g., `useQRCode`, `useAssetManagement`) - **Components should be thin** - Components handle UI rendering, user interactions, and state presentation only - **Extract business logic to composables** - Data processing, API calls, complex calculations belong in composables - **Follow Vue 3 Composition API best practices** - Use reactive refs, computed properties, and watchers appropriately ### Code Organization Patterns #### Composables Structure ``` src/composables/ ├── assets/ │ ├── useAssetManagement.js │ ├── useQRCode.js │ └── useAssetAnalytics.js ├── workorders/ └── shared/ ``` #### Component Structure ```vue ``` ### What Goes Where #### Composables Should Handle: - Business logic and calculations - Data transformation and validation - Local reactive state (component-specific refs, computed) - Complex operations (QR generation, file processing, etc.) - Reusable functionality across components - Orchestrating between repositories and stores #### Components Should Handle: - Template rendering and UI structure - User interaction events (clicks, inputs) - UI-specific state (modals, loading states) - Props validation and emitting events - Basic data formatting for display - Component lifecycle management #### Repositories Should Handle: - All API calls and HTTP requests - Data fetching and posting to backend - Request/response transformation - API error handling and retry logic - Authentication headers and request configuration - Endpoint management and URL construction #### Pinia Stores Should Handle: - Global application state - Cross-component data sharing - Persistent state management - State mutations and actions - Computed state (getters) - State synchronization with backend data ### Test-Driven Development (TDD) Process **ALWAYS follow TDD - Write tests FIRST, then implementation:** 1. **Write the test** - Define expected behavior with failing tests 2. **Write minimal code** - Make the test pass with simplest implementation 3. **Refactor** - Improve code while keeping tests green 4. **Repeat** - Continue with next test case ### Implementation Checklist Before implementing new features, ask: 1. **Have you written the test first?** → TDD is mandatory 2. **Is there business logic?** → Create a composable (with tests) 3. **Will this be reused?** → Create a composable (with tests) 4. **Does it involve data processing?** → Use a composable (with tests) 5. **Is it purely UI-related?** → Keep in component (with tests) 6. **Does it need API calls?** → Use a repository (with tests) 7. **Does it manage global state?** → Use a Pinia store (with tests) 8. **Does it need cross-component data sharing?** → Use a Pinia store (with tests) 9. **Is it local component state?** → Use reactive refs in composable or component (with tests) ### Examples #### ✅ Good: Proper Separation of Concerns ```vue ``` #### ✅ Good: TDD Example - Write Test First ```javascript // __tests__/useQRCode.test.js import { describe, it, expect, vi } from 'vitest' import { useQRCode } from '@/composables/assets/useQRCode' describe('useQRCode', () => { it('should generate QR code with valid asset data', async () => { const { generateQRCode } = useQRCode() const assetData = { name: 'Test Asset', assetNumber: 'AST-001' } const result = await generateQRCode(assetData) expect(result.qrCode).toContain('data:image/png;base64') expect(result.data.name).toBe('Test Asset') }) it('should throw error for invalid asset data', async () => { const { generateQRCode } = useQRCode() const invalidData = {} await expect(generateQRCode(invalidData)).rejects.toThrow() }) }) ``` #### ✅ Good: Repository Pattern with JSDoc ```javascript // AssetRepository.js /** * Repository for handling asset-related API operations */ export class AssetRepository extends BaseRepository { /** * Create a new asset * @param {Object} assetData - The asset data to create * @param {string} assetData.name - Asset name * @param {string} assetData.category - Asset category * @returns {Promise} Created asset data */ async createAsset(assetData) { return this.post('/assets', assetData) } /** * Update an existing asset * @param {string} id - Asset ID to update * @param {Object} assetData - Updated asset data * @returns {Promise} Updated asset data */ async updateAsset(id, assetData) { return this.put(`/assets/${id}`, assetData) } } ``` #### ✅ Good: Pinia Store Pattern with JSDoc ```javascript // stores/assets.js import { defineStore } from 'pinia' import { AssetRepository } from '@/services/repositories/AssetRepository' /** * Asset store for managing global asset state */ export const useAssetStore = defineStore('assets', { state: () => ({ /** @type {Array} */ assets: [], /** @type {Object|null} */ currentAsset: null, /** @type {boolean} */ loading: false, /** @type {string|null} */ error: null }), getters: { /** * Get asset by ID * @param {Object} state * @returns {function(string): Object|undefined} */ getAssetById: (state) => (id) => { return state.assets.find(asset => asset.id === id) } }, actions: { /** * Create a new asset * @param {Object} assetData - Asset data to create * @returns {Promise} Created asset */ async createAsset(assetData) { this.loading = true this.error = null try { const newAsset = await AssetRepository.createAsset(assetData) this.assets.push(newAsset) return newAsset } catch (error) { this.error = error.message throw error } finally { this.loading = false } } } }) ``` #### ✅ Good: Composable with JSDoc and TDD ```javascript // composables/assets/useAssetManagement.js import { ref, computed } from 'vue' /** * Composable for asset management business logic * @returns {Object} Asset management methods and state */ export function useAssetManagement() { /** @type {import('vue').Ref} */ const error = ref(null) /** * Validate asset data * @param {Object} assetData - Asset data to validate * @param {string} assetData.name - Asset name * @param {string} assetData.category - Asset category * @returns {boolean} Whether asset data is valid */ const validateAsset = (assetData) => { error.value = null if (!assetData.name || assetData.name.trim().length === 0) { error.value = 'Asset name is required' return false } if (!assetData.category) { error.value = 'Asset category is required' return false } return true } /** * Process asset data before saving * @param {Object} rawData - Raw form data * @returns {Object} Processed asset data */ const processAssetData = (rawData) => { return { ...rawData, name: rawData.name?.trim(), createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() } } return { error: computed(() => error.value), validateAsset, processAssetData } } ``` #### ❌ Bad: No Tests Written First ```javascript // Don't write implementation without tests first export function useAssetManagement() { // Implementation without tests = bad practice const validateAsset = (assetData) => { // Complex logic without tests to verify behavior } } ``` #### ❌ Bad: API Calls in Components ```vue ``` #### ❌ Bad: No JSDoc Documentation ```javascript // Don't skip documentation export function useAssetManagement() { const validateAsset = (assetData) => { // No documentation about parameters or return values } } ``` ## Vue.js 3 + Pinia Specific Guidelines - **Use JavaScript consistently** - No TypeScript, pure JavaScript with JSDoc for type hints - Use Composition API consistently - Prefer `