# ๐Ÿ› ๏ธ Development Guide This guide covers the development workflow, coding standards, and best practices for the Smart Parking Finder application. ## ๐Ÿ“‹ Table of Contents 1. [Development Setup](#development-setup) 2. [Project Structure](#project-structure) 3. [Development Workflow](#development-workflow) 4. [Coding Standards](#coding-standards) 5. [Testing Strategy](#testing-strategy) 6. [Debugging](#debugging) 7. [Performance Guidelines](#performance-guidelines) 8. [Contributing](#contributing) ## ๐Ÿš€ Development Setup ### Prerequisites - Node.js 18+ and npm - Docker and Docker Compose - Git - VS Code (recommended) ### Initial Setup ```bash # 1. Clone repository git clone cd smart-parking-finder # 2. Run automated setup ./setup.sh # 3. Start development environment docker-compose up -d # 4. Install dependencies cd frontend && npm install cd ../backend && npm install # 5. Start development servers npm run dev:all # Starts both frontend and backend ``` ### Environment Configuration ```bash # .env.development NODE_ENV=development # Database DATABASE_URL=postgresql://parking_user:parking_pass@localhost:5432/parking_db # Redis REDIS_URL=redis://localhost:6379 # Valhalla VALHALLA_URL=http://localhost:8002 # Development DEBUG=true LOG_LEVEL=debug HOT_RELOAD=true ``` ## ๐Ÿ“ Project Structure ``` smart-parking-finder/ โ”œโ”€โ”€ frontend/ # Next.js frontend application โ”‚ โ”œโ”€โ”€ src/ โ”‚ โ”‚ โ”œโ”€โ”€ app/ # App router pages โ”‚ โ”‚ โ”œโ”€โ”€ components/ # Reusable UI components โ”‚ โ”‚ โ”œโ”€โ”€ hooks/ # Custom React hooks โ”‚ โ”‚ โ”œโ”€โ”€ services/ # API service layers โ”‚ โ”‚ โ”œโ”€โ”€ types/ # TypeScript type definitions โ”‚ โ”‚ โ””โ”€โ”€ utils/ # Utility functions โ”‚ โ”œโ”€โ”€ public/ # Static assets โ”‚ โ””โ”€โ”€ tests/ # Frontend tests โ”œโ”€โ”€ backend/ # NestJS backend application โ”‚ โ”œโ”€โ”€ src/ โ”‚ โ”‚ โ”œโ”€โ”€ modules/ # Feature modules โ”‚ โ”‚ โ”œโ”€โ”€ common/ # Shared utilities โ”‚ โ”‚ โ”œโ”€โ”€ config/ # Configuration files โ”‚ โ”‚ โ””โ”€โ”€ database/ # Database related files โ”‚ โ””โ”€โ”€ tests/ # Backend tests โ”œโ”€โ”€ valhalla/ # Routing engine setup โ”œโ”€โ”€ scripts/ # Development scripts โ””โ”€โ”€ docs/ # Documentation ``` ### Frontend Architecture ``` frontend/src/ โ”œโ”€โ”€ app/ # Next.js 14 App Router โ”‚ โ”œโ”€โ”€ (dashboard)/ # Route groups โ”‚ โ”œโ”€โ”€ api/ # API routes โ”‚ โ”œโ”€โ”€ globals.css # Global styles โ”‚ โ”œโ”€โ”€ layout.tsx # Root layout โ”‚ โ””โ”€โ”€ page.tsx # Home page โ”œโ”€โ”€ components/ # UI Components โ”‚ โ”œโ”€โ”€ ui/ # Base UI components โ”‚ โ”œโ”€โ”€ forms/ # Form components โ”‚ โ”œโ”€โ”€ map/ # Map-related components โ”‚ โ””โ”€โ”€ parking/ # Parking-specific components โ”œโ”€โ”€ hooks/ # Custom hooks โ”‚ โ”œโ”€โ”€ useGeolocation.ts โ”‚ โ”œโ”€โ”€ useParking.ts โ”‚ โ””โ”€โ”€ useRouting.ts โ”œโ”€โ”€ services/ # API services โ”‚ โ”œโ”€โ”€ api.ts # Base API client โ”‚ โ”œโ”€โ”€ parkingService.ts โ”‚ โ””โ”€โ”€ routingService.ts โ””โ”€โ”€ types/ # TypeScript definitions โ”œโ”€โ”€ parking.ts โ”œโ”€โ”€ routing.ts โ””โ”€โ”€ user.ts ``` ### Backend Architecture ``` backend/src/ โ”œโ”€โ”€ modules/ # Feature modules โ”‚ โ”œโ”€โ”€ auth/ # Authentication โ”‚ โ”œโ”€โ”€ parking/ # Parking management โ”‚ โ”œโ”€โ”€ routing/ # Route calculation โ”‚ โ””โ”€โ”€ users/ # User management โ”œโ”€โ”€ common/ # Shared code โ”‚ โ”œโ”€โ”€ decorators/ # Custom decorators โ”‚ โ”œโ”€โ”€ filters/ # Exception filters โ”‚ โ”œโ”€โ”€ guards/ # Auth guards โ”‚ โ””โ”€โ”€ pipes/ # Validation pipes โ”œโ”€โ”€ config/ # Configuration โ”‚ โ”œโ”€โ”€ database.config.ts โ”‚ โ”œโ”€โ”€ redis.config.ts โ”‚ โ””โ”€โ”€ app.config.ts โ””โ”€โ”€ database/ # Database files โ”œโ”€โ”€ migrations/ # Database migrations โ”œโ”€โ”€ seeds/ # Seed data โ””โ”€โ”€ entities/ # TypeORM entities ``` ## ๐Ÿ”„ Development Workflow ### Git Workflow ```bash # 1. Create feature branch git checkout -b feature/parking-search-improvements # 2. Make changes with atomic commits git add . git commit -m "feat(parking): add distance-based search filtering" # 3. Push and create PR git push origin feature/parking-search-improvements ``` ### Commit Message Convention ``` type(scope): description Types: - feat: New feature - fix: Bug fix - docs: Documentation changes - style: Code style changes - refactor: Code refactoring - test: Adding tests - chore: Maintenance tasks Examples: feat(map): add real-time parking availability indicators fix(routing): resolve incorrect distance calculations docs(api): update parking endpoint documentation ``` ### Development Scripts ```json { "scripts": { "dev": "next dev", "dev:backend": "cd backend && npm run start:dev", "dev:all": "concurrently \"npm run dev\" \"npm run dev:backend\"", "build": "next build", "test": "jest", "test:watch": "jest --watch", "test:coverage": "jest --coverage", "lint": "eslint . --ext .ts,.tsx", "lint:fix": "eslint . --ext .ts,.tsx --fix", "type-check": "tsc --noEmit" } } ``` ## ๐Ÿ“ Coding Standards ### TypeScript Configuration ```json // tsconfig.json { "compilerOptions": { "target": "ES2022", "lib": ["dom", "dom.iterable", "es6"], "allowJs": true, "skipLibCheck": true, "strict": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true, "plugins": [ { "name": "next" } ], "baseUrl": ".", "paths": { "@/*": ["./src/*"], "@/components/*": ["./src/components/*"], "@/services/*": ["./src/services/*"], "@/types/*": ["./src/types/*"] } } } ``` ### ESLint Configuration ```json // .eslintrc.json { "extends": [ "next/core-web-vitals", "@typescript-eslint/recommended", "prettier" ], "rules": { "@typescript-eslint/no-unused-vars": "error", "@typescript-eslint/explicit-function-return-type": "warn", "prefer-const": "error", "no-var": "error", "react-hooks/exhaustive-deps": "warn" } } ``` ### Code Style Guidelines #### Frontend Components ```typescript // โœ… Good: Functional component with proper typing interface ParkingListProps { parkingLots: ParkingLot[]; onSelect: (lot: ParkingLot) => void; loading?: boolean; } export const ParkingList: React.FC = ({ parkingLots, onSelect, loading = false }) => { const [selectedId, setSelectedId] = useState(null); const handleSelect = useCallback((lot: ParkingLot) => { setSelectedId(lot.id); onSelect(lot); }, [onSelect]); if (loading) { return ; } return (
{parkingLots.map((lot) => ( handleSelect(lot)} /> ))}
); }; ``` #### Backend Services ```typescript // โœ… Good: Service with proper error handling and typing @Injectable() export class ParkingService { constructor( @InjectRepository(ParkingLot) private readonly parkingRepository: Repository, private readonly cacheService: CacheService, private readonly logger: Logger ) {} async findNearbyParking( dto: FindNearbyParkingDto ): Promise { try { const cacheKey = `nearby:${dto.latitude}:${dto.longitude}:${dto.radius}`; // Check cache first const cached = await this.cacheService.get(cacheKey); if (cached) { return cached; } // Query database with spatial index const lots = await this.parkingRepository .createQueryBuilder('lot') .where( 'ST_DWithin(lot.location::geography, ST_Point(:lng, :lat)::geography, :radius)', { lng: dto.longitude, lat: dto.latitude, radius: dto.radius } ) .andWhere('lot.isActive = :isActive', { isActive: true }) .orderBy( 'ST_Distance(lot.location::geography, ST_Point(:lng, :lat)::geography)', 'ASC' ) .limit(dto.limit || 20) .getMany(); // Cache results await this.cacheService.set(cacheKey, lots, 300); // 5 minutes return lots; } catch (error) { this.logger.error('Failed to find nearby parking', error); throw new InternalServerErrorException('Failed to find nearby parking'); } } } ``` ## ๐Ÿงช Testing Strategy ### Test Structure ``` tests/ โ”œโ”€โ”€ unit/ # Unit tests โ”œโ”€โ”€ integration/ # Integration tests โ”œโ”€โ”€ e2e/ # End-to-end tests โ””โ”€โ”€ fixtures/ # Test data ``` ### Frontend Testing ```typescript // components/ParkingList.test.tsx import { render, screen, fireEvent } from '@testing-library/react'; import { ParkingList } from './ParkingList'; import { mockParkingLots } from '../../../tests/fixtures/parking'; describe('ParkingList', () => { const mockOnSelect = jest.fn(); beforeEach(() => { mockOnSelect.mockClear(); }); it('renders parking lots correctly', () => { render( ); expect(screen.getByText('Central Mall Parking')).toBeInTheDocument(); expect(screen.getByText('$5/hour')).toBeInTheDocument(); }); it('calls onSelect when parking lot is clicked', () => { render( ); fireEvent.click(screen.getByText('Central Mall Parking')); expect(mockOnSelect).toHaveBeenCalledWith(mockParkingLots[0]); }); it('shows loading spinner when loading', () => { render( ); expect(screen.getByRole('status')).toBeInTheDocument(); }); }); ``` ### Backend Testing ```typescript // parking/parking.service.spec.ts import { Test, TestingModule } from '@nestjs/testing'; import { getRepositoryToken } from '@nestjs/typeorm'; import { ParkingService } from './parking.service'; import { ParkingLot } from './entities/parking-lot.entity'; import { mockRepository } from '../../tests/mocks/repository.mock'; describe('ParkingService', () => { let service: ParkingService; let repository: any; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ ParkingService, { provide: getRepositoryToken(ParkingLot), useValue: mockRepository, }, ], }).compile(); service = module.get(ParkingService); repository = module.get(getRepositoryToken(ParkingLot)); }); describe('findNearbyParking', () => { it('should return nearby parking lots', async () => { const mockLots = [/* mock data */]; repository.createQueryBuilder().getMany.mockResolvedValue(mockLots); const result = await service.findNearbyParking({ latitude: 1.3521, longitude: 103.8198, radius: 1000, }); expect(result).toEqual(mockLots); expect(repository.createQueryBuilder).toHaveBeenCalled(); }); }); }); ``` ### Integration Testing ```typescript // parking/parking.controller.integration.spec.ts import { Test } from '@nestjs/testing'; import { INestApplication } from '@nestjs/common'; import * as request from 'supertest'; import { AppModule } from '../app.module'; describe('ParkingController (Integration)', () => { let app: INestApplication; beforeAll(async () => { const moduleRef = await Test.createTestingModule({ imports: [AppModule], }).compile(); app = moduleRef.createNestApplication(); await app.init(); }); it('/parking/nearby (POST)', () => { return request(app.getHttpServer()) .post('/parking/nearby') .send({ latitude: 1.3521, longitude: 103.8198, radius: 1000, }) .expect(200) .expect((res) => { expect(res.body).toHaveProperty('data'); expect(Array.isArray(res.body.data)).toBe(true); }); }); afterAll(async () => { await app.close(); }); }); ``` ## ๐Ÿ› Debugging ### Frontend Debugging ```typescript // Development debugging utilities export const debugLog = (message: string, data?: any): void => { if (process.env.NODE_ENV === 'development') { console.log(`[DEBUG] ${message}`, data); } }; // React Developer Tools // Component debugging export const ParkingDebugger: React.FC = () => { const [parkingLots, setParkingLots] = useLocalStorage('debug:parking', []); useEffect(() => { // Log component updates debugLog('ParkingDebugger mounted'); return () => { debugLog('ParkingDebugger unmounted'); }; }, []); return (

Parking Debug Info

{JSON.stringify(parkingLots, null, 2)}
); }; ``` ### Backend Debugging ```typescript // Logger configuration import { Logger } from '@nestjs/common'; @Injectable() export class DebugService { private readonly logger = new Logger(DebugService.name); logRequest(req: Request, res: Response, next: NextFunction): void { const { method, originalUrl, body, query } = req; this.logger.debug(`${method} ${originalUrl}`, { body, query, timestamp: new Date().toISOString(), }); next(); } logDatabaseQuery(query: string, parameters?: any[]): void { this.logger.debug('Database Query', { query, parameters, timestamp: new Date().toISOString(), }); } } ``` ### VS Code Debug Configuration ```json // .vscode/launch.json { "version": "0.2.0", "configurations": [ { "name": "Debug Frontend", "type": "node", "request": "launch", "cwd": "${workspaceFolder}/frontend", "runtimeExecutable": "npm", "runtimeArgs": ["run", "dev"] }, { "name": "Debug Backend", "type": "node", "request": "launch", "cwd": "${workspaceFolder}/backend", "program": "${workspaceFolder}/backend/dist/main.js", "env": { "NODE_ENV": "development" }, "console": "integratedTerminal", "restart": true, "protocol": "inspector" } ] } ``` ## โšก Performance Guidelines ### Frontend Performance ```typescript // Use React.memo for expensive components export const ParkingMap = React.memo(({ parkingLots, onMarkerClick }) => { // Component implementation }); // Optimize re-renders with useMemo const filteredLots = useMemo(() => { return parkingLots.filter(lot => lot.availableSpaces > 0 && lot.distance <= maxDistance ); }, [parkingLots, maxDistance]); // Virtual scrolling for large lists import { FixedSizeList as List } from 'react-window'; const VirtualizedParkingList: React.FC = ({ items }) => ( {ParkingRow} ); ``` ### Backend Performance ```typescript // Database query optimization @Injectable() export class OptimizedParkingService { // Use spatial indexes async findNearbyOptimized(dto: FindNearbyParkingDto): Promise { return this.parkingRepository.query(` SELECT * FROM parking_lots WHERE ST_DWithin( location::geography, ST_Point($1, $2)::geography, $3 ) AND available_spaces > 0 ORDER BY location <-> ST_Point($1, $2) LIMIT $4 `, [dto.longitude, dto.latitude, dto.radius, dto.limit]); } // Implement caching @Cacheable('parking:nearby', 300) // 5 minutes async findNearbyCached(dto: FindNearbyParkingDto): Promise { return this.findNearbyOptimized(dto); } } // Connection pooling export const databaseConfig: TypeOrmModuleOptions = { type: 'postgres', url: process.env.DATABASE_URL, extra: { max: 20, // maximum number of connections connectionTimeoutMillis: 2000, idleTimeoutMillis: 30000, }, }; ``` ## ๐Ÿค Contributing ### Pull Request Process 1. **Fork and Clone** ```bash git clone https://github.com/your-username/smart-parking-finder.git cd smart-parking-finder git remote add upstream https://github.com/original/smart-parking-finder.git ``` 2. **Create Feature Branch** ```bash git checkout -b feature/your-feature-name ``` 3. **Development** - Follow coding standards - Write tests for new features - Update documentation 4. **Submit PR** - Ensure all tests pass - Update CHANGELOG.md - Provide clear description ### Code Review Guidelines - **Code Quality**: Follows TypeScript best practices - **Testing**: Adequate test coverage (>80%) - **Performance**: No performance regressions - **Documentation**: Updated documentation - **Security**: No security vulnerabilities ### Issue Templates ```markdown ## Bug Report **Describe the bug** A clear description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** What you expected to happen. **Screenshots** If applicable, add screenshots. **Environment:** - OS: [e.g. iOS] - Browser [e.g. chrome, safari] - Version [e.g. 22] ``` --- For more information, see the [README](../README.md) and [Technical Specification](../TECHNICAL_SPECIFICATION.md).