# 📝 **Documents Management System Version 1.4.1: āđāļ™āļ§āļ—āļēāļ‡āļāļēāļĢāļžāļąāļ’āļ™āļē FullStackJS (āļ›āļĢāļąāļšāļ›āļĢāļļāļ‡āđ‚āļ”āļĒ deepseek)** **āļ›āļĢāļąāļšāļ›āļĢāļļāļ‡āļ•āļēāļĄ Requirements v1.4.0 āļ—āļĩāđˆāļ­āļąāļ›āđ€āļ”āļ•āđāļĨāđ‰āļ§* ## 🧠**1. āļ›āļĢāļąāļŠāļāļēāļ—āļąāđˆāļ§āđ„āļ›** āđāļ™āļ§āļ—āļēāļ‡āļ›āļāļīāļšāļąāļ•āļīāļ—āļĩāđˆāļ”āļĩāļ—āļĩāđˆāļŠāļļāļ”āđāļšāļšāļ„āļĢāļšāļ§āļ‡āļˆāļĢāļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļžāļąāļ’āļ™āļē NestJS Backend, NextJS Frontend āđāļĨāļ° Tailwind-based UI/UX āđƒāļ™āļŠāļ āļēāļžāđāļ§āļ”āļĨāđ‰āļ­āļĄ TypeScript āļĄāļļāđˆāļ‡āđ€āļ™āđ‰āļ™āļ—āļĩāđˆ āļ„āļ§āļēāļĄāļŠāļąāļ”āđ€āļˆāļ™ (clarity), āļ„āļ§āļēāļĄāļ‡āđˆāļēāļĒāđƒāļ™āļāļēāļĢāļšāļģāļĢāļļāļ‡āļĢāļąāļāļĐāļē (maintainability), āļ„āļ§āļēāļĄāļŠāļ­āļ”āļ„āļĨāđ‰āļ­āļ‡āļāļąāļ™ (consistency) āđāļĨāļ° āļāļēāļĢāđ€āļ‚āđ‰āļēāļ–āļķāļ‡āđ„āļ”āđ‰ (accessibility) āļ•āļĨāļ­āļ”āļ—āļąāđ‰āļ‡āļŠāđāļ•āđ‡āļ ## ⚙ïļ**2. āđāļ™āļ§āļ—āļēāļ‡āļ—āļąāđˆāļ§āđ„āļ›āļŠāļģāļŦāļĢāļąāļš TypeScript** ### **2.1 āļŦāļĨāļąāļāļāļēāļĢāļžāļ·āđ‰āļ™āļāļēāļ™** * āđƒāļŠāđ‰ **āļ āļēāļĐāļēāļ­āļąāļ‡āļāļĪāļĐ** āļŠāļģāļŦāļĢāļąāļšāđ‚āļ„āđ‰āļ” * āđƒāļŠāđ‰ **āļ āļēāļĐāļēāđ„āļ—āļĒ** āļŠāļģāļŦāļĢāļąāļš comment āđāļĨāļ°āđ€āļ­āļāļŠāļēāļĢāļ—āļąāđ‰āļ‡āļŦāļĄāļ” * āļāļģāļŦāļ™āļ”āđ„āļ—āļ›āđŒ (type) āļ­āļĒāđˆāļēāļ‡āļŠāļąāļ”āđ€āļˆāļ™āļŠāļģāļŦāļĢāļąāļšāļ•āļąāļ§āđāļ›āļĢ, āļžāļēāļĢāļēāļĄāļīāđ€āļ•āļ­āļĢāđŒ āđāļĨāļ°āļ„āđˆāļēāļ—āļĩāđˆāļŠāđˆāļ‡āļāļĨāļąāļš (return values) āļ—āļąāđ‰āļ‡āļŦāļĄāļ” * āļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļāļēāļĢāđƒāļŠāđ‰ any; āđƒāļŦāđ‰āļŠāļĢāđ‰āļēāļ‡āđ„āļ—āļ›āđŒ (types) āļŦāļĢāļ·āļ­āļ­āļīāļ™āđ€āļ—āļ­āļĢāđŒāđ€āļŸāļ‹ (interfaces) āļ—āļĩāđˆāļāļģāļŦāļ™āļ”āđ€āļ­āļ‡ * āđƒāļŠāđ‰ **JSDoc** āļŠāļģāļŦāļĢāļąāļšāļ„āļĨāļēāļŠ (classes) āđāļĨāļ°āđ€āļĄāļ˜āļ­āļ” (methods) āļ—āļĩāđˆāđ€āļ›āđ‡āļ™ public * āļŠāđˆāļ‡āļ­āļ­āļ (Export) **āļŠāļąāļāļĨāļąāļāļĐāļ“āđŒāļŦāļĨāļąāļ (main symbol) āđ€āļžāļĩāļĒāļ‡āļŦāļ™āļķāđˆāļ‡āđ€āļ”āļĩāļĒāļ§** āļ•āđˆāļ­āđ„āļŸāļĨāđŒ * āļŦāļĨāļĩāļāđ€āļĨāļĩāđˆāļĒāļ‡āļšāļĢāļĢāļ—āļąāļ”āļ§āđˆāļēāļ‡āļ āļēāļĒāđƒāļ™āļŸāļąāļ‡āļāđŒāļŠāļąāļ™ * āļĢāļ°āļšāļļ // File: path/filename āđƒāļ™āļšāļĢāļĢāļ—āļąāļ”āđāļĢāļāļ‚āļ­āļ‡āļ—āļļāļāđ„āļŸāļĨāđŒ * āļĢāļ°āļšāļļ // āļšāļąāļ™āļ—āļķāļāļāļēāļĢāđāļāđ‰āđ„āļ‚, āļŦāļēāļāļĄāļĩāļāļēāļĢāđāļāđ‰āđ„āļ‚āđ€āļžāļīāđˆāļĄāđƒāļ™āļ­āļ™āļēāļ„āļ• āđƒāļŦāđ‰āđ€āļžāļīāđˆāļĄāļšāļąāļ™āļ—āļķāļ ### **2.2 āļ‚āđ‰āļ­āļ•āļāļĨāļ‡āđƒāļ™āļāļēāļĢāļ•āļąāđ‰āļ‡āļŠāļ·āđˆāļ­ (Naming Conventions)** | Entity (āļŠāļīāđˆāļ‡āļ—āļĩāđˆāļ•āļąāđ‰āļ‡āļŠāļ·āđˆāļ­) | Convention (āļĢāļđāļ›āđāļšāļš) | Example (āļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡) | | :---- | :---- | :---- | | Classes | PascalCase | UserService | | Property | snake_case | user_id | | Variables & Functions | camelCase | getUserInfo | | Files & Folders | kebab-case | user-service.ts | | Environment Variables | UPPERCASE | DATABASE_URL | | Booleans | Verb + Noun | isActive, canDelete, hasPermission | āđƒāļŠāđ‰āļ„āļģāđ€āļ•āđ‡āļĄ â€” āđ„āļĄāđˆāđƒāļŠāđ‰āļ­āļąāļāļĐāļĢāļĒāđˆāļ­ â€” āļĒāļāđ€āļ§āđ‰āļ™āļ„āļģāļĄāļēāļ•āļĢāļāļēāļ™ (āđ€āļŠāđˆāļ™ API, URL, req, res, err, ctx) ### ðŸ§Đ**2.3 āļŸāļąāļ‡āļāđŒāļŠāļąāļ™ (Functions)** * āđ€āļ‚āļĩāļĒāļ™āļŸāļąāļ‡āļāđŒāļŠāļąāļ™āđƒāļŦāđ‰āļŠāļąāđ‰āļ™ āđāļĨāļ°āļ—āļģ **āļŦāļ™āđ‰āļēāļ—āļĩāđˆāđ€āļžāļĩāļĒāļ‡āļ­āļĒāđˆāļēāļ‡āđ€āļ”āļĩāļĒāļ§** (single-purpose) (\< 20 āļšāļĢāļĢāļ—āļąāļ”) * āđƒāļŠāđ‰ **early returns** āđ€āļžāļ·āđˆāļ­āļĨāļ”āļāļēāļĢāļ‹āđ‰āļ­āļ™ (nesting) āļ‚āļ­āļ‡āđ‚āļ„āđ‰āļ” * āđƒāļŠāđ‰ **map**, **filter**, **reduce** āđāļ—āļ™āļāļēāļĢāđƒāļŠāđ‰ loops āđ€āļĄāļ·āđˆāļ­āđ€āļŦāļĄāļēāļ°āļŠāļĄ * āļ„āļ§āļĢāđƒāļŠāđ‰ **arrow functions** āļŠāļģāļŦāļĢāļąāļšāļ•āļĢāļĢāļāļ°āļŠāļąāđ‰āļ™āđ†, āđāļĨāļ°āđƒāļŠāđ‰ **named functions** āđƒāļ™āļāļĢāļ“āļĩāļ­āļ·āđˆāļ™ * āđƒāļŠāđ‰ **default parameters** āđāļ—āļ™āļāļēāļĢāļ•āļĢāļ§āļˆāļŠāļ­āļšāļ„āđˆāļē null * āļˆāļąāļ”āļāļĨāļļāđˆāļĄāļžāļēāļĢāļēāļĄāļīāđ€āļ•āļ­āļĢāđŒāļŦāļĨāļēāļĒāļ•āļąāļ§āđƒāļŦāđ‰āđ€āļ›āđ‡āļ™āļ­āđ‡āļ­āļšāđ€āļˆāļāļ•āđŒāđ€āļ”āļĩāļĒāļ§ (RO-RO pattern) * āļŠāđˆāļ‡āļ„āđˆāļēāļāļĨāļąāļš (Return) āđ€āļ›āđ‡āļ™āļ­āđ‡āļ­āļšāđ€āļˆāļāļ•āđŒāļ—āļĩāđˆāļĄāļĩāđ„āļ—āļ›āđŒāļāļģāļŦāļ™āļ” (typed objects) āđ„āļĄāđˆāđƒāļŠāđˆāļ„āđˆāļēāļžāļ·āđ‰āļ™āļāļēāļ™ (primitives) * āļĢāļąāļāļĐāļēāļĢāļ°āļ”āļąāļšāļ‚āļ­āļ‡āļŠāļīāđˆāļ‡āļ—āļĩāđˆāđ€āļ›āđ‡āļ™āļ™āļēāļĄāļ˜āļĢāļĢāļĄ (abstraction level) āđƒāļŦāđ‰āđ€āļ›āđ‡āļ™āļĢāļ°āļ”āļąāļšāđ€āļ”āļĩāļĒāļ§āđƒāļ™āđāļ•āđˆāļĨāļ°āļŸāļąāļ‡āļāđŒāļŠāļąāļ™ ### ðŸ§ą**2.4 āļāļēāļĢāļˆāļąāļ”āļāļēāļĢāļ‚āđ‰āļ­āļĄāļđāļĨ (Data Handling)** * āļŦāđˆāļ­āļŦāļļāđ‰āļĄāļ‚āđ‰āļ­āļĄāļđāļĨ (Encapsulate) āđƒāļ™āđ„āļ—āļ›āđŒāđāļšāļšāļœāļŠāļĄ (composite types) * āđƒāļŠāđ‰ **immutability** (āļāļēāļĢāđ„āļĄāđˆāđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡āļ„āđˆāļē) āļ”āđ‰āļ§āļĒ readonly āđāļĨāļ° as const * āļ—āļģāļāļēāļĢāļ•āļĢāļ§āļˆāļŠāļ­āļšāļ„āļ§āļēāļĄāļ–āļđāļāļ•āđ‰āļ­āļ‡āļ‚āļ­āļ‡āļ‚āđ‰āļ­āļĄāļđāļĨ (Validations) āđƒāļ™āļ„āļĨāļēāļŠāļŦāļĢāļ·āļ­ DTOs āđ„āļĄāđˆāđƒāļŠāđˆāļ āļēāļĒāđƒāļ™āļŸāļąāļ‡āļāđŒāļŠāļąāļ™āļ—āļēāļ‡āļ˜āļļāļĢāļāļīāļˆ * āļ•āļĢāļ§āļˆāļŠāļ­āļšāļ„āļ§āļēāļĄāļ–āļđāļāļ•āđ‰āļ­āļ‡āļ‚āļ­āļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāđ‚āļ”āļĒāđƒāļŠāđ‰ DTOs āļ—āļĩāđˆāļĄāļĩāđ„āļ—āļ›āđŒāļāļģāļŦāļ™āļ”āđ€āļŠāļĄāļ­ ### 🧰**2.5 āļ„āļĨāļēāļŠ (Classes)** * āļ›āļāļīāļšāļąāļ•āļīāļ•āļēāļĄāļŦāļĨāļąāļāļāļēāļĢ **SOLID** * āļ„āļ§āļĢāđƒāļŠāđ‰ **composition āļĄāļēāļāļāļ§āđˆāļē inheritance** (Prefer composition over inheritance) * āļāļģāļŦāļ™āļ” **interfaces** āļŠāļģāļŦāļĢāļąāļšāļŠāļąāļāļāļē (contracts) * āđƒāļŦāđ‰āļ„āļĨāļēāļŠāļĄāļļāđˆāļ‡āđ€āļ™āđ‰āļ™āļāļēāļĢāļ—āļģāļ‡āļēāļ™āđ€āļ‰āļžāļēāļ°āļ­āļĒāđˆāļēāļ‡āđāļĨāļ°āļĄāļĩāļ‚āļ™āļēāļ”āđ€āļĨāđ‡āļ (\< 200 āļšāļĢāļĢāļ—āļąāļ”, \< 10 āđ€āļĄāļ˜āļ­āļ”, \< 10 properties) ### ðŸšĻ**2.6 āļāļēāļĢāļˆāļąāļ”āļāļēāļĢāļ‚āđ‰āļ­āļœāļīāļ”āļžāļĨāļēāļ” (Error Handling)** * āđƒāļŠāđ‰ Exceptions āļŠāļģāļŦāļĢāļąāļšāļ‚āđ‰āļ­āļœāļīāļ”āļžāļĨāļēāļ”āļ—āļĩāđˆāđ„āļĄāđˆāļ„āļēāļ”āļ„āļīāļ” * āļ”āļąāļāļˆāļąāļš (Catch) āļ‚āđ‰āļ­āļœāļīāļ”āļžāļĨāļēāļ”āđ€āļžāļ·āđˆāļ­āđāļāđ‰āđ„āļ‚āļŦāļĢāļ·āļ­āđ€āļžāļīāđˆāļĄāļšāļĢāļīāļšāļ— (context) āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™; āļŦāļēāļāđ„āļĄāđˆāđ€āļŠāđˆāļ™āļ™āļąāđ‰āļ™ āđƒāļŦāđ‰āđƒāļŠāđ‰ global error handlers * āļĢāļ°āļšāļļāļ‚āđ‰āļ­āļ„āļ§āļēāļĄāļ‚āđ‰āļ­āļœāļīāļ”āļžāļĨāļēāļ” (error messages) āļ—āļĩāđˆāļĄāļĩāļ„āļ§āļēāļĄāļŦāļĄāļēāļĒāđ€āļŠāļĄāļ­ ### 🧊**2.7 āļāļēāļĢāļ—āļ”āļŠāļ­āļš (āļ—āļąāđˆāļ§āđ„āļ›) (Testing (General))** * āđƒāļŠāđ‰āļĢāļđāļ›āđāļšāļš **Arrange–Act–Assert** * āđƒāļŠāđ‰āļŠāļ·āđˆāļ­āļ•āļąāļ§āđāļ›āļĢāđƒāļ™āļāļēāļĢāļ—āļ”āļŠāļ­āļšāļ—āļĩāđˆāļŠāļ·āđˆāļ­āļ„āļ§āļēāļĄāļŦāļĄāļēāļĒ (inputData, expectedOutput) * āđ€āļ‚āļĩāļĒāļ™ **unit tests** āļŠāļģāļŦāļĢāļąāļš public methods āļ—āļąāđ‰āļ‡āļŦāļĄāļ” * āļˆāļģāļĨāļ­āļ‡ (Mock) āļāļēāļĢāļžāļķāđˆāļ‡āļžāļēāļ āļēāļĒāļ™āļ­āļ (external dependencies) * āđ€āļžāļīāđˆāļĄ **acceptance tests** āļ•āđˆāļ­āđ‚āļĄāļ”āļđāļĨāđ‚āļ”āļĒāđƒāļŠāđ‰āļĢāļđāļ›āđāļšāļš Given–When-Then ### **Testing Strategy āđ‚āļ”āļĒāļĨāļ°āđ€āļ­āļĩāļĒāļ”** * **Test Pyramid Structure** /\ / \ E2E Tests (10%) /____\ Integration Tests (20%) / \ Unit Tests (70%) /________\ * **Testing Tools Stack** ```typescript // Backend Testing Stack const backendTesting = { unit: ['Jest', 'ts-jest', '@nestjs/testing'], integration: ['Supertest', 'Testcontainers', 'Jest'], e2e: ['Supertest', 'Jest', 'Database Seeds'], security: ['Jest', 'Custom Security Test Helpers'], performance: ['Jest', 'autocannon', 'artillery'] }; // Frontend Testing Stack const frontendTesting = { unit: ['Vitest', 'React Testing Library'], integration: ['React Testing Library', 'MSW'], e2e: ['Playwright', 'Jest'], visual: ['Playwright', 'Loki'] }; ``` * **Test Data Managemen** ```typescript // Test Data Factories interface TestDataFactory { createUser(overrides?: Partial): User; createCorrespondence(overrides?: Partial): Correspondence; createRoutingTemplate(overrides?: Partial): RoutingTemplate; } // Test Scenarios const testScenarios = { happyPath: 'Normal workflow execution', edgeCases: 'Boundary conditions and limits', errorConditions: 'Error handling and recovery', security: 'Authentication and authorization', performance: 'Load and stress conditions' }; ``` ## 🏗ïļ**3. āđāļšāđ‡āļāđ€āļ­āļ™āļ”āđŒ (NestJS) (Backend (NestJS))** ### **3.1 āļŦāļĨāļąāļāļāļēāļĢ** * **āļŠāļ–āļēāļ›āļąāļ•āļĒāļāļĢāļĢāļĄāđāļšāļšāđ‚āļĄāļ”āļđāļĨāļēāļĢāđŒ (Modular architecture)**: * āļŦāļ™āļķāđˆāļ‡āđ‚āļĄāļ”āļđāļĨāļ•āđˆāļ­āļŦāļ™āļķāđˆāļ‡āđ‚āļ”āđ€āļĄāļ™ * āđ‚āļ„āļĢāļ‡āļŠāļĢāđ‰āļēāļ‡āđāļšāļš Controller → Service → Repository (Model) * API-First: āļĄāļļāđˆāļ‡āđ€āļ™āđ‰āļ™āļāļēāļĢāļŠāļĢāđ‰āļēāļ‡ API āļ—āļĩāđˆāļĄāļĩāļ„āļļāļ“āļ āļēāļžāļŠāļđāļ‡ āļĄāļĩāđ€āļ­āļāļŠāļēāļĢāļ›āļĢāļ°āļāļ­āļš (Swagger) āļ—āļĩāđˆāļŠāļąāļ”āđ€āļˆāļ™āļŠāļģāļŦāļĢāļąāļš Frontend Team * DTOs āļ—āļĩāđˆāļ•āļĢāļ§āļˆāļŠāļ­āļšāļ„āļ§āļēāļĄāļ–āļđāļāļ•āđ‰āļ­āļ‡āļ”āđ‰āļ§āļĒ **class-validator** * āđƒāļŠāđ‰ **MikroORM** (āļŦāļĢāļ·āļ­ TypeORM/Prisma) āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļ„āļ‡āļ­āļĒāļđāđˆāļ‚āļ­āļ‡āļ‚āđ‰āļ­āļĄāļđāļĨ (persistence) āļ‹āļķāđˆāļ‡āļŠāļ­āļ”āļ„āļĨāđ‰āļ­āļ‡āļāļąāļšāļŠāļ„āļĩāļĄāļē MariaDB * āļŦāđˆāļ­āļŦāļļāđ‰āļĄāđ‚āļ„āđ‰āļ”āļ—āļĩāđˆāđƒāļŠāđ‰āļ‹āđ‰āļģāđ„āļ”āđ‰āđ„āļ§āđ‰āđƒāļ™ **common module** (@app/common): * Configs, decorators, DTOs, guards, interceptors, notifications, shared services, types, validators ### **3.2 āļŸāļąāļ‡āļāđŒāļŠāļąāļ™āļŦāļĨāļąāļ (Core Functionalities)** * Global **filters** āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļˆāļąāļ”āļāļēāļĢ exception * **Middlewares** āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļˆāļąāļ”āļāļēāļĢ request * **Guards** āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļ­āļ™āļļāļāļēāļ• (permissions) āđāļĨāļ° RBAC * **Interceptors** āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāđāļ›āļĨāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨ response āđāļĨāļ°āļāļēāļĢāļšāļąāļ™āļ—āļķāļ log ### **3.3 āļ‚āđ‰āļ­āļˆāļģāļāļąāļ”āđƒāļ™āļāļēāļĢ Deploy (QNAP Container Station)** * **āļŦāđ‰āļēāļĄāđƒāļŠāđ‰āđ„āļŸāļĨāđŒ .env** āđƒāļ™āļāļēāļĢāļ•āļąāđ‰āļ‡āļ„āđˆāļē Environment Variables [cite: 2.1] * āļāļēāļĢāļ•āļąāđ‰āļ‡āļ„āđˆāļēāļ—āļąāđ‰āļ‡āļŦāļĄāļ” (āđ€āļŠāđˆāļ™ Database connection string, JWT secret) **āļˆāļ°āļ•āđ‰āļ­āļ‡āļ–āļđāļāļāļģāļŦāļ™āļ”āļœāđˆāļēāļ™ Environment Variable āđƒāļ™ docker-compose.yml āđ‚āļ”āļĒāļ•āļĢāļ‡** [cite: 6.5] āļ‹āļķāđˆāļ‡āļˆāļ°āļˆāļąāļ”āļāļēāļĢāļœāđˆāļēāļ™ UI āļ‚āļ­āļ‡ QNAP Container Station [cite: 2.1] ### **3.4 āļ‚āđ‰āļ­āļˆāļģāļāļąāļ”āļ”āđ‰āļēāļ™āļ„āļ§āļēāļĄāļ›āļĨāļ­āļ”āļ āļąāļĒ (Security Constraints):** * **File Upload Security:** āļ•āđ‰āļ­āļ‡āļĄāļĩ virus scanning (ClamAV), file type validation (white-list), āđāļĨāļ° file size limits (50MB) * **Input Validation:** āļ•āđ‰āļ­āļ‡āļ›āđ‰āļ­āļ‡āļāļąāļ™ OWASP Top 10 vulnerabilities (SQL Injection, XSS, CSRF) * **Rate Limiting:** āļ•āđ‰āļ­āļ‡ implement rate limiting āļ•āļēāļĄ strategy āļ—āļĩāđˆāļāļģāļŦāļ™āļ” * **Secrets Management:** āļ•āđ‰āļ­āļ‡āļĄāļĩ mechanism āļŠāļģāļŦāļĢāļąāļšāļˆāļąāļ”āļāļēāļĢ sensitive secrets āļ­āļĒāđˆāļēāļ‡āļ›āļĨāļ­āļ”āļ āļąāļĒ āđāļĄāđ‰āļˆāļ°āđƒāļŠāđ‰ docker-compose.yml ### **3.5 āđ‚āļ„āļĢāļ‡āļŠāļĢāđ‰āļēāļ‡āđ‚āļĄāļ”āļđāļĨāļ•āļēāļĄāđ‚āļ”āđ€āļĄāļ™ (Domain-Driven Module Structure)** āđ€āļžāļ·āđˆāļ­āđƒāļŦāđ‰āļŠāļ­āļ”āļ„āļĨāđ‰āļ­āļ‡āļāļąāļšāļŠāļ„āļĩāļĄāļē SQL (LCBP3-DMS) āđ€āļĢāļēāļˆāļ°āđƒāļŠāđ‰āđ‚āļ„āļĢāļ‡āļŠāļĢāđ‰āļēāļ‡āđ‚āļĄāļ”āļđāļĨāđāļšāļš **Domain-Driven (āđāļšāđˆāļ‡āļ•āļēāļĄāļ‚āļ­āļšāđ€āļ‚āļ•āļ˜āļļāļĢāļāļīāļˆ)** āđāļ—āļ™āļāļēāļĢāđāļšāđˆāļ‡āļ•āļēāļĄāļŸāļąāļ‡āļāđŒāļŠāļąāļ™: #### 3.5.1 **CommonModule:** * āđ€āļāđ‡āļš Services āļ—āļĩāđˆāđƒāļŠāđ‰āļĢāđˆāļ§āļĄāļāļąāļ™ āđ€āļŠāđˆāļ™ DatabaseModule, FileStorageService (āļˆāļąāļ”āļāļēāļĢāđ„āļŸāļĨāđŒāđƒāļ™ QNAP), AuditLogService, NotificationService * āļˆāļąāļ”āļāļēāļĢ audit_logs * NotificationService āļ•āđ‰āļ­āļ‡āļĢāļ­āļ‡āļĢāļąāļš Triggers āļ—āļĩāđˆāļĢāļ°āļšāļļāđƒāļ™ Requirement 6.7 [cite: 6.7] #### 3.5.2 **AuthModule:** * āļˆāļąāļ”āļāļēāļĢāļ°āļāļēāļĢāļĒāļ·āļ™āļĒāļąāļ™āļ•āļąāļ§āļ•āļ™ (JWT, Guards) * **(āļŠāļģāļ„āļąāļ)** āļ•āđ‰āļ­āļ‡āļĢāļąāļšāļœāļīāļ”āļŠāļ­āļšāļāļēāļĢāļ•āļĢāļ§āļˆāļŠāļ­āļšāļŠāļīāļ—āļ˜āļīāđŒ **4 āļĢāļ°āļ”āļąāļš** [cite: 4.2]: āļŠāļīāļ—āļ˜āļīāđŒāļĢāļ°āļ”āļąāļšāļĢāļ°āļšāļš (Global Role), āļŠāļīāļ—āļ˜āļīāđŒāļĢāļ°āļ”āļąāļšāļ­āļ‡āļāļĢāļ“āđŒ (Organization Role), āļŠāļīāļ—āļ˜āļīāđŒāļĢāļ°āļ”āļąāļšāđ‚āļ›āļĢāđ€āļˆāļāļ•āđŒ (Project Role), āđāļĨāļ° āļŠāļīāļ—āļ˜āļīāđŒāļĢāļ°āļ”āļąāļšāļŠāļąāļāļāļē (Contract Role) * **(āļŠāļģāļ„āļąāļ)** āļ•āđ‰āļ­āļ‡āļĄāļĩ API āļŠāļģāļŦāļĢāļąāļš **Admin Panel** āđ€āļžāļ·āđˆāļ­: * āļŠāļĢāđ‰āļēāļ‡āđāļĨāļ°āļˆāļąāļ”āļāļēāļĢ Role āđāļĨāļ°āļāļēāļĢāļˆāļąāļšāļ„āļđāđˆ Permission āđāļšāļšāđ„āļ”āļ™āļēāļĄāļīāļ [cite: 4.3] * āđƒāļŦāđ‰ Superadmin āļŠāļĢāđ‰āļēāļ‡ Organizations āđāļĨāļ°āļāļģāļŦāļ™āļ” Org Admin āđ„āļ”āđ‰ [cite: 4.6] * āđƒāļŦāđ‰ Superadmin/Admin āļˆāļąāļ”āļāļēāļĢ document_number_formats (āļĢāļđāļ›āđāļšāļšāđ€āļĨāļ‚āļ—āļĩāđˆāđ€āļ­āļāļŠāļēāļĢ), document_number_counters (Running Number) [cite: 3.10] #### 3.5.3 **UserModule:** * āļˆāļąāļ”āļāļēāļĢ users, roles, permissions, global_default_roles, role_permissions, user_roles, user_project_roles * **(āļŠāļģāļ„āļąāļ)** āļ•āđ‰āļ­āļ‡āļĄāļĩ API āļŠāļģāļŦāļĢāļąāļš **Admin Panel** āđ€āļžāļ·āđˆāļ­: * āļŠāļĢāđ‰āļēāļ‡āđāļĨāļ°āļˆāļąāļ”āļāļēāļĢ Role āđāļĨāļ°āļāļēāļĢāļˆāļąāļšāļ„āļđāđˆ Permission āđāļšāļšāđ„āļ”āļ™āļēāļĄāļīāļ [cite: 4.3] #### 3.5.4 **ProjectModule:** * āļˆāļąāļ”āļāļēāļĢ projects, organizations, contracts, project_parties, contract_parties #### 3.5.6 **MasterModule:** * āļˆāļąāļ”āļāļēāļĢ master data (correspondence_types, rfa_types, rfa_status_codes, rfa_approve_codes, circulation_status_codes, correspondence_types, correspondence_status, tags) [cite: 4.5] #### 3.5.7**CorrespondenceModule (āđ‚āļĄāļ”āļđāļĨāļĻāļđāļ™āļĒāđŒāļāļĨāļēāļ‡):** * āļˆāļąāļ”āļāļēāļĢ correspondences, correspondence_revisions, correspondence_tags * **(āļŠāļģāļ„āļąāļ)** Service āļ™āļĩāđ‰āļ•āđ‰āļ­āļ‡ Inject DocumentNumberingService āđ€āļžāļ·āđˆāļ­āļ‚āļ­āđ€āļĨāļ‚āļ—āļĩāđˆāđ€āļ­āļāļŠāļēāļĢāđƒāļŦāļĄāđˆāļāđˆāļ­āļ™āļāļēāļĢāļŠāļĢāđ‰āļēāļ‡ * **(āļŠāļģāļ„āļąāļ)** āļ•āļĢāļĢāļāļ°āļāļēāļĢāļŠāļĢāđ‰āļēāļ‡/āļ­āļąāļ›āđ€āļ”āļ• Revision āļˆāļ°āļ­āļĒāļđāđˆāđƒāļ™ Service āļ™āļĩāđ‰ * āļˆāļąāļ”āļāļēāļĢ correspondence_attachments (āļ•āļēāļĢāļēāļ‡āđ€āļŠāļ·āđˆāļ­āļĄāđ„āļŸāļĨāđŒāđāļ™āļš) * āļĢāļąāļšāļœāļīāļ”āļŠāļ­āļš Routing **Correspondence Routing** (correspondence_routings, correspondence_routing_template_steps, correspondence_routing_templates, correspondence_status_transitions) āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļŠāđˆāļ‡āļ•āđˆāļ­āđ€āļ­āļāļŠāļēāļĢāļ—āļąāđˆāļ§āđ„āļ›āļĢāļ°āļŦāļ§āđˆāļēāļ‡āļ­āļ‡āļ„āđŒāļāļĢ #### 3.5.8 **RfaModule:** * āļˆāļąāļ”āļāļēāļĢ rfas, rfa_revisions, rfa_items * āļĢāļąāļšāļœāļīāļ”āļŠāļ­āļšāđ€āļ§āļīāļĢāđŒāļāđ‚āļŸāļĨāļ§āđŒ **"RFA Workflows"** (rfa_workflows, rfa_workflow_templates, rfa_workflow_template_steps, rfa_status_transitions) āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļ­āļ™āļļāļĄāļąāļ•āļīāđ€āļ­āļāļŠāļēāļĢāļ—āļēāļ‡āđ€āļ—āļ„āļ™āļīāļ„ #### 3.5.9 **DrawingModule:** * āļˆāļąāļ”āļāļēāļĢ shop_drawings, shop_drawing_revisions, contract_drawings, contract_drawing_volumes, contract_drawing_cats, contract_drawing_sub_cats, shop_drawing_main_categories, shop_drawing_sub_categories, contract_drawing_subcat_cat_maps, shop_drawing_revision_contract_refs * āļˆāļąāļ”āļāļēāļĢ shop_drawing_revision_attachments āđāļĨāļ° contract_drawing_attachments(āļ•āļēāļĢāļēāļ‡āđ€āļŠāļ·āđˆāļ­āļĄāđ„āļŸāļĨāđŒāđāļ™āļš) #### 3.5.10 **CirculationModule:** * āļˆāļąāļ”āļāļēāļĢ circulations, circulation_templates, circulation_assignees * āļˆāļąāļ”āļāļēāļĢ circulation_attachments (āļ•āļēāļĢāļēāļ‡āđ€āļŠāļ·āđˆāļ­āļĄāđ„āļŸāļĨāđŒāđāļ™āļš) * āļĢāļąāļšāļœāļīāļ”āļŠāļ­āļšāđ€āļ§āļīāļĢāđŒāļāđ‚āļŸāļĨāļ§āđŒ **"Circulations"** (circulation_status_transitions, circulation_template_assignees, circulation_assignees, circulation_recipients, circulation_actions, circulation_action_documents)āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāđ€āļ§āļĩāļĒāļ™āđ€āļ­āļāļŠāļēāļĢ **āļ āļēāļĒāđƒāļ™āļ­āļ‡āļ„āđŒāļāļĢ** #### 3.5.11 **TransmittalModule:** * āļˆāļąāļ”āļāļēāļĢ transmittals āđāļĨāļ° transmittal_items #### 3.5.12 **SearchModule:** * āđƒāļŦāđ‰āļšāļĢāļīāļāļēāļĢāļ„āđ‰āļ™āļŦāļēāļ‚āļąāđ‰āļ™āļŠāļđāļ‡ (Advanced Search) [cite: 6.2] āđ‚āļ”āļĒāđƒāļŠāđ‰ **Elasticsearch** āđ€āļžāļ·āđˆāļ­āļĢāļ­āļ‡āļĢāļąāļšāļāļēāļĢāļ„āđ‰āļ™āļŦāļēāđāļšāļš Full-text āļˆāļēāļāļŠāļ·āđˆāļ­āđ€āļĢāļ·āđˆāļ­āļ‡, āļĢāļēāļĒāļĨāļ°āđ€āļ­āļĩāļĒāļ”, āđ€āļĨāļ‚āļ—āļĩāđˆāđ€āļ­āļāļŠāļēāļĢ, āļ›āļĢāļ°āđ€āļ āļ—, āļ§āļąāļ™āļ—āļĩāđˆ, āđāļĨāļ° Tags * āļĢāļ°āļšāļšāļˆāļ°āđƒāļŠāđ‰ Elasticsearch Engine āđƒāļ™āļāļēāļĢāļˆāļąāļ”āļ—āļģāļ”āļąāļŠāļ™āļĩāđ€āļžāļ·āđˆāļ­āļāļēāļĢāļ„āđ‰āļ™āļŦāļēāļ‚āđ‰āļ­āļĄāļđāļĨāđ€āļŠāļīāļ‡āļĨāļķāļāļˆāļēāļāđ€āļ™āļ·āđ‰āļ­āļŦāļēāļ‚āļ­āļ‡āđ€āļ­āļāļŠāļēāļĢ āđ‚āļ”āļĒāļ‚āđ‰āļ­āļĄāļđāļĨāļˆāļ°āļ–āļđāļāļŠāđˆāļ‡āđ„āļ›āļ—āļģāļ”āļąāļŠāļ™āļĩāļˆāļēāļ Backend (NestJS) āļ—āļļāļāļ„āļĢāļąāđ‰āļ‡āļ—āļĩāđˆāļĄāļĩāļāļēāļĢāļŠāļĢāđ‰āļēāļ‡āļŦāļĢāļ·āļ­āđāļāđ‰āđ„āļ‚āđ€āļ­āļāļŠāļēāļĢ #### 3.5.13 **DocumentNumberingModule:** * **āļŠāļ–āļēāļ™āļ°:** āđ€āļ›āđ‡āļ™ Module āļ āļēāļĒāđƒāļ™ (Internal Module) āđ„āļĄāđˆāđ€āļ›āļīāļ” API āļŠāļđāđˆāļ āļēāļĒāļ™āļ­āļ * **āļŦāļ™āđ‰āļēāļ—āļĩāđˆ:** āđƒāļŦāđ‰āļšāļĢāļīāļāļēāļĢ DocumentNumberingService āļ—āļĩāđˆ Module āļ­āļ·āđˆāļ™ (āđ€āļŠāđˆāļ™ CorrespondenceModule) āļˆāļ° Inject āđ„āļ›āđƒāļŠāđ‰āļ‡āļēāļ™ * **āļ•āļĢāļĢāļāļ°:** āļĢāļąāļšāļœāļīāļ”āļŠāļ­āļšāļāļēāļĢāļŠāļĢāđ‰āļēāļ‡āđ€āļĨāļ‚āļ—āļĩāđˆāđ€āļ­āļāļŠāļēāļĢāđ‚āļ”āļĒāđƒāļŠāđ‰ **Redis distributed locking** āđāļ—āļ™ stored procedure * **Features:** * Application-level locking āđ€āļžāļ·āđˆāļ­āļ›āđ‰āļ­āļ‡āļāļąāļ™ race condition * Retry mechanism āļ”āđ‰āļ§āļĒ exponential backoff * Fallback mechanism āđ€āļĄāļ·āđˆāļ­āļāļēāļĢāļ‚āļ­āđ€āļĨāļ‚āļĨāđ‰āļĄāđ€āļŦāļĨāļ§ * Audit log āļ—āļļāļāļ„āļĢāļąāđ‰āļ‡āļ—āļĩāđˆāļĄāļĩāļāļēāļĢ generate āđ€āļĨāļ‚āļ—āļĩāđˆāđ€āļ­āļāļŠāļēāļĢāđƒāļŦāļĄāđˆ #### 3.5.14 **CorrespondenceRoutingModule:** * **āļŠāļ–āļēāļ™āļ°:** āđ‚āļĄāļ”āļđāļĨāļŦāļĨāļąāļāļŠāļģāļŦāļĢāļąāļšāļˆāļąāļ”āļāļēāļĢāļāļēāļĢāļŠāđˆāļ‡āļ•āđˆāļ­āđ€āļ­āļāļŠāļēāļĢ * **āļŦāļ™āđ‰āļēāļ—āļĩāđˆ:** āļˆāļąāļ”āļāļēāļĢāđāļĄāđˆāđāļšāļšāļāļēāļĢāļŠāđˆāļ‡āļ•āđˆāļ­āđāļĨāļ°āļāļēāļĢāļŠāđˆāļ‡āļ•āđˆāļ­āļˆāļĢāļīāļ‡ * **Entities:** * CorrespondenceRoutingTemplate * CorrespondenceRoutingTemplateStep * CorrespondenceRouting * **Features:** * āļŠāļĢāđ‰āļēāļ‡āđāļĨāļ°āļˆāļąāļ”āļāļēāļĢāđāļĄāđˆāđāļšāļšāļāļēāļĢāļŠāđˆāļ‡āļ•āđˆāļ­ * āļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢāļŠāđˆāļ‡āļ•āđˆāļ­āđ€āļ­āļāļŠāļēāļĢāļ•āļēāļĄāđāļĄāđˆāđāļšāļš * āļ•āļīāļ”āļ•āļēāļĄāļŠāļ–āļēāļ™āļ°āļāļēāļĢāļŠāđˆāļ‡āļ•āđˆāļ­ * āļ„āļģāļ™āļ§āļ“āļ§āļąāļ™āļ„āļĢāļšāļāļģāļŦāļ™āļ”āļ­āļąāļ•āđ‚āļ™āļĄāļąāļ•āļī * āļŠāđˆāļ‡āļāļēāļĢāđāļˆāđ‰āļ‡āđ€āļ•āļ·āļ­āļ™āđ€āļĄāļ·āđˆāļ­āļĄāļĩāļāļēāļĢāļŠāđˆāļ‡āļ•āđˆāļ­āđƒāļŦāļĄāđˆ #### 3.5.15 **WorkflowEngineModule:** * **āļŠāļ–āļēāļ™āļ°:** Internal Module āļŠāļģāļŦāļĢāļąāļšāļˆāļąāļ”āļāļēāļĢ workflow logic * **āļŦāļ™āđ‰āļēāļ—āļĩāđˆ:** āļ›āļĢāļ°āļĄāļ§āļĨāļœāļĨ state transitions āđāļĨāļ° business rules * **Features:** * State machine āļŠāļģāļŦāļĢāļąāļšāļŠāļ–āļēāļ™āļ°āđ€āļ­āļāļŠāļēāļĢ * Validation rules āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāđ€āļ›āļĨāļĩāđˆāļĒāļ™āļŠāļ–āļēāļ™āļ° * Automatic status updates * Deadline management āđāļĨāļ° escalation ### 3.5.16 **JsonSchemaModule:** * **āļŠāļ–āļēāļ™āļ°:** Internal Module āļŠāļģāļŦāļĢāļąāļšāļˆāļąāļ”āļāļēāļĢ JSON schemas * **āļŦāļ™āđ‰āļēāļ—āļĩāđˆ:** Validate, transform, āđāļĨāļ° manage JSON data structures * **Features:** * JSON schema validation āļ”āđ‰āļ§āļĒ AJV * Schema versioning āđāļĨāļ° migration * Dynamic schema generation * Data transformation āđāļĨāļ° sanitization ### 3.5.17 **DetailsService:** * **āļŠāļ–āļēāļ™āļ°:** Shared Service āļŠāļģāļŦāļĢāļąāļšāļˆāļąāļ”āļāļēāļĢ details fields * **āļŦāļ™āđ‰āļēāļ—āļĩāđˆ:** Centralized service āļŠāļģāļŦāļĢāļąāļš JSON details operations * **Methods:** * validateDetails(type: string, data: any): ValidationResult * transformDetails(input: any, targetVersion: string): any * sanitizeDetails(data: any): any * getDefaultDetails(type: string): any ### **3.6 āļŠāļ–āļēāļ›āļąāļ•āļĒāļāļĢāļĢāļĄāļĢāļ°āļšāļš (System Architecture)** āđ‚āļ„āļĢāļ‡āļŠāļĢāđ‰āļēāļ‡āđ‚āļĄāļ”āļđāļĨ (Module Structure) ```bash 📁 src ├── 📄 app.module.ts ├── 📄 main.ts ├── 📁 common # @app/common (āđ‚āļĄāļ”āļđāļĨāļŠāđˆāļ§āļ™āļāļĨāļēāļ‡) │ ├── 📁 auth # AuthModule (JWT, Guards) │ ├── 📁 config # Configuration │ ├── 📁 decorators # Custom Decorators (āđ€āļŠāđˆāļ™ @RequirePermission) │ ├── 📁 entities # Shared Entities (User, Role, Permission) │ ├── 📁 exceptions # Global Exception Filters │ ├── 📁 file-storage # FileStorageService (Virus Scanning, Security) │ ├── 📁 guards # Custom Guards (RBAC Guard, RateLimitGuard) │ ├── 📁 interceptors # Interceptors (Audit Log, Transform, Performance) │ ├── 📁 resilience # Circuit Breaker, Retry Patterns │ └── 📁 services # Shared Services (NotificationService, CachingService) ├── 📁 modules │ ├── 📁 user # UserModule (āļˆāļąāļ”āļāļēāļĢ Users, Roles, Permissions) │ ├── 📁 project # ProjectModule (āļˆāļąāļ”āļāļēāļĢ Projects, Organizations, Contracts) │ ├── 📁 correspondence # CorrespondenceModule (āļˆāļąāļ”āļāļēāļĢāđ€āļ­āļāļŠāļēāļĢāđ‚āļ•āđ‰āļ•āļ­āļš) │ ├── 📁 rfa # RfaModule (āļˆāļąāļ”āļāļēāļĢāđ€āļ­āļāļŠāļēāļĢāļ‚āļ­āļ­āļ™āļļāļĄāļąāļ•āļī) │ ├── 📁 drawing # DrawingModule (āļˆāļąāļ”āļāļēāļĢāđāļšāļšāđāļ›āļĨāļ™) │ ├── 📁 circulation # CirculationModule (āļˆāļąāļ”āļāļēāļĢāđƒāļšāđ€āļ§āļĩāļĒāļ™) │ ├── 📁 transmittal # TransmittalModule (āļˆāļąāļ”āļāļēāļĢāđ€āļ­āļāļŠāļēāļĢāļ™āļģāļŠāđˆāļ‡) │ ├── 📁 search # SearchModule (āļ„āđ‰āļ™āļŦāļēāļ‚āļąāđ‰āļ™āļŠāļđāļ‡āļ”āđ‰āļ§āļĒ Elasticsearch) │ ├── 📁 monitoring # MonitoringModule (Metrics, Health Checks) │ └── 📁 document-numbering # DocumentNumberingModule (Internal Module) └── 📁 database # Database Migration & Seeding Scripts ``` ### **3.7 āļāļĨāļĒāļļāļ—āļ˜āđŒāļ„āļ§āļēāļĄāļ—āļ™āļ—āļēāļ™āđāļĨāļ°āļāļēāļĢāļˆāļąāļ”āļāļēāļĢāļ‚āđ‰āļ­āļœāļīāļ”āļžāļĨāļēāļ” (Resilience & Error Handling Strategy)** * **2.10.1 Circuit Breaker Pattern:** āđƒāļŠāđ‰āļŠāļģāļŦāļĢāļąāļš external service calls (Email, LINE, Elasticsearch) * **2.10.2 Retry Mechanism:** āļ”āđ‰āļ§āļĒ exponential backoff āļŠāļģāļŦāļĢāļąāļš transient failures * **2.10.3 Fallback Strategies:** Graceful degradation āđ€āļĄāļ·āđˆāļ­āļšāļĢāļīāļāļēāļĢāļ āļēāļĒāļ™āļ­āļāļĨāđ‰āļĄāđ€āļŦāļĨāļ§ * **2.10.4 Error Handling:** Error messages āļ•āđ‰āļ­āļ‡āđ„āļĄāđˆāđ€āļ›āļīāļ”āđ€āļœāļĒāļ‚āđ‰āļ­āļĄāļđāļĨ sensitive * **2.10.5 Monitoring:** Centralized error monitoring āđāļĨāļ° alerting system ### **3.8 FileStorageService (āļ›āļĢāļąāļšāļ›āļĢāļļāļ‡āđƒāļŦāļĄāđˆ):** * **Virus Scanning:** Integrate ClamAV āļŠāļģāļŦāļĢāļąāļš scan āđ„āļŸāļĨāđŒāļ—āļĩāđˆāļ­āļąāļ›āđ‚āļŦāļĨāļ”āļ—āļąāđ‰āļ‡āļŦāļĄāļ” * **File Type Validation:** āđƒāļŠāđ‰ white-list approach (PDF, DWG, DOCX, XLSX, ZIP) * **File Size Limits:** 50MB āļ•āđˆāļ­āđ„āļŸāļĨāđŒ * **Security Measures:** * āđ€āļāđ‡āļšāđ„āļŸāļĨāđŒāļ™āļ­āļ web root * Download āļœāđˆāļēāļ™ authenticated endpoint āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™ * Download links āļĄāļĩ expiration time (24 āļŠāļąāđˆāļ§āđ‚āļĄāļ‡) * File integrity checks (checksum) * Access control checks āļāđˆāļ­āļ™āļ”āļēāļ§āļ™āđŒāđ‚āļŦāļĨāļ” ### **3.9 āđ€āđ€āļ—āļ„āđ‚āļ™āđ‚āļĨāļĒāļĩāļ—āļĩāđˆāđƒāļŠāđ‰ (Technology Stack)** | āļŠāđˆāļ§āļ™ | Library/Tool | āļŦāļĄāļēāļĒāđ€āļŦāļ•āļļ | |---|---|---| | **Framework** | `@nestjs/core`, `@nestjs/common` | Core Framework | | **Language** | `TypeScript` | āđƒāļŠāđ‰ TypeScript āļ—āļąāđ‰āļ‡āļĢāļ°āļšāļš | | **Database** | `MariaDB 10.11` | āļāļēāļ™āļ‚āđ‰āļ­āļĄāļđāļĨāļŦāļĨāļąāļ | | **ORM** | `@nestjs/typeorm`, `typeorm` | 🗃ïļāļˆāļąāļ”āļāļēāļĢāļāļēāļĢāđ€āļŠāļ·āđˆāļ­āļĄāļ•āđˆāļ­āđāļĨāļ° Query āļāļēāļ™āļ‚āđ‰āļ­āļĄāļđāļĨ | | **Validation** | `class-validator`, `class-transformer` | ðŸ“Ķāļ•āļĢāļ§āļˆāļŠāļ­āļšāđāļĨāļ°āđāļ›āļĨāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāđƒāļ™ DTO | | **Auth** | `@nestjs/jwt`, `@nestjs/passport`, `passport-jwt` | 🔐āļāļēāļĢāļĒāļ·āļ™āļĒāļąāļ™āļ•āļąāļ§āļ•āļ™āļ”āđ‰āļ§āļĒ JWT | |**Authorization** | `casl` | 🔐āļˆāļąāļ”āļāļēāļĢāļŠāļīāļ—āļ˜āļīāđŒāđāļšāļš RBAC | | **File Upload** | `multer` | 📁āļˆāļąāļ”āļāļēāļĢāļāļēāļĢāļ­āļąāļ›āđ‚āļŦāļĨāļ”āđ„āļŸāļĨāđŒ | | **Search** | `@nestjs/elasticsearch` | 🔍āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļ„āđ‰āļ™āļŦāļēāļ‚āļąāđ‰āļ™āļŠāļđāļ‡ | | **Notification** | `nodemailer` | 📎āļŠāđˆāļ‡āļ­āļĩāđ€āļĄāļĨāđāļˆāđ‰āļ‡āđ€āļ•āļ·āļ­āļ™ | | **Scheduling** | `@nestjs/schedule` | 📎āļŠāļģāļŦāļĢāļąāļš Cron Jobs (āđ€āļŠāđˆāļ™ āđāļˆāđ‰āļ‡āđ€āļ•āļ·āļ­āļ™ Deadline) | | **Logging** | `winston` | 📊āļšāļąāļ™āļ—āļķāļ Log āļ—āļĩāđˆāļĄāļĩāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž | | **Testing** | `@nestjs/testing`, `jest`, `supertest` | 🧊āļ—āļ”āļŠāļ­āļš Unit, Integration āđāļĨāļ° E2E | | **Documentation** | `@nestjs/swagger` | 🌐āļŠāļĢāđ‰āļēāļ‡ API Documentation āļ­āļąāļ•āđ‚āļ™āļĄāļąāļ•āļī | | **Security** | `helmet`, `rate-limiter-flexible` | ðŸ›Ąïļāđ€āļžāļīāđˆāļĄāļ„āļ§āļēāļĄāļ›āļĨāļ­āļ”āļ āļąāļĒāđƒāļŦāđ‰ API | | **Resilience** | `@nestjs/circuit-breaker` | 🔄 Circuit breaker pattern | | **Caching** | `@nestjs/cache-manager`, `cache-manager-redis-store` | ðŸ’ū Distributed caching | | **Security** | `helmet`, `csurf`, `rate-limiter-flexible` | ðŸ›Ąïļ Security enhancements | | **Validation** | `class-validator`, `class-transformer` | ✅ Input validation | | **Monitoring** | `@nestjs/monitoring`, `winston` | 📊 Application monitoring | | **File Processing** | `clamscan` | ðŸĶ  Virus scanning | | **Cryptography** | `bcrypt`, `crypto` | 🔐 Password hashing āđāļĨāļ° checksums | | **JSON Validation** | `ajv`, `ajv-formats` | ðŸŽŊ JSON schema validation | | **JSON Processing** | `jsonpath`, `json-schema-ref-parser` | 🔧 JSON manipulation | | **Data Transformation** | `class-transformer` | 🔄 Object transformation | | **Compression** | `compression` | ðŸ“Ķ JSON compression | āđ€āļĢāļēāļˆāļ°āđāļšāđˆāļ‡āļāļēāļĢāļ—āļ”āļŠāļ­āļšāđ€āļ›āđ‡āļ™ 3 āļĢāļ°āļ”āļąāļš āđ‚āļ”āļĒāđƒāļŠāđ‰ **Jest** āđāļĨāļ° @nestjs/testing: * **Unit Tests (āļāļēāļĢāļ—āļ”āļŠāļ­āļšāļŦāļ™āđˆāļ§āļĒāļĒāđˆāļ­āļĒ):** * **āđ€āļ›āđ‰āļēāļŦāļĄāļēāļĒ:** āļ—āļ”āļŠāļ­āļš Logic āļ āļēāļĒāđƒāļ™ Service, Guard, āļŦāļĢāļ·āļ­ Pipe āđ‚āļ”āļĒāļˆāļģāļĨāļ­āļ‡ (Mock) Dependencies āļ—āļąāđ‰āļ‡āļŦāļĄāļ” * **āļŠāļīāđˆāļ‡āļ—āļĩāđˆāļ•āđ‰āļ­āļ‡āļ—āļ”āļŠāļ­āļš:** Business Logic (āđ€āļŠāđˆāļ™ āļāļēāļĢāđ€āļ›āļĨāļĩāđˆāļĒāļ™āļŠāļ–āļēāļ™āļ° Workflow, āļāļēāļĢāļ•āļĢāļ§āļˆāļŠāļ­āļš Deadline) [cite: 2.9.1], āļ•āļĢāļĢāļāļ°āļāļēāļĢāļ•āļĢāļ§āļˆāļŠāļ­āļšāļŠāļīāļ—āļ˜āļīāđŒ (Auth Guard) āļ—āļąāđ‰āļ‡ 4 āļĢāļ°āļ”āļąāļš * **Integration Tests (āļāļēāļĢāļ—āļ”āļŠāļ­āļšāļāļēāļĢāļšāļđāļĢāļ“āļēāļāļēāļĢ):** * **āđ€āļ›āđ‰āļēāļŦāļĄāļēāļĒ:** āļ—āļ”āļŠāļ­āļšāļāļēāļĢāļ—āļģāļ‡āļēāļ™āļĢāđˆāļ§āļĄāļāļąāļ™āļ‚āļ­āļ‡ Controller -> Service -> Repository (Database) * **āđ€āļ—āļ„āļ™āļīāļ„:** āđƒāļŠāđ‰ **Test Database āđāļĒāļāļ•āđˆāļēāļ‡āļŦāļēāļ** (āļŦāđ‰āļēāļĄāđƒāļŠāđ‰ Dev DB) āđāļĨāļ°āđƒāļŠāđ‰ supertest āđ€āļžāļ·āđˆāļ­āļĒāļīāļ‡ HTTP Request āļˆāļĢāļīāļ‡āđ„āļ›āļĒāļąāļ‡ App * **āļŠāļīāđˆāļ‡āļ—āļĩāđˆāļ•āđ‰āļ­āļ‡āļ—āļ”āļŠāļ­āļš:** āļāļēāļĢāđ€āļĢāļĩāļĒāļ document numbering service, āđāļĨāļ°āļāļēāļĢāļ—āļģāļ‡āļēāļ™āļ‚āļ­āļ‡ Views (āđ€āļŠāđˆāļ™ v_user_tasks) * **E2E (End-to-End) Tests:** * **āđ€āļ›āđ‰āļēāļŦāļĄāļēāļĒ:** āļ—āļ”āļŠāļ­āļš API Contract āļ§āđˆāļē Response Body Shape āļ•āļĢāļ‡āļ•āļēāļĄāđ€āļ­āļāļŠāļēāļĢ Swagger āđ€āļžāļ·āđˆāļ­āļĢāļąāļšāļ›āļĢāļ°āļāļąāļ™āļ—āļĩāļĄ Frontend ### **3.10 Security Testing:** * **Penetration Testing:** āļ—āļ”āļŠāļ­āļš OWASP Top 10 vulnerabilities * **Security Audit:** Review code āļŠāļģāļŦāļĢāļąāļš security flaws * **Virus Scanning Test:** āļ—āļ”āļŠāļ­āļš file upload security * **Rate Limiting Test:** āļ—āļ”āļŠāļ­āļš rate limiting functionality ### **3.11 Performance Testing:** * **Load Testing:** āļ—āļ”āļŠāļ­āļšāļ”āđ‰āļ§āļĒ realistic workloads * **Stress Testing:** āļŦāļē breaking points āļ‚āļ­āļ‡āļĢāļ°āļšāļš * **Endurance Testing:** āļ—āļ”āļŠāļ­āļšāļāļēāļĢāļ—āļģāļ‡āļēāļ™āļ•āđˆāļ­āđ€āļ™āļ·āđˆāļ­āļ‡āđ€āļ›āđ‡āļ™āđ€āļ§āļĨāļēāļ™āļēāļ™ ### 🗄ïļ**3.12 Backend State Management** Backend (NestJS) āļ„āļ§āļĢāđ€āļ›āđ‡āļ™ **Stateless** (āđ„āļĄāđˆāđ€āļāđ‡āļšāļŠāļ–āļēāļ™āļ°) "State" āļ—āļąāđ‰āļ‡āļŦāļĄāļ”āļˆāļ°āļ–āļđāļāļˆāļąāļ”āđ€āļāđ‡āļšāđƒāļ™ MariaDB * **Request-Scoped State (āļŠāļ–āļēāļ™āļ°āļ āļēāļĒāđƒāļ™ Request āđ€āļ”āļĩāļĒāļ§):** * **āļ›āļąāļāļŦāļē:** āļˆāļ°āļŠāđˆāļ‡āļ•āđˆāļ­āļ‚āđ‰āļ­āļĄāļđāļĨ (āđ€āļŠāđˆāļ™ User āļ—āļĩāđˆāļĨāđ‡āļ­āļāļ­āļīāļ™) āļĢāļ°āļŦāļ§āđˆāļēāļ‡ Guard āđāļĨāļ° Service āđƒāļ™ Request āđ€āļ”āļĩāļĒāļ§āļāļąāļ™āđ„āļ”āđ‰āļ­āļĒāđˆāļēāļ‡āđ„āļĢ? * **āļ§āļīāļ˜āļĩāđāļāđ‰:** āđƒāļŠāđ‰ **Request-Scoped Providers** āļ‚āļ­āļ‡ NestJS (āđ€āļŠāđˆāļ™ AuthContextService) āđ€āļžāļ·āđˆāļ­āđ€āļāđ‡āļšāļ‚āđ‰āļ­āļĄāļđāļĨ User āļ›āļąāļˆāļˆāļļāļšāļąāļ™āļ—āļĩāđˆāđ„āļ”āđ‰āļˆāļēāļ AuthGuard āđāļĨāļ°āđƒāļŦāđ‰ Service āļ­āļ·āđˆāļ™ Inject āđ„āļ›āđƒāļŠāđ‰ * **Application-Scoped State (āļāļēāļĢ Caching):** * **āļ›āļąāļāļŦāļē:** āļ‚āđ‰āļ­āļĄāļđāļĨ Master (āđ€āļŠāđˆāļ™ roles, permissions, organizations) āļ–āļđāļāđ€āļĢāļĩāļĒāļāđƒāļŠāđ‰āļšāđˆāļ­āļĒ * **āļ§āļīāļ˜āļĩāđāļāđ‰:** āđƒāļŠāđ‰ **Caching** (āđ€āļŠāđˆāļ™ @nestjs/cache-manager) āđ€āļžāļ·āđˆāļ­ Caching āļ‚āđ‰āļ­āļĄāļđāļĨāđ€āļŦāļĨāđˆāļēāļ™āļĩāđ‰ āđāļĨāļ°āļĨāļ”āļ āļēāļĢāļ° Database ### **3.13 Caching Strategy (āļ•āļēāļĄāļ‚āđ‰āļ­ 6.4.2):** * **Master Data Cache:** Roles, Permissions, Organizations (TTL: 1 hour) * **User Session Cache:** User permissions āđāļĨāļ° profile (TTL: 30 minutes) * **Search Result Cache:** Frequently searched queries (TTL: 15 minutes) * **File Metadata Cache:** Attachment metadata (TTL: 1 hour) * **Cache Invalidation:** Clear cache on update/delete operations ### **3.14 āļāļēāļĢāđ„āļŦāļĨāļ‚āļ­āļ‡āļ‚āđ‰āļ­āļĄāļđāļĨ (Data Flow)** #### **3.14.1 Main Flow:** 1. Request: āļœāđˆāļēāļ™ Nginx Proxy Manager -> NestJS Controller 2. **Rate Limiting:** RateLimitGuard āļ•āļĢāļ§āļˆāļŠāļ­āļš request limits 3. **Input Validation:** Validation Pipe āļ•āļĢāļ§āļˆāļŠāļ­āļšāđāļĨāļ° sanitize inputs 4. Authentication: JWT Guard āļ•āļĢāļ§āļˆāļŠāļ­āļš Token āđāļĨāļ°āļ”āļķāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨ User 5. Authorization: RBAC Guard āļ•āļĢāļ§āļˆāļŠāļ­āļšāļŠāļīāļ—āļ˜āļīāđŒ 6. **Security Checks:** Virus scanning (āļŠāļģāļŦāļĢāļąāļš file upload), XSS protection 7. Business Logic: Service Layer āļ›āļĢāļ°āļĄāļ§āļĨāļœāļĨāļ•āļĢāļĢāļāļ°āļ—āļēāļ‡āļ˜āļļāļĢāļāļīāļˆ 8. **Resilience:** Circuit breaker āđāļĨāļ° retry logic āļŠāļģāļŦāļĢāļąāļš external calls 9. Data Access: Repository Layer āļ•āļīāļ”āļ•āđˆāļ­āļāļąāļšāļāļēāļ™āļ‚āđ‰āļ­āļĄāļđāļĨ 10. **Caching:** Cache frequently accessed data 11. **Audit Log:** āļšāļąāļ™āļ—āļķāļāļāļēāļĢāļāļĢāļ°āļ—āļģāļŠāļģāļ„āļąāļ 12. Response: āļŠāđˆāļ‡āļāļĨāļąāļšāđ„āļ›āļĒāļąāļ‡ Frontend #### **3.14.2 Workflow Data Flow:** 1. User āļŠāļĢāđ‰āļēāļ‡āđ€āļ­āļāļŠāļēāļĢ â†’ āđ€āļĨāļ·āļ­āļ routing template 2. System āļŠāļĢāđ‰āļēāļ‡ routing instances āļ•āļēāļĄ template 3. āļŠāļģāļŦāļĢāļąāļšāđāļ•āđˆāļĨāļ° routing step: - āļāļģāļŦāļ™āļ” due date (āļˆāļēāļ expected_days) - āļŠāđˆāļ‡ notification āđ„āļ›āļĒāļąāļ‡āļ­āļ‡āļ„āđŒāļāļĢāļœāļđāđ‰āļĢāļąāļš - āļ­āļąāļžāđ€āļ”āļ—āļŠāļ–āļēāļ™āļ°āđ€āļ›āđ‡āļ™ SENT 4. āđ€āļĄāļ·āđˆāļ­āļ­āļ‡āļ„āđŒāļāļĢāļœāļđāđ‰āļĢāļąāļšāļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ: - āļ­āļąāļžāđ€āļ”āļ—āļŠāļ–āļēāļ™āļ°āđ€āļ›āđ‡āļ™ ACTIONED/FORWARDED/REPLIED - āļšāļąāļ™āļ—āļķāļ processed_by āđāļĨāļ° processed_at - āļŠāđˆāļ‡ notification āđ„āļ›āļĒāļąāļ‡āļ‚āļąāđ‰āļ™āļ•āļ­āļ™āļ•āđˆāļ­āđ„āļ› (āļ–āđ‰āļēāļĄāļĩ) 5. āđ€āļĄāļ·āđˆāļ­āļ„āļĢāļšāļ—āļļāļāļ‚āļąāđ‰āļ™āļ•āļ­āļ™ â†’ āļ­āļąāļžāđ€āļ”āļ—āļŠāļ–āļēāļ™āļ°āđ€āļ­āļāļŠāļēāļĢāđ€āļ›āđ‡āļ™ COMPLETED #### **3.14.3 JSON Details Processing Flow:** 1. **Receive Request** → Get JSON data from client 2. **Schema Validation** → Validate against predefined schema 3. **Data Sanitization** → Sanitize and transform data 4. **Version Check** → Handle schema version compatibility 5. **Storage** → Store validated JSON in database 6. **Retrieval** → Retrieve and transform on demand ### 📊**3.15 Monitoring & Observability (āļ•āļēāļĄāļ‚āđ‰āļ­ 6.8)** #### **Application Monitoring:** * **Health Checks:** `/health` endpoint āļŠāļģāļŦāļĢāļąāļš load balancer * **Metrics Collection:** Response times, error rates, throughput * **Distributed Tracing:** āļŠāļģāļŦāļĢāļąāļš request tracing across services * **Log Aggregation:** Structured logging āļ”āđ‰āļ§āļĒ JSON format * **Alerting:** āļŠāļģāļŦāļĢāļąāļš critical errors āđāļĨāļ° performance degradation #### **Business Metrics:** * āļˆāļģāļ™āļ§āļ™ documents created āļ•āđˆāļ­āļ§āļąāļ™ * Workflow completion rates * User activity metrics * System utilization rates * Search query performance #### **Performance Targets:** * API Response Time: < 200ms (90th percentile) * Search Query Performance: < 500ms * File Upload Performance: < 30 seconds āļŠāļģāļŦāļĢāļąāļšāđ„āļŸāļĨāđŒ 50MB * Cache Hit Ratio: > 80% ## ðŸ–Ĩïļ**4. āļŸāļĢāļ­āļ™āļ•āđŒāđ€āļ­āļ™āļ”āđŒ (NextJS / React / UI) (Frontend (NextJS / React / UI))** **āđ‚āļ›āļĢāđ„āļŸāļĨāđŒāļ™āļąāļāļžāļąāļ’āļ™āļē (Developer Profile:** āļ§āļīāļĻāļ§āļāļĢ TypeScript + React/NextJS āļĢāļ°āļ”āļąāļš Senior āđ€āļŠāļĩāđˆāļĒāļ§āļŠāļēāļ TailwindCSS, Shadcn/UI, āđāļĨāļ° Radix āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļžāļąāļ’āļ™āļē UI ### **4.1 āđāļ™āļ§āļ—āļēāļ‡āļāļēāļĢāļžāļąāļ’āļ™āļēāđ‚āļ„āđ‰āļ” (Code Implementation Guidelines)** * āđƒāļŠāđ‰ **early returns** āđ€āļžāļ·āđˆāļ­āļ„āļ§āļēāļĄāļŠāļąāļ”āđ€āļˆāļ™ * āđƒāļŠāđ‰āļ„āļĨāļēāļŠāļ‚āļ­āļ‡ **TailwindCSS** āđƒāļ™āļāļēāļĢāļāļģāļŦāļ™āļ”āļŠāđ„āļ•āļĨāđŒāđ€āļŠāļĄāļ­ * āļ„āļ§āļĢāđƒāļŠāđ‰ class: syntax āđāļšāļšāļĄāļĩāđ€āļ‡āļ·āđˆāļ­āļ™āđ„āļ‚ (āļŦāļĢāļ·āļ­ utility clsx) āļĄāļēāļāļāļ§āđˆāļēāļāļēāļĢāđƒāļŠāđ‰ ternary operators āđƒāļ™ class strings * āđƒāļŠāđ‰ **const arrow functions** āļŠāļģāļŦāļĢāļąāļš components āđāļĨāļ° handlers * Event handlers āđƒāļŦāđ‰āļ‚āļķāđ‰āļ™āļ•āđ‰āļ™āļ”āđ‰āļ§āļĒ handle... (āđ€āļŠāđˆāļ™ handleClick, handleSubmit) * āļĢāļ§āļĄāđāļ­āļ•āļ—āļĢāļīāļšāļīāļ§āļ•āđŒāļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāđ€āļ‚āđ‰āļēāļ–āļķāļ‡ (accessibility) āļ”āđ‰āļ§āļĒ: tabIndex="0", aria-label, onKeyDown, āļŊāļĨāļŊ * āļ•āļĢāļ§āļˆāļŠāļ­āļšāđƒāļŦāđ‰āđāļ™āđˆāđƒāļˆāļ§āđˆāļēāđ‚āļ„āđ‰āļ”āļ—āļąāđ‰āļ‡āļŦāļĄāļ” **āļŠāļĄāļšāļđāļĢāļ“āđŒ**, **āļœāđˆāļēāļ™āļāļēāļĢāļ—āļ”āļŠāļ­āļš**, āđāļĨāļ° **āđ„āļĄāđˆāļ‹āđ‰āļģāļ‹āđ‰āļ­āļ™ (DRY)** * āļ•āđ‰āļ­āļ‡ import āđ‚āļĄāļ”āļđāļĨāļ—āļĩāđˆāļˆāļģāđ€āļ›āđ‡āļ™āļ•āđ‰āļ­āļ‡āđƒāļŠāđ‰āļ­āļĒāđˆāļēāļ‡āļŠāļąāļ”āđ€āļˆāļ™āđ€āļŠāļĄāļ­ ### **4.2 UI/UX āļ”āđ‰āļ§āļĒ React** * āđƒāļŠāđ‰ **semantic HTML** * āđƒāļŠāđ‰āļ„āļĨāļēāļŠāļ‚āļ­āļ‡ **Tailwind** āļ—āļĩāđˆāļĢāļ­āļ‡āļĢāļąāļš responsive (sm:, md:, lg:) * āļĢāļąāļāļĐāļēāļĨāļģāļ”āļąāļšāļŠāļąāđ‰āļ™āļ‚āļ­āļ‡āļāļēāļĢāļĄāļ­āļ‡āđ€āļŦāđ‡āļ™ (visual hierarchy) āļ”āđ‰āļ§āļĒāļāļēāļĢāđƒāļŠāđ‰ typography āđāļĨāļ° spacing * āđƒāļŠāđ‰ **Shadcn** components (Button, Input, Card, āļŊāļĨāļŊ) āđ€āļžāļ·āđˆāļ­ UI āļ—āļĩāđˆāļŠāļ­āļ”āļ„āļĨāđ‰āļ­āļ‡āļāļąāļ™ * āļ—āļģāđƒāļŦāđ‰ components āļĄāļĩāļ‚āļ™āļēāļ”āđ€āļĨāđ‡āļāđāļĨāļ°āļĄāļļāđˆāļ‡āđ€āļ™āđ‰āļ™āļāļēāļĢāļ—āļģāļ‡āļēāļ™āđ€āļ‰āļžāļēāļ°āļ­āļĒāđˆāļēāļ‡ * āđƒāļŠāđ‰ utility classes āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļˆāļąāļ”āļŠāđ„āļ•āļĨāđŒāļ­āļĒāđˆāļēāļ‡āļĢāļ§āļ”āđ€āļĢāđ‡āļ§ (spacing, colors, text, āļŊāļĨāļŊ) * āļ•āļĢāļ§āļˆāļŠāļ­āļšāđƒāļŦāđ‰āđāļ™āđˆāđƒāļˆāļ§āđˆāļēāļŠāļ­āļ”āļ„āļĨāđ‰āļ­āļ‡āļāļąāļš **ARIA** āđāļĨāļ°āđƒāļŠāđ‰ semantic markup ### **4.3 āļāļēāļĢāļ•āļĢāļ§āļˆāļŠāļ­āļšāļŸāļ­āļĢāđŒāļĄāđāļĨāļ°āļ‚āđ‰āļ­āļœāļīāļ”āļžāļĨāļēāļ” (Form Validation & Errors)** * āđƒāļŠāđ‰āđ„āļĨāļšāļĢāļēāļĢāļĩāļāļąāđˆāļ‡ client āđ€āļŠāđˆāļ™ zod āđāļĨāļ° react-hook-form * āđāļŠāļ”āļ‡āļ‚āđ‰āļ­āļœāļīāļ”āļžāļĨāļēāļ”āļ”āđ‰āļ§āļĒ **alert components** āļŦāļĢāļ·āļ­āļ‚āđ‰āļ­āļ„āļ§āļēāļĄ inline * āļ•āđ‰āļ­āļ‡āļĄāļĩ labels, placeholders, āđāļĨāļ°āļ‚āđ‰āļ­āļ„āļ§āļēāļĄ feedback ### **🧊4.4 Frontend Testing** āđ€āļĢāļēāļˆāļ°āđƒāļŠāđ‰ **React Testing Library (RTL)** āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļ—āļ”āļŠāļ­āļš Component āđāļĨāļ° **Playwright** āļŠāļģāļŦāļĢāļąāļš E2E: * **Unit Tests (āļāļēāļĢāļ—āļ”āļŠāļ­āļšāļŦāļ™āđˆāļ§āļĒāļĒāđˆāļ­āļĒ):** * **āđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­:** Vitest + RTL * **āđ€āļ›āđ‰āļēāļŦāļĄāļēāļĒ:** āļ—āļ”āļŠāļ­āļš Component āļ‚āļ™āļēāļ”āđ€āļĨāđ‡āļ (āđ€āļŠāđˆāļ™ Buttons, Inputs) āļŦāļĢāļ·āļ­ Utility functions * **Integration Tests (āļāļēāļĢāļ—āļ”āļŠāļ­āļšāļāļēāļĢāļšāļđāļĢāļ“āļēāļāļēāļĢ):** * **āđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­:** RTL + **Mock Service Worker (MSW)** * **āđ€āļ›āđ‰āļēāļŦāļĄāļēāļĒ:** āļ—āļ”āļŠāļ­āļšāļ§āđˆāļē Component āļŦāļĢāļ·āļ­ Page āļ—āļģāļ‡āļēāļ™āļāļąāļš API (āļ—āļĩāđˆāļˆāļģāļĨāļ­āļ‡āļ‚āļķāđ‰āļ™) āđ„āļ”āđ‰āļ–āļđāļāļ•āđ‰āļ­āļ‡ * **āđ€āļ—āļ„āļ™āļīāļ„:** āđƒāļŠāđ‰ MSW āđ€āļžāļ·āđˆāļ­āļˆāļģāļĨāļ­āļ‡ NestJS API āđāļĨāļ°āļ—āļ”āļŠāļ­āļšāļ§āđˆāļē Component āđāļŠāļ”āļ‡āļœāļĨāļ‚āđ‰āļ­āļĄāļđāļĨāļˆāļģāļĨāļ­āļ‡āđ„āļ”āđ‰āļ–āļđāļāļ•āđ‰āļ­āļ‡āļŦāļĢāļ·āļ­āđ„āļĄāđˆ (āđ€āļŠāđˆāļ™ āļ—āļ”āļŠāļ­āļšāļŦāļ™āđ‰āļē Dashboard [cite: 5.3] āļ—āļĩāđˆāļ”āļķāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāļˆāļēāļ v_user_tasks) * **E2E (End-to-End) Tests:** * **āđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­:** **Playwright** * **āđ€āļ›āđ‰āļēāļŦāļĄāļēāļĒ:** āļ—āļ”āļŠāļ­āļš User Flow āļ—āļąāđ‰āļ‡āļĢāļ°āļšāļšāđ‚āļ”āļĒāļ­āļąāļ•āđ‚āļ™āļĄāļąāļ•āļī (āđ€āļŠāđˆāļ™ āļĨāđ‡āļ­āļāļ­āļīāļ™ -> āļŠāļĢāđ‰āļēāļ‡ RFA -> āļ•āļĢāļ§āļˆāļŠāļ­āļš Workflow Visualization [cite: 5.6]) ### **🗄ïļ4.5 Frontend State Management** āļŠāļģāļŦāļĢāļąāļš Next.js App Router āđ€āļĢāļēāļˆāļ°āđāļšāđˆāļ‡ State āđ€āļ›āđ‡āļ™ 4 āļĢāļ°āļ”āļąāļš: 1. **Local UI State (āļŠāļ–āļēāļ™āļ° UI āļŠāļąāđˆāļ§āļ„āļĢāļēāļ§):** * **āđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­:** useState, useReducer * **āđƒāļŠāđ‰āđ€āļĄāļ·āđˆāļ­:** āļˆāļąāļ”āļāļēāļĢāļŠāļ–āļēāļ™āļ°āđ€āļĨāđ‡āļāđ† āļ—āļĩāđˆāļˆāļšāđƒāļ™ Component āđ€āļ”āļĩāļĒāļ§ (āđ€āļŠāđˆāļ™ Modal āđ€āļ›āļīāļ”/āļ›āļīāļ”, āļ„āđˆāļēāđƒāļ™ Input) 2. **Server State (āļŠāļ–āļēāļ™āļ°āļ‚āđ‰āļ­āļĄāļđāļĨāļˆāļēāļāđ€āļ‹āļīāļĢāđŒāļŸāđ€āļ§āļ­āļĢāđŒ):** * **āđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­:** **React Query (TanStack Query)** āļŦāļĢāļ·āļ­ SWR * **āđƒāļŠāđ‰āđ€āļĄāļ·āđˆāļ­:** āļˆāļąāļ”āļāļēāļĢāļ‚āđ‰āļ­āļĄāļđāļĨāļ—āļĩāđˆāļ”āļķāļ‡āļĄāļēāļˆāļēāļ NestJS API (āđ€āļŠāđˆāļ™ āļĢāļēāļĒāļāļēāļĢ correspondences, rfas, drawings) * **āļ—āļģāđ„āļĄ:** React Query āđ€āļ›āđ‡āļ™ "Cache" āļ—āļĩāđˆāļˆāļąāļ”āļāļēāļĢ Caching, Re-fetching, āđāļĨāļ° Invalidation āđƒāļŦāđ‰āđ‚āļ”āļĒāļ­āļąāļ•āđ‚āļ™āļĄāļąāļ•āļī 3. **Global Client State (āļŠāļ–āļēāļ™āļ°āļŠāđˆāļ§āļ™āļāļĨāļēāļ‡āļāļąāđˆāļ‡ Client):** * **āđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­:** **Zustand** (āđāļ™āļ°āļ™āļģ) āļŦāļĢāļ·āļ­ Context API * **āđƒāļŠāđ‰āđ€āļĄāļ·āđˆāļ­:** āļˆāļąāļ”āļāļēāļĢāļ‚āđ‰āļ­āļĄāļđāļĨāļ—āļĩāđˆāļ•āđ‰āļ­āļ‡āđƒāļŠāđ‰āļĢāđˆāļ§āļĄāļāļąāļ™āļ—āļąāđˆāļ§āļ—āļąāđ‰āļ‡āđāļ­āļ› āđāļĨāļ° *āđ„āļĄāđˆāđƒāļŠāđˆ* āļ‚āđ‰āļ­āļĄāļđāļĨāļˆāļēāļāđ€āļ‹āļīāļĢāđŒāļŸāđ€āļ§āļ­āļĢāđŒ (āđ€āļŠāđˆāļ™ āļ‚āđ‰āļ­āļĄāļđāļĨ User āļ—āļĩāđˆāļĨāđ‡āļ­āļāļ­āļīāļ™, āļŠāļīāļ—āļ˜āļīāđŒ Permissions) 4. **Form State (āļŠāļ–āļēāļ™āļ°āļ‚āļ­āļ‡āļŸāļ­āļĢāđŒāļĄ):** * **āđ€āļ„āļĢāļ·āđˆāļ­āļ‡āļĄāļ·āļ­:** **React Hook Form** + **Zod** * **āđƒāļŠāđ‰āđ€āļĄāļ·āđˆāļ­:** āļˆāļąāļ”āļāļēāļĢāļŸāļ­āļĢāđŒāļĄāļ—āļĩāđˆāļ‹āļąāļšāļ‹āđ‰āļ­āļ™ (āđ€āļŠāđˆāļ™ āļŸāļ­āļĢāđŒāļĄāļŠāļĢāđ‰āļēāļ‡ RFA, āļŸāļ­āļĢāđŒāļĄ Circulation [cite: 3.7]) ## 🔗**5. āđāļ™āļ§āļ—āļēāļ‡āļāļēāļĢāļšāļđāļĢāļ“āļēāļāļēāļĢ Full Stack (Full Stack Integration Guidelines)** | Aspect (āđāļ‡āđˆāļĄāļļāļĄ) | Backend (NestJS) | Frontend (NextJS) | UI Layer (Tailwind/Shadcn) | | :---- | :---- | :---- | :---- | | API | REST / GraphQL Controllers | API hooks āļœāđˆāļēāļ™ fetch/axios/SWR | Components āļ—āļĩāđˆāļĢāļąāļšāļ‚āđ‰āļ­āļĄāļđāļĨ | | Validation (āļāļēāļĢāļ•āļĢāļ§āļˆāļŠāļ­āļš) | class-validator DTOs | zod / react-hook-form | āļŠāļ–āļēāļ™āļ°āļ‚āļ­āļ‡āļŸāļ­āļĢāđŒāļĄ/input āđƒāļ™ Shadcn | | Auth (āļāļēāļĢāļĒāļ·āļ™āļĒāļąāļ™āļ•āļąāļ§āļ•āļ™) | Guards, JWT | NextAuth / cookies | āļŠāļ–āļēāļ™āļ° UI āļ‚āļ­āļ‡ Auth (loading, signed in) | | Errors (āļ‚āđ‰āļ­āļœāļīāļ”āļžāļĨāļēāļ”) | Global filters | Toasts / modals | Alerts / āļ‚āđ‰āļ­āļ„āļ§āļēāļĄ feedback | | Testing (āļāļēāļĢāļ—āļ”āļŠāļ­āļš) | Jest (unit/e2e) | Vitest / Playwright | Visual regression | | Styles (āļŠāđ„āļ•āļĨāđŒ) | Scoped modules (āļ–āđ‰āļēāļˆāļģāđ€āļ›āđ‡āļ™) | Tailwind / Shadcn | Tailwind utilities | | Accessibility (āļāļēāļĢāđ€āļ‚āđ‰āļēāļ–āļķāļ‡) | Guards + filters | ARIA attributes | Semantic HTML | ## 🗂ïļ**6. āļ‚āđ‰āļ­āļ•āļāļĨāļ‡āđ€āļ‰āļžāļēāļ°āļŠāļģāļŦāļĢāļąāļš DMS (LCBP3-DMS)** āļŠāđˆāļ§āļ™āļ™āļĩāđ‰āļ‚āļĒāļēāļĒāđāļ™āļ§āļ—āļēāļ‡ FullStackJS āļ—āļąāđˆāļ§āđ„āļ›āļŠāļģāļŦāļĢāļąāļšāđ‚āļ›āļĢāđ€āļˆāļāļ•āđŒ **LCBP3-DMS** āđ‚āļ”āļĒāļĄāļļāđˆāļ‡āđ€āļ™āđ‰āļ™āđ„āļ›āļ—āļĩāđˆāđ€āļ§āļīāļĢāđŒāļāđ‚āļŸāļĨāļ§āđŒāļāļēāļĢāļ­āļ™āļļāļĄāļąāļ•āļīāđ€āļ­āļāļŠāļēāļĢ (Correspondence, RFA, Drawing, Contract, Transmittal, Circulation) ### ðŸ§Đ**6.1 RBAC āđāļĨāļ°āļāļēāļĢāļ„āļ§āļšāļ„āļļāļĄāļŠāļīāļ—āļ˜āļīāđŒ (RBAC & Permission Control)** āđƒāļŠāđ‰ Decorators āđ€āļžāļ·āđˆāļ­āļšāļąāļ‡āļ„āļąāļšāđƒāļŠāđ‰āļŠāļīāļ—āļ˜āļīāđŒāļāļēāļĢāđ€āļ‚āđ‰āļēāļ–āļķāļ‡ āđ‚āļ”āļĒāļ­āđ‰āļēāļ‡āļ­āļīāļ‡āļŠāļīāļ—āļ˜āļīāđŒāļˆāļēāļāļ•āļēāļĢāļēāļ‡ permissions ```typescript @RequirePermission('rfas.respond') // āļ•āđ‰āļ­āļ‡āļ•āļĢāļ‡āļāļąāļš 'permission_code' @Put(':id') updateRFA(@Param('id') id: string) { return this.rfaService.update(id); } ``` #### **6.1.1 Roles (āļšāļ—āļšāļēāļ—)** * **Superadmin**: āđ„āļĄāđˆāļĄāļĩāļ‚āđ‰āļ­āļˆāļģāļāļąāļ”āđƒāļ”āđ† [cite: 4.3] * **Admin**: āļĄāļĩāļŠāļīāļ—āļ˜āļīāđŒāđ€āļ•āđ‡āļĄāļ—āļĩāđˆāđƒāļ™āļ­āļ‡āļ„āđŒāļāļĢ [cite: 4.3] * **Document Control**: āđ€āļžāļīāđˆāļĄ/āđāļāđ‰āđ„āļ‚/āļĨāļš āđ€āļ­āļāļŠāļēāļĢāđƒāļ™āļ­āļ‡āļ„āđŒāļāļĢ [cite: 4.3] * **Editor**: āļŠāļēāļĄāļēāļĢāļ– āđ€āļžāļīāđˆāļĄ/āđāļāđ‰āđ„āļ‚ āđ€āļ­āļāļŠāļēāļĢāļ—āļĩāđˆāļāļģāļŦāļ™āļ” [cite: 4.3] * **Viewer**: āļŠāļēāļĄāļēāļĢāļ–āļ”āļđ āđ€āļ­āļāļŠāļēāļĢ [cite: 4.3] #### **6.1.2 āļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡ Permissions (āļˆāļēāļāļ•āļēāļĢāļēāļ‡ permissions)** * rfas.view, rfas.create, rfas.respond, rfas.delete * drawings.view, drawings.upload, drawings.delete * corr.view, corr.manage * transmittals.manage * cirs.manage * project_parties.manage āļāļēāļĢāļˆāļąāļšāļ„āļđāđˆāļĢāļ°āļŦāļ§āđˆāļēāļ‡ roles āđāļĨāļ° permissions **āđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™** āļˆāļ°āļ–āļđāļ seed āļœāđˆāļēāļ™āļŠāļ„āļĢāļīāļ›āļ•āđŒ (āļ”āļąāļ‡āļ—āļĩāđˆāđ€āļŦāđ‡āļ™āđƒāļ™āđ„āļŸāļĨāđŒ SQL)**āļ­āļĒāđˆāļēāļ‡āđ„āļĢāļāđ‡āļ•āļēāļĄ AuthModule/UserModule āļ•āđ‰āļ­āļ‡āļĄāļĩ API āļŠāļģāļŦāļĢāļąāļš Admin āđ€āļžāļ·āđˆāļ­āļŠāļĢāđ‰āļēāļ‡ Role āđƒāļŦāļĄāđˆāđāļĨāļ°āļāļģāļŦāļ™āļ”āļŠāļīāļ—āļ˜āļīāđŒ (Permissions) āđ€āļžāļīāđˆāļĄāđ€āļ•āļīāļĄāđ„āļ”āđ‰āđƒāļ™āļ āļēāļĒāļŦāļĨāļąāļ‡** [cite: 4.3] ### ðŸ§ū**6.2 āļĄāļēāļ•āļĢāļāļēāļ™ AuditLog (AuditLog Standard)** āļšāļąāļ™āļ—āļķāļāļāļēāļĢāļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ CRUD āđāļĨāļ°āļāļēāļĢāļˆāļąāļšāļ„āļđāđˆāļ—āļąāđ‰āļ‡āļŦāļĄāļ”āļĨāļ‡āđƒāļ™āļ•āļēāļĢāļēāļ‡ audit_logs | Field (āļŸāļīāļĨāļ”āđŒ) | Type (āļˆāļēāļ SQL) | Description (āļ„āļģāļ­āļ˜āļīāļšāļēāļĒ) | | :---- | :---- | :---- | | audit_id | BIGINT | Primary Key | | user_id | INT | āļœāļđāđ‰āđƒāļŠāđ‰āļ—āļĩāđˆāļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ (FK -> users) | | action | VARCHAR(100) | rfa.create, correspondence.update, login.success | | entity_type | VARCHAR(50) | āļŠāļ·āđˆāļ­āļ•āļēāļĢāļēāļ‡/āđ‚āļĄāļ”āļđāļĨ āđ€āļŠāđˆāļ™ 'rfa', 'correspondence' | | entity_id | VARCHAR(50) | Primary ID āļ‚āļ­āļ‡āļĢāļ°āđ€āļšāļĩāļĒāļ™āļ—āļĩāđˆāđ„āļ”āđ‰āļĢāļąāļšāļœāļĨāļāļĢāļ°āļ—āļš | | details_json | JSON | āļ‚āđ‰āļ­āļĄāļđāļĨāļšāļĢāļīāļšāļ— (āđ€āļŠāđˆāļ™ āļŸāļīāļĨāļ”āđŒāļ—āļĩāđˆāļĄāļĩāļāļēāļĢāđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡) | | ip_address | VARCHAR(45) | IP address āļ‚āļ­āļ‡āļœāļđāđ‰āļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ | | user_agent | VARCHAR(255) | User Agent āļ‚āļ­āļ‡āļœāļđāđ‰āļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ | | created_at | TIMESTAMP | Timestamp (UTC) | ### 📂**6.3 āļāļēāļĢāļˆāļąāļ”āļāļēāļĢāđ„āļŸāļĨāđŒ (File Handling)** #### **6.3.1 āļĄāļēāļ•āļĢāļāļēāļ™āļāļēāļĢāļ­āļąāļ›āđ‚āļŦāļĨāļ”āđ„āļŸāļĨāđŒ (File Upload Standard)** * **Security-First Approach:** āļāļēāļĢāļ­āļąāļ›āđ‚āļŦāļĨāļ”āđ„āļŸāļĨāđŒāļ—āļąāđ‰āļ‡āļŦāļĄāļ”āļˆāļ°āļ–āļđāļāļˆāļąāļ”āļāļēāļĢāđ‚āļ”āļĒ FileStorageService āļ—āļĩāđˆāļĄāļĩ security measures āļ„āļĢāļšāļ–āđ‰āļ§āļ™ * āđ„āļŸāļĨāđŒāļˆāļ°āļ–āļđāļāđ€āļŠāļ·āđˆāļ­āļĄāđ‚āļĒāļ‡āđ„āļ›āļĒāļąāļ‡ Entity āļ—āļĩāđˆāļ–āļđāļāļ•āđ‰āļ­āļ‡āļœāđˆāļēāļ™ **āļ•āļēāļĢāļēāļ‡āđ€āļŠāļ·āđˆāļ­āļĄ (Junction Tables)** āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™: * correspondence_attachments (āđ€āļŠāļ·āđˆāļ­āļĄ Correspondence āļāļąāļš Attachments) * circulation_attachments (āđ€āļŠāļ·āđˆāļ­āļĄ Circulation āļāļąāļš Attachments) * shop_drawing_revision_attachments (āđ€āļŠāļ·āđˆāļ­āļĄ Shop Drawing Revision āļāļąāļš Attachments) * contract_drawing_attachments (āđ€āļŠāļ·āđˆāļ­āļĄ Contract Drawing āļāļąāļš Attachments) * āđ€āļŠāđ‰āļ™āļ—āļēāļ‡āļˆāļąāļ”āđ€āļāđ‡āļšāđ„āļŸāļĨāđŒ (Upload path): āļ­āđ‰āļēāļ‡āļ­āļīāļ‡āļˆāļēāļ Requirement 2.1 āļ„āļ·āļ­ /share/dms-data [cite: 2.1] āđ‚āļ”āļĒ FileStorageService āļˆāļ°āļŠāļĢāđ‰āļēāļ‡āđ‚āļŸāļĨāđ€āļ”āļ­āļĢāđŒāļĒāđˆāļ­āļĒāđāļšāļšāļĢāļ§āļĄāļĻāļđāļ™āļĒāđŒ (āđ€āļŠāđˆāļ™ /share/dms-data/uploads/{YYYY}/{MM}/[stored_filename]) * āļ›āļĢāļ°āđ€āļ āļ—āđ„āļŸāļĨāđŒāļ—āļĩāđˆāļ­āļ™āļļāļāļēāļ•: pdf, dwg, docx, xlsx, zip (āļœāđˆāļēāļ™ white-list validation) * āļ‚āļ™āļēāļ”āļŠāļđāļ‡āļŠāļļāļ”: **50 MB** * āļˆāļąāļ”āđ€āļāđ‡āļšāļ™āļ­āļ webroot * āđƒāļŦāđ‰āļšāļĢāļīāļāļēāļĢāđ„āļŸāļĨāđŒāļœāđˆāļēāļ™ endpoint āļ—āļĩāđˆāļ›āļĨāļ­āļ”āļ āļąāļĒ /files/:attachment_id/download #### **6.3.2 Security Controls āļŠāļģāļŦāļĢāļąāļš File Access:** āļāļēāļĢāđ€āļ‚āđ‰āļēāļ–āļķāļ‡āđ„āļŸāļĨāđŒāđ„āļĄāđˆāđƒāļŠāđˆāļāļēāļĢāđ€āļ‚āđ‰āļēāļ–āļķāļ‡āđ‚āļ”āļĒāļ•āļĢāļ‡ endpoint /files/:attachment_id/download āļˆāļ°āļ•āđ‰āļ­āļ‡: 1. āļ„āđ‰āļ™āļŦāļēāļĢāļ°āđ€āļšāļĩāļĒāļ™ attachment 2. āļ•āļĢāļ§āļˆāļŠāļ­āļšāļ§āđˆāļē attachment_id āļ™āļĩāđ‰ āđ€āļŠāļ·āđˆāļ­āļĄāđ‚āļĒāļ‡āļāļąāļš Entity āđƒāļ” (āđ€āļŠāđˆāļ™ correspondence, circulation, shop_drawing_revision, contract_drawing) āļœāđˆāļēāļ™āļ•āļēāļĢāļēāļ‡āđ€āļŠāļ·āđˆāļ­āļĄ 3. āļ•āļĢāļ§āļˆāļŠāļ­āļšāļ§āđˆāļēāļœāļđāđ‰āđƒāļŠāđ‰āļĄāļĩāļŠāļīāļ—āļ˜āļīāđŒ (permission) āđƒāļ™āļāļēāļĢāļ”āļđ Entity āļ•āđ‰āļ™āļ—āļēāļ‡āļ™āļąāđ‰āļ™āđ† āļŦāļĢāļ·āļ­āđ„āļĄāđˆ 4. āļ•āļĢāļ§āļˆāļŠāļ­āļš download token expiration (24 āļŠāļąāđˆāļ§āđ‚āļĄāļ‡) 5. āļšāļąāļ™āļ—āļķāļ audit log āļāļēāļĢāļ”āļēāļ§āļ™āđŒāđ‚āļŦāļĨāļ” ### 🔟**6.4 āļāļēāļĢāļˆāļąāļ”āļāļēāļĢāđ€āļĨāļ‚āļ—āļĩāđˆāđ€āļ­āļāļŠāļēāļĢ (Document Numbering) [cite: 3.10]** * **āđ€āļ›āđ‰āļēāļŦāļĄāļēāļĒ:** āļŠāļĢāđ‰āļēāļ‡āđ€āļĨāļ‚āļ—āļĩāđˆāđ€āļ­āļāļŠāļēāļĢ (āđ€āļŠāđˆāļ™ correspondence_number) āđ‚āļ”āļĒāļ­āļąāļ•āđ‚āļ™āļĄāļąāļ•āļī āļ•āļēāļĄāļĢāļđāļ›āđāļšāļšāļ—āļĩāđˆāļāļģāļŦāļ™āļ” * **āļ•āļĢāļĢāļāļ°āļāļēāļĢāļ™āļąāļš:** āļāļēāļĢāļ™āļąāļš Running number (SEQ) āļˆāļ°āļ™āļąāļšāđāļĒāļāļ•āļēāļĄ Key: **Project + Originator Organization + Document Type + Year** * **āļ•āļēāļĢāļēāļ‡ SQL:** * document_number_formats: Admin āđƒāļŠāđ‰āļāļģāļŦāļ™āļ” "āļĢāļđāļ›āđāļšāļš" (Template) āļ‚āļ­āļ‡āđ€āļĨāļ‚āļ—āļĩāđˆ (āđ€āļŠāđˆāļ™ {ORG_CODE}-{TYPE_CODE}-{YEAR_SHORT}-{SEQ:4}) āđ‚āļ”āļĒāļāļģāļŦāļ™āļ”āļ•āļēāļĄ **Project** āđāļĨāļ° **Document Type** [cite: 4.5] * document_number_counters: āļĢāļ°āļšāļšāđƒāļŠāđ‰āđ€āļāđ‡āļš "āļ•āļąāļ§āļ™āļąāļš" āļĨāđˆāļēāļŠāļļāļ”āļ‚āļ­āļ‡ Key (Project+Org+Type+Year) * **āļāļēāļĢāļ—āļģāļ‡āļēāļ™ (Backend):** * DocumentNumberingModule āļˆāļ°āđƒāļŦāđ‰āļšāļĢāļīāļāļēāļĢ DocumentNumberingService * āđ€āļĄāļ·āđˆāļ­ CorrespondenceModule āļ•āđ‰āļ­āļ‡āļāļēāļĢāļŠāļĢāđ‰āļēāļ‡āđ€āļ­āļāļŠāļēāļĢāđƒāļŦāļĄāđˆ, āļĄāļąāļ™āļˆāļ°āđ€āļĢāļĩāļĒāļ documentNumberingService.generateNextNumber(...) * Service āļ™āļĩāđ‰āļˆāļ°āđƒāļŠāđ‰ **Redis distributed locking** āđāļ—āļ™ stored procedure āļ‹āļķāđˆāļ‡āļˆāļ°āļˆāļąāļ”āļāļēāļĢ Database Transaction āđāļĨāļ° Row Locking āļ āļēāļĒāđƒāļ™ Application Layer āđ€āļžāļ·āđˆāļ­āļĢāļąāļšāļ›āļĢāļ°āļāļąāļ™āļāļēāļĢāļ›āđ‰āļ­āļ‡āļāļąāļ™ Race Condition * āļĄāļĩ retry mechanism āđāļĨāļ° fallback strategies ### 📊**6.5 āļāļēāļĢāļĢāļēāļĒāļ‡āļēāļ™āđāļĨāļ°āļāļēāļĢāļŠāđˆāļ‡āļ­āļ­āļ (Reporting & Exports)** #### **5.8.1 āļ§āļīāļ§āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļĢāļēāļĒāļ‡āļēāļ™ (Reporting Views) (āļˆāļēāļ SQL)** āļāļēāļĢāļĢāļēāļĒāļ‡āļēāļ™āļ„āļ§āļĢāļŠāļĢāđ‰āļēāļ‡āļ‚āļķāđ‰āļ™āļˆāļēāļ Views āļ—āļĩāđˆāļāļģāļŦāļ™āļ”āđ„āļ§āđ‰āļĨāđˆāļ§āļ‡āļŦāļ™āđ‰āļēāđƒāļ™āļāļēāļ™āļ‚āđ‰āļ­āļĄāļđāļĨāđ€āļ›āđ‡āļ™āļŦāļĨāļąāļ: * v_current_correspondences: āļŠāļģāļŦāļĢāļąāļš revision āļ›āļąāļˆāļˆāļļāļšāļąāļ™āļ—āļąāđ‰āļ‡āļŦāļĄāļ”āļ‚āļ­āļ‡āđ€āļ­āļāļŠāļēāļĢāļ—āļĩāđˆāđ„āļĄāđˆāđƒāļŠāđˆ RFA * v_current_rfas: āļŠāļģāļŦāļĢāļąāļš revision āļ›āļąāļˆāļˆāļļāļšāļąāļ™āļ—āļąāđ‰āļ‡āļŦāļĄāļ”āļ‚āļ­āļ‡ RFA āđāļĨāļ°āļ‚āđ‰āļ­āļĄāļđāļĨ master * v_contract_parties_all: āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļ•āļĢāļ§āļˆāļŠāļ­āļšāļ„āļ§āļēāļĄāļŠāļąāļĄāļžāļąāļ™āļ˜āđŒāļ‚āļ­āļ‡ project/contract/organization * v_user_tasks: āļŠāļģāļŦāļĢāļąāļš Dashboard "āļ‡āļēāļ™āļ‚āļ­āļ‡āļ‰āļąāļ™" * v_audit_log_details: āļŠāļģāļŦāļĢāļąāļš Activity Feed Views āđ€āļŦāļĨāđˆāļēāļ™āļĩāđ‰āļ—āļģāļŦāļ™āđ‰āļēāļ—āļĩāđˆāđ€āļ›āđ‡āļ™āđāļŦāļĨāđˆāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāļŦāļĨāļąāļāļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāļĢāļēāļĒāļ‡āļēāļ™āļāļąāđˆāļ‡āđ€āļ‹āļīāļĢāđŒāļŸāđ€āļ§āļ­āļĢāđŒāđāļĨāļ°āļāļēāļĢāļŠāđˆāļ‡āļ­āļ­āļāļ‚āđ‰āļ­āļĄāļđāļĨ #### **5.8.2 āļāļŽāļāļēāļĢāļŠāđˆāļ‡āļ­āļ­āļ (Export Rules)** * Export formats: CSV, Excel, PDF. * āļˆāļąāļ”āđ€āļ•āļĢāļĩāļĒāļĄāļĄāļļāļĄāļĄāļ­āļ‡āļŠāļģāļŦāļĢāļąāļšāļžāļīāļĄāļžāđŒ (Print view). * āļĢāļ§āļĄāļĨāļīāļ‡āļāđŒāđ„āļ›āļĒāļąāļ‡āļ•āđ‰āļ™āļ—āļēāļ‡ (āđ€āļŠāđˆāļ™ /rfas/:id). ## ðŸ§Ū**7. āļŸāļĢāļ­āļ™āļ•āđŒāđ€āļ­āļ™āļ”āđŒ: āļĢāļđāļ›āđāļšāļš DataTable āđāļĨāļ°āļŸāļ­āļĢāđŒāļĄ (Frontend: DataTable & Form Patterns)** ### **7.1 DataTable (Server‑Side)** * Endpoint: /api/{module}?page=1&pageSize=20&sort=...&filter=... * āļ•āđ‰āļ­āļ‡āļĢāļ­āļ‡āļĢāļąāļš: āļāļēāļĢāđāļšāđˆāļ‡āļŦāļ™āđ‰āļē (pagination), āļāļēāļĢāđ€āļĢāļĩāļĒāļ‡āļĨāļģāļ”āļąāļš (sorting), āļāļēāļĢāļ„āđ‰āļ™āļŦāļē (search), āļāļēāļĢāļāļĢāļ­āļ‡ (filters) * āđāļŠāļ”āļ‡ revision āļĨāđˆāļēāļŠāļļāļ”āđāļšāļš inline āđ€āļŠāļĄāļ­ (āļŠāļģāļŦāļĢāļąāļš RFA/Drawing) ### **7.2 āļĄāļēāļ•āļĢāļāļēāļ™āļŸāļ­āļĢāđŒāļĄ (Form Standards)** * āļ•āđ‰āļ­āļ‡āļĄāļĩāļāļēāļĢāđƒāļŠāđ‰āļ‡āļēāļ™ Dropdowns āđāļšāļšāļ‚āļķāđ‰āļ™āļ•āđˆāļ­āļāļąāļ™ (Dependent dropdowns) (āļ•āļēāļĄāļ—āļĩāđˆāļŠāļ„āļĩāļĄāļēāļĢāļ­āļ‡āļĢāļąāļš): * Project → Contract Drawing Volumes * Contract Drawing Category → Sub-Category * RFA (āļ›āļĢāļ°āđ€āļ āļ— Shop Drawing) → Shop Drawing Revisions āļ—āļĩāđˆāđ€āļŠāļ·āđˆāļ­āļĄāđ‚āļĒāļ‡āđ„āļ”āđ‰ * **File Upload Security:** āļ•āđ‰āļ­āļ‡āļĢāļ­āļ‡āļĢāļąāļš **Multi-file upload (Drag-and-Drop)** [cite: 5.7] āļžāļĢāđ‰āļ­āļĄ virus scanning feedback * **File Type Indicators:** UI āļ•āđ‰āļ­āļ‡āļ­āļ™āļļāļāļēāļ•āđƒāļŦāđ‰āļœāļđāđ‰āđƒāļŠāđ‰āļāļģāļŦāļ™āļ”āļ§āđˆāļēāđ„āļŸāļĨāđŒāđƒāļ”āđ€āļ›āđ‡āļ™ **"āđ€āļ­āļāļŠāļēāļĢāļŦāļĨāļąāļ"** āļŦāļĢāļ·āļ­ "āđ€āļ­āļāļŠāļēāļĢāđāļ™āļšāļ›āļĢāļ°āļāļ­āļš" [cite: 5.7] āļžāļĢāđ‰āļ­āļĄāđāļŠāļ”āļ‡ file type icons * **Security Feedback:** āđāļŠāļ”āļ‡ security warnings āļŠāļģāļŦāļĢāļąāļš file types āļ—āļĩāđˆāđ€āļŠāļĩāđˆāļĒāļ‡āļŦāļĢāļ·āļ­ files āļ—āļĩāđˆ fail virus scan * āļŠāđˆāļ‡ (Submit) āļœāđˆāļēāļ™ API āļžāļĢāđ‰āļ­āļĄ feedback āđāļšāļš toast ### **7.3 āļ‚āđ‰āļ­āļāļģāļŦāļ™āļ” Component āđ€āļ‰āļžāļēāļ° (Specific UI Requirements)** * **Dashboard - My Tasks:** āļ•āđ‰āļ­āļ‡āļžāļąāļ’āļ™āļē Component āļ•āļēāļĢāļēāļ‡ "āļ‡āļēāļ™āļ‚āļ­āļ‡āļ‰āļąāļ™" (My Tasks)āļ‹āļķāđˆāļ‡āļ”āļķāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāļ‡āļēāļ™āļ—āļĩāđˆāļœāļđāđ‰āđƒāļŠāđ‰āļĨāđ‡āļ­āļāļ­āļīāļ™āļ­āļĒāļđāđˆāļ•āđ‰āļ­āļ‡āļĢāļąāļšāļœāļīāļ”āļŠāļ­āļš (Main/Action) āļˆāļēāļ v_user_tasks [cite: 5.3] * **Workflow Visualization:** āļ•āđ‰āļ­āļ‡āļžāļąāļ’āļ™āļē Component āļŠāļģāļŦāļĢāļąāļšāđāļŠāļ”āļ‡āļœāļĨ Workflow (āđ‚āļ”āļĒāđ€āļ‰āļžāļēāļ° RFA)āļ—āļĩāđˆāđāļŠāļ”āļ‡āļ‚āļąāđ‰āļ™āļ•āļ­āļ™āļ—āļąāđ‰āļ‡āļŦāļĄāļ”āđ€āļ›āđ‡āļ™āļĨāļģāļ”āļąāļš āđ‚āļ”āļĒāļ‚āļąāđ‰āļ™āļ•āļ­āļ™āļ›āļąāļˆāļˆāļļāļšāļąāļ™ (active) āđ€āļ—āđˆāļēāļ™āļąāđ‰āļ™āļ—āļĩāđˆāļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢāđ„āļ”āđ‰ āđāļĨāļ°āļ‚āļąāđ‰āļ™āļ•āļ­āļ™āļ­āļ·āđˆāļ™āđ€āļ›āđ‡āļ™ disabled [cite: 5.6] āļ•āđ‰āļ­āļ‡āļĄāļĩāļ•āļĢāļĢāļāļ°āļŠāļģāļŦāļĢāļąāļš Admin āđƒāļ™āļāļēāļĢ override āļŦāļĢāļ·āļ­āļĒāđ‰āļ­āļ™āļāļĨāļąāļšāļ‚āļąāđ‰āļ™āļ•āļ­āļ™āđ„āļ”āđ‰ [cite: 5.6] * **Admin Panel:** āļ•āđ‰āļ­āļ‡āļĄāļĩāļŦāļ™āđ‰āļē UI āļŠāļģāļŦāļĢāļąāļš Superadmin/Admin āđ€āļžāļ·āđˆāļ­āļˆāļąāļ”āļāļēāļĢāļ‚āđ‰āļ­āļĄāļđāļĨāļŦāļĨāļąāļ (Master Data [cite: 4.5]), āļāļēāļĢāđ€āļĢāļīāđˆāļĄāļ•āđ‰āļ™āđƒāļŠāđ‰āļ‡āļēāļ™ (Onboarding [cite: 4.6]), āđāļĨāļ° **āļĢāļđāļ›āđāļšāļšāđ€āļĨāļ‚āļ—āļĩāđˆāđ€āļ­āļāļŠāļēāļĢ (Numbering Formats [cite: 3.10])** * **Security Dashboard:** āđāļŠāļ”āļ‡ security metrics āđāļĨāļ° audit logs āļŠāļģāļŦāļĢāļąāļš administrators ## 🧭**8. āđāļ”āļŠāļšāļ­āļĢāđŒāļ”āđāļĨāļ°āļŸāļĩāļ”āļāļīāļˆāļāļĢāļĢāļĄ (Dashboard & Activity Feed)** ### **8.1 āļāļēāļĢāđŒāļ”āļšāļ™āđāļ”āļŠāļšāļ­āļĢāđŒāļ” (Dashboard Cards)** * āđāļŠāļ”āļ‡ Correspondences, RFAs, Circulations, Shop Drawing Revision āļĨāđˆāļēāļŠāļļāļ” * āļĢāļ§āļĄāļŠāļĢāļļāļ› KPI (āđ€āļŠāđˆāļ™ "RFAs āļ—āļĩāđˆāļĢāļ­āļāļēāļĢāļ­āļ™āļļāļĄāļąāļ•āļī", "Shop Drawing āļ—āļĩāđˆāļĢāļ­āļāļēāļĢāļ­āļ™āļļāļĄāļąāļ•āļī") [cite: 5.3] * āļĢāļ§āļĄāļĨāļīāļ‡āļāđŒāļ”āđˆāļ§āļ™āđ„āļ›āļĒāļąāļ‡āđ‚āļĄāļ”āļđāļĨāļ•āđˆāļēāļ‡āđ† * **Security Metrics:** āđāļŠāļ”āļ‡āļˆāļģāļ™āļ§āļ™ files scanned, security incidents, failed login attempts ### **8.2 āļŸāļĩāļ”āļāļīāļˆāļāļĢāļĢāļĄ (Activity Feed)** * āđāļŠāļ”āļ‡āļĢāļēāļĒāļāļēāļĢ v_audit_log_details āļĨāđˆāļēāļŠāļļāļ” (10 āļĢāļēāļĒāļāļēāļĢ) āļ—āļĩāđˆāđ€āļāļĩāđˆāļĒāļ§āļ‚āđ‰āļ­āļ‡āļāļąāļšāļœāļđāđ‰āđƒāļŠāđ‰ * āļĢāļ§āļĄ security-related activities (failed logins, permission changes) ```typescript // āļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡ API response [ { user: 'editor01', action: 'Updated RFA (LCBP3-RFA-001)', time: '2025-11-04T09:30Z' }, { user: 'system', action: 'Virus scan completed - 0 threats found', time: '2025-11-04T09:25Z' } ] ``` ## ðŸ›Ąïļ**9. āļ‚āđ‰āļ­āļāļģāļŦāļ™āļ”āļ—āļĩāđˆāđ„āļĄāđˆāđƒāļŠāđˆāļŸāļąāļ‡āļāđŒāļŠāļąāļ™āļāļēāļĢāļ—āļģāļ‡āļēāļ™ (Non-Functional Requirements)** āļŠāđˆāļ§āļ™āļ™āļĩāđ‰āļŠāļĢāļļāļ›āļ‚āđ‰āļ­āļāļģāļŦāļ™āļ” Non-Functional āļˆāļēāļ requirements.md āđ€āļžāļ·āđˆāļ­āđƒāļŦāđ‰āļ—āļĩāļĄāļžāļąāļ’āļ™āļēāļ—āļēāļ™ * **Audit Log [cite: 6.1]:** āļ—āļļāļāļāļēāļĢāļāļĢāļ°āļ—āļģāļ—āļĩāđˆāļŠāļģāļ„āļąāļ (C/U/D) āļ•āđ‰āļ­āļ‡āļ–āļđāļāļšāļąāļ™āļ—āļķāļāđƒāļ™ audit_logs * **Performance [cite: 6.4]:** āļ•āđ‰āļ­āļ‡āđƒāļŠāđ‰ Caching āļŠāļģāļŦāļĢāļąāļšāļ‚āđ‰āļ­āļĄāļđāļĨāļ—āļĩāđˆāđ€āļĢāļĩāļĒāļāļšāđˆāļ­āļĒ āđāļĨāļ°āđƒāļŠāđ‰ Pagination * **Security [cite: 6.5]:** āļ•āđ‰āļ­āļ‡āļĄāļĩ Rate Limiting āđāļĨāļ°āļˆāļąāļ”āļāļēāļĢ Secret āļœāđˆāļēāļ™ docker-compose.yml (āđ„āļĄāđˆāđƒāļŠāđˆ .env) * **File Security [cite: 3.9.6]:** āļ•āđ‰āļ­āļ‡āļĄāļĩ virus scanning, file type validation, access controls * **Resilience [cite: 6.5.3]:** āļ•āđ‰āļ­āļ‡āļĄāļĩ circuit breaker, retry mechanisms, graceful degradation * **Backup & Recovery [cite: 6.6]:** āļ•āđ‰āļ­āļ‡āļĄāļĩāđāļœāļ™āļŠāļģāļĢāļ­āļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāļ—āļąāđ‰āļ‡ Database (MariaDB) āđāļĨāļ° File Storage (/share/dms-data) āļ­āļĒāđˆāļēāļ‡āļ™āđ‰āļ­āļĒāļ§āļąāļ™āļĨāļ° 1 āļ„āļĢāļąāđ‰āļ‡ * **Notification Strategy [cite: 6.7]:** āļĢāļ°āļšāļšāđāļˆāđ‰āļ‡āđ€āļ•āļ·āļ­āļ™ (Email/Line) āļ•āđ‰āļ­āļ‡āļ–āļđāļ Trigger āđ€āļĄāļ·āđˆāļ­āļĄāļĩāđ€āļ­āļāļŠāļēāļĢāđƒāļŦāļĄāđˆāļŠāđˆāļ‡āļ–āļķāļ‡, āļĄāļĩāļāļēāļĢāļĄāļ­āļšāļŦāļĄāļēāļĒāļ‡āļēāļ™āđƒāļŦāļĄāđˆ (Circulation), āļŦāļĢāļ·āļ­ (āļ—āļēāļ‡āđ€āļĨāļ·āļ­āļ) āđ€āļĄāļ·āđˆāļ­āļ‡āļēāļ™āđ€āļŠāļĢāđ‡āļˆ/āđƒāļāļĨāđ‰āļ–āļķāļ‡āļāļģāļŦāļ™āļ” * **Monitoring [cite: 6.8]:** āļ•āđ‰āļ­āļ‡āļĄāļĩ health checks, metrics collection, alerting ## ✅**10. āļĄāļēāļ•āļĢāļāļēāļ™āļ—āļĩāđˆāļ™āļģāđ„āļ›āđƒāļŠāđ‰āđāļĨāđ‰āļ§ (āļˆāļēāļ SQL v1.4.0) (Implemented Standards (from SQL v1.4.0))** āļŠāđˆāļ§āļ™āļ™āļĩāđ‰āļĒāļ·āļ™āļĒāļąāļ™āļ§āđˆāļēāđāļ™āļ§āļ—āļēāļ‡āļ›āļāļīāļšāļąāļ•āļīāļ—āļĩāđˆāļ”āļĩāļ—āļĩāđˆāļŠāļļāļ”āļ•āđˆāļ­āđ„āļ›āļ™āļĩāđ‰āđ€āļ›āđ‡āļ™āļŠāđˆāļ§āļ™āļŦāļ™āļķāđˆāļ‡āļ‚āļ­āļ‡āļāļēāļĢāļ­āļ­āļāđāļšāļšāļāļēāļ™āļ‚āđ‰āļ­āļĄāļđāļĨāļ­āļĒāļđāđˆāđāļĨāđ‰āļ§ āđāļĨāļ°āļ„āļ§āļĢāļ–āļđāļāļ™āļģāđ„āļ›āđƒāļŠāđ‰āļ›āļĢāļ°āđ‚āļĒāļŠāļ™āđŒ āđ„āļĄāđˆāđƒāļŠāđˆāļŠāļĢāđ‰āļēāļ‡āļ‚āļķāđ‰āļ™āđƒāļŦāļĄāđˆ * ✅ **Soft Delete:** āļ™āļģāđ„āļ›āđƒāļŠāđ‰āđāļĨāđ‰āļ§āļœāđˆāļēāļ™āļ„āļ­āļĨāļąāļĄāļ™āđŒ deleted_at āđƒāļ™āļ•āļēāļĢāļēāļ‡āļŠāļģāļ„āļąāļ (āđ€āļŠāđˆāļ™ correspondences, rfas, project_parties) āļ•āļĢāļĢāļāļ°āļāļēāļĢāļ”āļķāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāļ•āđ‰āļ­āļ‡āļāļĢāļ­āļ‡ deleted_at IS NULL * ✅ **Database Indexes:** āļŠāļ„āļĩāļĄāļēāđ„āļ”āđ‰āļĄāļĩāļāļēāļĢāļ—āļģ index āđ„āļ§āđ‰āļ­āļĒāđˆāļēāļ‡āļŦāļ™āļąāļāļŦāļ™āđˆāļ§āļ‡āļšāļ™ foreign keys āđāļĨāļ°āļ„āļ­āļĨāļąāļĄāļ™āđŒāļ—āļĩāđˆāđƒāļŠāđ‰āļ„āđ‰āļ™āļŦāļēāļšāđˆāļ­āļĒ (āđ€āļŠāđˆāļ™ idx_rr_rfa, idx_cor_project, idx_cr_is_current) āđ€āļžāļ·āđˆāļ­āļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļž * ✅ **āđ‚āļ„āļĢāļ‡āļŠāļĢāđ‰āļēāļ‡ RBAC:** āļĄāļĩāļĢāļ°āļšāļš users, roles, permissions, user_roles, āđāļĨāļ° user_project_roles āļ—āļĩāđˆāļ„āļĢāļ­āļšāļ„āļĨāļļāļĄāļ­āļĒāļđāđˆāđāļĨāđ‰āļ§ * ✅ **Data Seeding:** āļ‚āđ‰āļ­āļĄāļđāļĨ Master (roles, permissions, organization_roles, initial users, project parties) āļ–āļđāļāļĢāļ§āļĄāļ­āļĒāļđāđˆāđƒāļ™āļŠāļ„āļĢāļīāļ›āļ•āđŒāļŠāļ„āļĩāļĄāļēāđāļĨāđ‰āļ§ * ✅ **Application-level Locking:** āđƒāļŠāđ‰ Redis distributed lock āđāļ—āļ™ stored procedure * ✅ **File Security:** Virus scanning, file type validation, access control * ✅ **Resilience Patterns:** Circuit breaker, retry, fallback mechanisms * ✅ **Security Measures:** Input validation, rate limiting, security headers * ✅ **Monitoring:** Health checks, metrics collection, distributed tracing ## **11. āļ•āļąāļ§āļ­āļĒāđˆāļēāļ‡ Implementation Details** * **Permission Hierarchy Logic:** ```typescript @Injectable() export class RbacGuard implements CanActivate { async canActivate(context: ExecutionContext): Promise { const requiredPermission = this.getRequiredPermission(context); const user = this.getUser(context); const resourceContext = this.getResourceContext(context); // Check permissions in hierarchy order return await this.checkPermissions(user, requiredPermission, resourceContext); } private async checkPermissions(user: User, permission: string, context: any) { // 1. Check Global permissions if (await this.hasGlobalPermission(user, permission)) return true; // 2. Check Organization permissions if (await this.hasOrganizationPermission(user, permission, context.organizationId)) return true; // 3. Check Project permissions if (await this.hasProjectPermission(user, permission, context.projectId)) return true; // 4. Check Contract permissions if (await this.hasContractPermission(user, permission, context.contractId)) return true; return false; } } ``` * **CorrespondenceRoutingService:** ```typescript @Injectable() export class CorrespondenceRoutingService { async initiateRouting(correspondenceId: number, templateId: number): Promise { const correspondence = await this.getCorrespondence(correspondenceId); const template = await this.getTemplate(templateId); const steps = await this.getTemplateSteps(templateId); let currentDate = new Date(); for (const step of steps.sort((a, b) => a.sequence - b.sequence)) { const dueDate = this.calculateDueDate(currentDate, step.expected_days); await this.createRoutingInstance({ correspondence_id: correspondenceId, template_id: templateId, sequence: step.sequence, from_organization_id: correspondence.originator_id, to_organization_id: step.to_organization_id, step_purpose: step.step_purpose, status: step.sequence === 1 ? 'SENT' : 'PENDING', due_date: dueDate }); // āļŠāļģāļŦāļĢāļąāļšāļ‚āļąāđ‰āļ™āļ•āļ­āļ™āđāļĢāļ āļŠāđˆāļ‡ notification āļ—āļąāļ™āļ—āļĩ if (step.sequence === 1) { await this.notificationService.sendRoutingNotification( step.to_organization_id, correspondenceId, 'NEW_ROUTING' ); } currentDate = dueDate; } } async processRoutingStep(routingId: number, action: string, comments?: string): Promise { const routing = await this.getRouting(routingId); const nextStep = await this.getNextStep(routing.correspondence_id, routing.sequence); // āļ­āļąāļžāđ€āļ”āļ—āļ‚āļąāđ‰āļ™āļ•āļ­āļ™āļ›āļąāļˆāļˆāļļāļšāļąāļ™ await this.updateRoutingStatus(routingId, action, comments); // āļ–āđ‰āļēāļĄāļĩāļ‚āļąāđ‰āļ™āļ•āļ­āļ™āļ•āđˆāļ­āđ„āļ› āļŠāđˆāļ‡ notification if (nextStep) { await this.advanceToNextStep(nextStep); await this.notificationService.sendRoutingNotification( nextStep.to_organization_id, routing.correspondence_id, 'NEXT_STEP' ); } else { // āļ–āđ‰āļēāđ„āļĄāđˆāļĄāļĩāļ‚āļąāđ‰āļ™āļ•āļ­āļ™āļ•āđˆāļ­āđ„āļ› āđāļŠāļ”āļ‡āļ§āđˆāļēāđ€āļŠāļĢāđ‡āļˆāļŠāļīāđ‰āļ™ await this.completeCorrespondence(routing.correspondence_id); } } } ``` * **Frontend Components āļŠāļģāļŦāļĢāļąāļš Routing:** ```typescript // Routing Template Management export const RoutingTemplateManager: React.FC = () => { // āļˆāļąāļ”āļāļēāļĢāđāļĄāđˆāđāļšāļšāļāļēāļĢāļŠāđˆāļ‡āļ•āđˆāļ­ }; // Routing Visualization export const RoutingWorkflowVisualization: React.FC<{ correspondenceId: number }> = ({ correspondenceId }) => { // āđāļŠāļ”āļ‡āļŠāļ–āļēāļ™āļ°āļāļēāļĢāļŠāđˆāļ‡āļ•āđˆāļ­āđ€āļ›āđ‡āļ™ workflow diagram }; // Pending Routings List export const PendingRoutingsList: React.FC = () => { // āđāļŠāļ”āļ‡āļĢāļēāļĒāļāļēāļĢ routing āļ—āļĩāđˆāļĢāļ­āļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢ }; ``` * **JsonSchemaService Implementation** ```typescript @Injectable() export class JsonSchemaService { private ajv: Ajv; private schemas: Map = new Map(); constructor() { this.ajv = new Ajv({ allErrors: true, strict: false, formats: { email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, date: /^\d{4}-\d{2}-\d{2}$/, datetime: /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/ } }); this.registerPredefinedSchemas(); } async validate(schemaId: string, data: any): Promise { const schema = this.getSchema(schemaId); if (!schema) { throw new Error(`Schema ${schemaId} not found`); } const isValid = this.ajv.validate(schema.schema, data); return { isValid, errors: this.ajv.errors || [], sanitizedData: isValid ? this.sanitizeData(data, schema) : undefined, warnings: this.generateWarnings(data, schema) }; } private sanitizeData(data: any, schema: JsonSchemaDefinition): any { // Remove any properties not defined in schema const sanitized = {}; Object.keys(schema.schema.properties || {}).forEach(key => { if (data.hasOwnProperty(key)) { sanitized[key] = data[key]; } else if (schema.schema.properties[key].default !== undefined) { sanitized[key] = schema.schema.properties[key].default; } }); return sanitized; } } ``` * **Predefined Schemas** ```typescript // schemas/correspondence-rfi.json export const RFI_SCHEMA = { $schema: "http://json-schema.org/draft-07/schema#", type: "object", properties: { metadata: { type: "object", properties: { version: { type: "string", pattern: "^\\d+\\.\\d+$" }, type: { type: "string", const: "RFI" }, rfi_category: { type: "string", enum: ["TECHNICAL", "ADMINISTRATIVE", "SAFETY", "QUALITY"] }, urgency: { type: "string", enum: ["LOW", "NORMAL", "HIGH", "URGENT"], default: "NORMAL" } }, required: ["version", "type"] }, questions: { type: "array", items: { type: "object", properties: { question_id: { type: "integer" }, question_text: { type: "string", maxLength: 1000 }, reference_drawing: { type: "string" }, response_required: { type: "boolean", default: true }, deadline: { type: "string", format: "datetime" } }, required: ["question_id", "question_text"] }, maxItems: 50 } }, required: ["metadata"], additionalProperties: false }; ``` * **DetailsService Integration** ```typescript @Injectable() export class CorrespondenceService { constructor( private readonly detailsService: DetailsService, private readonly jsonSchemaService: JsonSchemaService ) {} async createCorrespondence(dto: CreateCorrespondenceDto) { // Validate details against schema const validation = await this.jsonSchemaService.validate( `correspondence-${dto.correspondence_type_id}`, dto.details ); if (!validation.isValid) { throw new BadRequestException({ message: 'Invalid details structure', errors: validation.errors }); } // Process and sanitize details const processedDetails = await this.detailsService.processDetails( `correspondence-${dto.correspondence_type_id}`, dto.details ); const correspondence = this.correspondenceRepository.create({ ...dto, details: processedDetails.sanitizedData }); return await this.correspondenceRepository.save(correspondence); } } ``` * **Frontend JSON Details Components** ```typescript // React component āļŠāļģāļŦāļĢāļąāļšāļˆāļąāļ”āļāļēāļĢ JSON details export const CorrespondenceDetailsForm: React.FC<{ correspondenceType: string; initialData?: any; onChange: (data: any, isValid: boolean) => void; }> = ({ correspondenceType, initialData, onChange }) => { const [formData, setFormData] = useState(initialData || {}); const [errors, setErrors] = useState([]); const schema = useJsonSchema(correspondenceType); const handleFieldChange = (fieldPath: string, value: any) => { const newData = set(formData, fieldPath, value); setFormData(newData); // Validate against schema const validation = validateAgainstSchema(schema, newData); setErrors(validation.errors); onChange(newData, validation.isValid); }; return (
{schema && ( )}
); }; ``` * **API Endpoints āļŠāļģāļŦāļĢāļąāļš JSON Management** ```typescript @Controller('json-schemas') export class JsonSchemaController { @Get(':schemaId') async getSchema(@Param('schemaId') schemaId: string) { return this.jsonSchemaService.getSchema(schemaId); } @Post('validate/:schemaId') async validateData( @Param('schemaId') schemaId: string, @Body() data: any ) { return this.jsonSchemaService.validate(schemaId, data); } @Get('types/correspondence') async getCorrespondenceSchemas() { return this.jsonSchemaService.getSchemasByType('correspondence'); } } ``` * **Correspondence Revision Details** * Generic Correspondence Details ```typescript { "metadata": { "version": "1.0", "type": "CORRESPONDENCE", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" }, "content": { "subject": "āđ€āļĢāļ·āđˆāļ­āļ‡āļ‚āļ­āļ­āļ™āļļāļāļēāļ•āļ”āļģāđ€āļ™āļīāļ™āļ‡āļēāļ™", "description": "āļĢāļēāļĒāļĨāļ°āđ€āļ­āļĩāļĒāļ”āđ€āļžāļīāđˆāļĄāđ€āļ•āļīāļĄāđ€āļāļĩāđˆāļĒāļ§āļāļąāļšāđ€āļ­āļāļŠāļēāļĢ", "priority": "HIGH", "confidentiality": "INTERNAL", "references": [ { "type": "RELATED", "correspondence_id": 123, "description": "āđ€āļ­āļāļŠāļēāļĢāđ€āļāļĩāđˆāļĒāļ§āļ‚āđ‰āļ­āļ‡" } ] }, "attachments_metadata": { "main_documents": [ { "attachment_id": 456, "filename": "main_document.pdf", "description": "āđ€āļ­āļāļŠāļēāļĢāļŦāļĨāļąāļ" } ], "supporting_documents": [ { "attachment_id": 457, "filename": "supporting_data.xlsx", "description": "āļ‚āđ‰āļ­āļĄāļđāļĨāļ›āļĢāļ°āļāļ­āļš" } ] } } ``` * RFI (Request for Information) Details ```typescript { "metadata": { "version": "1.0", "type": "RFI", "rfi_category": "TECHNICAL", "urgency": "NORMAL" }, "questions": [ { "question_id": 1, "question_text": "āļ•āđ‰āļ­āļ‡āļāļēāļĢāļ—āļĢāļēāļšāļĢāļēāļĒāļĨāļ°āđ€āļ­āļĩāļĒāļ” specification āļ‚āļ­āļ‡ material", "reference_drawing": "DRG-2024-001", "response_required": true, "deadline": "2024-01-25T17:00:00Z" }, { "question_id": 2, "question_text": "āļ‚āļ­āļ—āļĢāļēāļšāļ§āļīāļ˜āļĩāļāļēāļĢāļ•āļīāļ”āļ•āļąāđ‰āļ‡", "response_required": false, "clarification_needed": true } ], "technical_details": { "discipline": "CIVIL", "related_drawings": ["DRG-2024-001", "DRG-2024-002"], "specification_references": ["SPEC-CIV-001", "SPEC-CIV-005"] } } ``` * Transmittal Details ```typescript { "metadata": { "version": "1.0", "type": "TRANSMITTAL", "purpose": "FOR_APPROVAL", "transmittal_category": "SHOP_DRAWING" }, "items": [ { "item_number": 1, "correspondence_id": 123, "description": "Shop Drawing - Structural Plan", "revision": "A", "quantity": 3, "remarks": "āļŠāļģāļŦāļĢāļąāļšāļ•āļĢāļ§āļˆāļŠāļ­āļšāđāļĨāļ°āļ­āļ™āļļāļĄāļąāļ•āļī" }, { "item_number": 2, "correspondence_id": 124, "description": "Calculation Sheet", "revision": "0", "quantity": 2, "remarks": "āļ›āļĢāļ°āļāļ­āļšāļāļēāļĢāļžāļīāļˆāļēāļĢāļ“āļē" } ], "delivery_info": { "method": "ELECTRONIC", "carrier": null, "tracking_number": null, "expected_delivery": "2024-01-16T09:00:00Z" } } ``` * **Routing Details** * Routing Template Details ```typescript { "metadata": { "version": "1.0", "type": "ROUTING_TEMPLATE", "scope": "PROJECT_SPECIFIC", "applicable_projects": ["LCBP3", "LCBP3-SUB1"], "created_by": 101, "last_modified": "2024-01-10T14:20:00Z" }, "workflow_rules": { "allow_parallel_processing": false, "allow_step_skipping": true, "require_approval_before_next": true, "escalation_rules": { "overdue_action": "NOTIFY_SUPERVISOR", "overdue_days": 3, "escalation_recipients": [201, 202] } }, "step_configurations": [ { "sequence": 1, "conditional_logic": { "condition": "DOCUMENT_TYPE == 'RFA'", "action": "AUTO_ASSIGN_TO_PROJECT_MANAGER" }, "auto_actions": { "on_receive": "CALCULATE_DUE_DATE", "on_approve": "NOTIFY_NEXT_STEP", "on_reject": "RETURN_TO_ORIGINATOR" } } ] } ``` * Routing Instance Details ```typescript { "metadata": { "version": "1.0", "type": "ROUTING_INSTANCE", "template_id": 15, "initiated_by": 101, "started_at": "2024-01-15T10:30:00Z" }, "current_status": { "current_step": 2, "overall_progress": 50, "estimated_completion": "2024-01-22T17:00:00Z", "blocked_reason": null }, "step_history": [ { "step_sequence": 1, "organization_id": 301, "assigned_to": 201, "assigned_at": "2024-01-15T10:30:00Z", "status": "COMPLETED", "completed_at": "2024-01-16T09:15:00Z", "action_taken": "APPROVED", "comments": "āļ•āļĢāļ§āļˆāļŠāļ­āļšāđāļĨāđ‰āļ§āđ€āļŦāđ‡āļ™āļ„āļ§āļĢāļ”āļģāđ€āļ™āļīāļ™āļāļēāļĢāļ•āđˆāļ­", "processing_time_hours": 22.75, "attachments_added": [501, 502] }, { "step_sequence": 2, "organization_id": 302, "assigned_to": null, "assigned_at": "2024-01-16T09:15:00Z", "status": "IN_PROGRESS", "due_date": "2024-01-19T17:00:00Z", "time_remaining_hours": 72, "reminders_sent": 0 } ], "performance_metrics": { "total_processing_time": 22.75, "average_step_time": 22.75, "steps_completed": 1, "steps_pending": 2, "on_track": true } } ``` * Routing Step Action Details ```typescript { "metadata": { "version": "1.0", "type": "ROUTING_ACTION", "action_type": "APPROVE_WITH_COMMENTS", "performed_by": 201, "performed_at": "2024-01-16T09:15:00Z" }, "action_details": { "decision": "APPROVED", "approval_code": "1A", "conditions": [ { "condition_id": 1, "description": "āļ•āđ‰āļ­āļ‡āļŠāđˆāļ‡āđāļšāļšāđāļāđ‰āđ„āļ‚āļāđˆāļ­āļ™āđ€āļĢāļīāđˆāļĄāļ‡āļēāļ™", "deadline": "2024-01-20T17:00:00Z" } ], "remarks": "āđāļšāļšāđāļ›āļĨāļ™āļ–āļđāļāļ•āđ‰āļ­āļ‡āļ•āļēāļĄāļ‚āđ‰āļ­āļāļģāļŦāļ™āļ” āđāļ•āđˆāļ•āđ‰āļ­āļ‡āđāļāđ‰āđ„āļ‚āļĢāļēāļĒāļĨāļ°āđ€āļ­āļĩāļĒāļ”āļāļēāļĢāļ•āļīāļ”āļ•āļąāđ‰āļ‡" }, "technical_review": { "compliance_status": "COMPLIANT", "exceptions": [ { "item": "Material Specification", "issue": "āđ„āļĄāđˆāđ„āļ”āđ‰āļĢāļ°āļšāļļ brand āļ—āļĩāđˆāļ•āđ‰āļ­āļ‡āļāļēāļĢ", "severity": "LOW", "recommendation": "āđ€āļžāļīāđˆāļĄāļĢāļēāļĒāļĨāļ°āđ€āļ­āļĩāļĒāļ” brand āļ—āļĩāđˆāļ­āļ™āļļāļāļēāļ•" } ], "reviewer_comments": "āđ‚āļ”āļĒāļĢāļ§āļĄāđ€āļ›āđ‡āļ™āđ„āļ›āļ•āļēāļĄāļ‚āđ‰āļ­āļāļģāļŦāļ™āļ”āļ‚āļ­āļ‡āđ‚āļ„āļĢāļ‡āļāļēāļĢ" }, "attachments": { "review_documents": [503], "reference_standards": ["ASTM-A36", "JIS-G3101"] }, "next_steps": { "auto_assign_to": 202, "required_actions": ["UPDATE_DRAWING", "RESUBMIT"], "deadline_extension_days": 5 } } ``` * **Audit & Security Details** * Audit Log Details ```typescript { "metadata": { "version": "1.0", "type": "AUDIT_LOG", "security_level": "SENSITIVE" }, "action_context": { "ip_address": "192.168.1.100", "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "session_id": "sess_abc123def456", "request_id": "req_789ghi012jkl" }, "changes_made": { "before": { "status": "DRAFT", "title": "āļĢāđˆāļēāļ‡āđ€āļ­āļāļŠāļēāļĢāļ‚āļ­āļ­āļ™āļļāļĄāļąāļ•āļī" }, "after": { "status": "SUBMITTED", "title": "āđ€āļ­āļāļŠāļēāļĢāļ‚āļ­āļ­āļ™āļļāļĄāļąāļ•āļīāđāļšāļšāļāđˆāļ­āļŠāļĢāđ‰āļēāļ‡" }, "fields_modified": ["status", "title"] }, "security_metadata": { "authentication_method": "JWT", "permissions_checked": ["correspondence.update", "workflow.submit"], "risk_level": "LOW", "compliance_checked": true } } ``` * File Upload Security Details ```typescript { "metadata": { "version": "1.0", "type": "FILE_SECURITY_SCAN", "scan_timestamp": "2024-01-15T10:35:22Z" }, "scan_results": { "virus_scan": { "engine": "ClamAV", "version": "1.0.1", "status": "CLEAN", "signatures": "20240115001", "scan_duration_ms": 245 }, "file_validation": { "expected_type": "application/pdf", "detected_type": "application/pdf", "file_size_bytes": 2547896, "checksum_sha256": "a1b2c3d4e5f6789012345678901234567890123456789012345678901234", "validation_passed": true }, "security_assessment": { "risk_level": "LOW", "threats_detected": [], "recommendations": ["None"] } }, "access_control": { "uploaded_by": 101, "organization_id": 301, "allowed_roles": ["VIEWER", "EDITOR", "DOCUMENT_CONTROL"], "download_count": 0, "last_accessed": null } } ``` * **Reporting & Analytics Details** * Correspondence Statistics ```typescript { "metadata": { "version": "1.0", "type": "CORRESPONDENCE_STATS", "period": "MONTHLY", "generated_at": "2024-01-31T23:59:59Z" }, "summary": { "total_correspondences": 156, "new_this_period": 45, "closed_this_period": 38, "outstanding": 67 }, "by_type": { "RFA": { "count": 89, "approval_rate": 72.5, "average_processing_days": 12.3 }, "RFI": { "count": 45, "response_rate": 95.6, "average_response_hours": 48.2 }, "LETTER": { "count": 22, "action_required": 15, "pending_actions": 8 } }, "performance_metrics": { "on_time_completion_rate": 78.4, "average_cycle_time_days": 8.7, "escalation_count": 12, "sla_violations": 5 } } ``` * **Usage Guidelines** * Schema Validation Rules ```typescript { "validation_rules": { "required_fields": ["metadata.version", "metadata.type"], "version_control": { "current_version": "1.0", "backward_compatible": true }, "size_limits": { "max_json_size_kb": 50, "max_array_elements": 1000 }, "data_types": { "timestamps": "ISO8601", "numbers": "integer_or_float", "enums": "predefined_values" } } } ``` * Example TypeScript Interfaces ```typescript interface CorrespondenceDetails { metadata: { version: string; type: string; created_at: string; updated_at: string; }; content: { subject: string; description?: string; priority: 'LOW' | 'NORMAL' | 'HIGH' | 'URGENT'; confidentiality: 'PUBLIC' | 'INTERNAL' | 'CONFIDENTIAL'; references?: Array<{ type: string; correspondence_id: number; description: string; }>; }; } interface RoutingInstanceDetails { metadata: { version: string; type: string; template_id: number; initiated_by: number; started_at: string; }; current_status: { current_step: number; overall_progress: number; estimated_completion: string; blocked_reason: string | null; }; step_history: Array<{ step_sequence: number; organization_id: number; assigned_to: number | null; assigned_at: string; status: string; completed_at?: string; action_taken?: string; comments?: string; processing_time_hours?: number; }>; } ``` ## ðŸ§Đ**12. āļāļēāļĢāļ›āļĢāļąāļšāļ›āļĢāļļāļ‡āļ—āļĩāđˆāđāļ™āļ°āļ™āļģ (āļŠāļģāļŦāļĢāļąāļšāļ­āļ™āļēāļ„āļ•) (Recommended Enhancements (Future))** * ✅ āļŠāļĢāđ‰āļēāļ‡ Background job (āđ‚āļ”āļĒāđƒāļŠāđ‰ **n8n** āđ€āļžāļ·āđˆāļ­āđ€āļŠāļ·āđˆāļ­āļĄāļ•āđˆāļ­āļāļąāļš **Line** [cite: 2.7] āđāļĨāļ°/āļŦāļĢāļ·āļ­āđƒāļŠāđ‰āļŠāļģāļŦāļĢāļąāļšāļāļēāļĢāđāļˆāđ‰āļ‡āđ€āļ•āļ·āļ­āļ™ RFA āļ—āļĩāđˆāđƒāļāļĨāđ‰āļ–āļķāļ‡āļāļģāļŦāļ™āļ” due_date [cite: 6.7]) * ✅ āđ€āļžāļīāđˆāļĄ job āļĨāđ‰āļēāļ‡āļ‚āđ‰āļ­āļĄāļđāļĨāđ€āļ›āđ‡āļ™āļĢāļ°āļĒāļ°āļŠāļģāļŦāļĢāļąāļš attachments āļ—āļĩāđˆāđ„āļĄāđˆāļ–āļđāļāđ€āļŠāļ·āđˆāļ­āļĄāđ‚āļĒāļ‡āļāļąāļš Entity āđƒāļ”āđ† āđ€āļĨāļĒ (āđ„āļŸāļĨāđŒāļāļģāļžāļĢāđ‰āļē) * 🔄 **AI-Powered Document Classification:** āđƒāļŠāđ‰ machine learning āļŠāļģāļŦāļĢāļąāļš automatic document categorization * 🔄 **Advanced Analytics:** Predictive analytics āļŠāļģāļŦāļĢāļąāļš workflow optimization * 🔄 **Mobile App:** Native mobile application āļŠāļģāļŦāļĢāļąāļš field workers * 🔄 **Blockchain Integration:** āļŠāļģāļŦāļĢāļąāļš document integrity verification āļ—āļĩāđˆāļ•āđ‰āļ­āļ‡āļāļēāļĢāļ„āļ§āļēāļĄāļ›āļĨāļ­āļ”āļ āļąāļĒāļŠāļđāļ‡āļŠāļļāļ” --- ## 📋**13 Summary of Key Changes from Previous Version** ### **Security Enhancements:** 1. **File Upload Security** - Virus scanning, file type validation, access controls 2. **Input Validation** - OWASP Top 10 protection, XSS/CSRF prevention 3. **Rate Limiting** - Comprehensive rate limiting strategy 4. **Secrets Management** - Secure handling of sensitive configuration ### **Architecture Improvements:** 1. **Document Numbering** - Changed from Stored Procedure to Application-level Locking 2. **Resilience Patterns** - Circuit breaker, retry mechanisms, fallback strategies 3. **Monitoring & Observability** - Health checks, metrics, distributed tracing 4. **Caching Strategy** - Comprehensive caching with proper invalidation ### **Performance Targets:** 1. **API Response Time** - < 200ms (90th percentile) 2. **Search Performance** - < 500ms 3. **File Upload** - < 30 seconds for 50MB files 4. **Cache Hit Ratio** - > 80% ### **Operational Excellence:** 1. **Disaster Recovery** - RTO < 4 hours, RPO < 1 hour 2. **Backup Procedures** - Comprehensive backup and restoration 3. **Security Testing** - Penetration testing and security audits 4. **Performance Testing** - Load testing with realistic workloads āđ€āļ­āļāļŠāļēāļĢāļ™āļĩāđ‰āļŠāļ°āļ—āđ‰āļ­āļ™āļ–āļķāļ‡āļ„āļ§āļēāļĄāļĄāļļāđˆāļ‡āļĄāļąāđˆāļ™āđƒāļ™āļāļēāļĢāļŠāļĢāđ‰āļēāļ‡āļĢāļ°āļšāļšāļ—āļĩāđˆāļĄāļĩāļ„āļ§āļēāļĄāļ›āļĨāļ­āļ”āļ āļąāļĒ, āļĄāļĩāļ„āļ§āļēāļĄāļ—āļ™āļ—āļēāļ™, āđāļĨāļ°āļĄāļĩāļ›āļĢāļ°āļŠāļīāļ—āļ˜āļīāļ āļēāļžāļŠāļđāļ‡ āļžāļĢāđ‰āļ­āļĄāļĢāļ­āļ‡āļĢāļąāļšāļāļēāļĢāđ€āļ•āļīāļšāđ‚āļ•āđƒāļ™āļ­āļ™āļēāļ„āļ•āđāļĨāļ°āļ„āļ§āļēāļĄāļ•āđ‰āļ­āļ‡āļāļēāļĢāļ—āļēāļ‡āļ˜āļļāļĢāļāļīāļˆāļ—āļĩāđˆāđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡āđ„āļ› **āļŦāļĄāļēāļĒāđ€āļŦāļ•āļļ:** āđāļ™āļ§āļ—āļēāļ‡āļ™āļĩāđ‰āļˆāļ°āļ–āļđāļāļ—āļšāļ—āļ§āļ™āđāļĨāļ°āļ›āļĢāļąāļšāļ›āļĢāļļāļ‡āđ€āļ›āđ‡āļ™āļĢāļ°āļĒāļ°āļ•āļēāļĄ feedback āļˆāļēāļāļ—āļĩāļĄāļžāļąāļ’āļ™āļēāđāļĨāļ°āļ„āļ§āļēāļĄāļ•āđ‰āļ­āļ‡āļāļēāļĢāļ—āļēāļ‡āļ˜āļļāļĢāļāļīāļˆāļ—āļĩāđˆāđ€āļ›āļĨāļĩāđˆāļĒāļ™āđāļ›āļĨāļ‡āđ„āļ›