# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview This is an HRMS (Human Resource Management System) check-in/check-out web application built for the Bangkok Metropolitan Administration (BMA). The application allows employees to record their work attendance using geolocation verification and camera features. **Tech Stack:** - Vue 3 with Composition API and TypeScript 4.7.4 - Vite for build tooling - Quasar Framework for UI components - Pinia for state management - Vue Router for routing - Keycloak for authentication - ArcGIS API and Google Maps for location features - PWA capabilities with offline support - Docker deployment with nginx **Development Server:** Runs on port 3008 ## Common Commands ```bash # Development npm run dev # Start dev server on port 3008 # Building npm run build # Build for production npm run preview # Preview production build on port 3008 # Testing npm run test:unit # Run unit tests with vitest npm run test:e2e # Run e2e tests with cypress npm run test:e2e:dev # Run cypress in dev mode # Code Quality npm run lint # Lint and auto-fix code npm run format # Format code with prettier npm run type-check # TypeScript type checking # Docker docker buildx build --platform=linux/amd64 -f docker/Dockerfile . -t hrms-checkin:0.1 ``` ## Architecture ### Directory Structure ``` src/ ├── api/ # API layer modules (checkin, history, message) ├── components/ # Reusable Vue components ├── composables/ # Vue composables (e.g., usePermissions) ├── interface/ # TypeScript type definitions │ └── response/ # API response types ├── plugins/ # Vue plugins (auth, http, keycloak) ├── router/ # Vue Router configuration ├── stores/ # Pinia stores for state management ├── style/ # Global styles and Quasar variables ├── utils/ # Utility functions └── views/ # Page-level Vue components ``` ### Key Architecture Patterns **Authentication Flow:** - Uses Keycloak for SSO authentication - Tokens stored in cookies with `BMAHRISCKI_KEYCLOAK_IDENTITY` key - Auth state managed in `src/plugins/auth.ts` - Router guards enforce authentication on protected routes - 401 responses trigger automatic logout via axios interceptor **State Management:** - `stores/mixin.ts` - Global utilities (Thai date formatting, dialogs, loaders, error handling) - `stores/chekin.ts` - Check-in history and status management - `stores/privacy.ts` - Privacy consent management - `stores/positionKeycloak.ts` - User position/role data **API Layer:** - Base axios instance in `src/plugins/http.ts` with automatic token injection - API endpoints organized by feature in `src/api/` - Environment-specific API URLs configured in `src/api/index.ts` - Production API URL set via `VITE_API_URI_CONFIG` env variable **Routing:** - Main layout (`MainView`) wraps authenticated routes - Protected routes require `meta.Auth: true` - Auth check runs in router beforeEach guard - Public routes: `/login`, `/auth`, `/reset-password`, `/history` **Geolocation & Maps:** - ArcGIS JS API for advanced mapping features - Google Maps integration for location services - Camera integration for check-in photo verification - Privacy consent required before accessing camera/location **Date/Time Handling:** - Thai Buddhist calendar (BE) conversion (+543 years) - Thai month names (full and abbreviated) - `date-fns-tz` for timezone handling (Asia/Bangkok) - Fiscal year calculation (October start) ### Component Conventions - Components use Quasar UI components (`q-btn`, `q-dialog`, etc.) - Thai language throughout the UI - Custom dialogs use `CustomDialog.vue` component - Loading states use Quasar's `QSpinnerCube` - Error dialogs prevent overlap with `activeErrorDialog` tracking ### Localization - Quasar configured with Thai language (`quasar/lang/th`) - All UI text in Thai - Date formatting uses `date2Thai()` and `monthYear2Thai()` from mixin store - Status labels translated: ABSENT→'ขาดราชการ', NORMAL→'ปกติ', LATE→'สาย' ### Environment Variables Required in `.env.production`: - `VITE_API_URI_CONFIG` - Production API base URL - `VITE_URL_SSO` - Keycloak SSO logout URL - `VITE_URL_USER` - User service URL for redirects - `VITE_URL_LANDING` - Landing page URL **Note:** `.env.local` uses `:` instead of `=` for variable assignment (non-standard format that works with the current setup) - `VITE_API_URI_CONFIG` - Production API base URL - `VITE_URL_SSO` - Keycloak SSO logout URL - `VITE_URL_USER` - User service URL for redirects ### PWA Configuration - Auto-update registration with `vite-plugin-pwa` - Manifest: "HRMS-Checkin" / "HRMS Checkin" - Icons: 192x192 and 512x512 PNG - Service worker registered in `src/registerServiceWorker.ts` ### Import Aliases - `@` is configured as an alias for the `src/` directory - Use this for all imports from within the source directory ### Environment Variable Substitution (Docker) The Docker build uses a multi-stage pattern: 1. **Build stage**: Node.js Alpine builds the static assets with `npm run build` 2. **Production stage**: nginx serves the static files - Environment variables (`VITE_API_URI_CONFIG`, `VITE_URL_SSO`, `VITE_URL_LANDING`, `VITE_URL_USER`) are substituted at container runtime via `entrypoint.sh` using `sed` - Built JS files contain placeholder values that get replaced with actual values at startup ### Testing Patterns - Unit tests: `*.spec.{js,ts}` - Run with Vitest in jsdom environment - E2E tests: `*.cy.{js,ts}` - Run with Cypress - E2E test server runs on port 4173 (via `start-server-and-test`) ### HTTP Interceptor Behavior - The axios interceptor in `http.ts` detects 401/403 responses but automatic logout is currently disabled (commented out) - 401 handling is done manually in `messageError()` from the mixin store ## Development Notes **When adding new features:** 1. Create API functions in `src/api/` 2. Define TypeScript interfaces in `src/interface/response/` 3. Use Pinia stores for complex state, composables for reusable logic 4. Follow Thai localization patterns for user-facing text 5. Ensure privacy consent flow for camera/location features **When working with dates:** - Always use `date2Thai()` or `convertDateToAPI()` from mixin store - Dates stored in BE format (year + 543) - API expects `yyyy-MM-dd` or `yyyy-MM-dd HH:mm:ss` format **When handling errors:** - Use `messageError()` from mixin store for consistent error dialogs - 401 errors trigger automatic logout - Dialog overlap prevention built into error handling **When running tests:** - Unit tests use Vitest with jsdom environment - E2E tests use Cypress with baseUrl: `http://localhost:4173` - Test files follow pattern: `*.cy.{js,ts}` or `*.spec.{js,ts}`