|
1 | | -# Localess Project Guidelines |
| 1 | +You are an expert in TypeScript, Angular, and scalable web application development. You write maintainable, performant, and accessible code following Angular and TypeScript best practices. |
2 | 2 |
|
3 | | -This document provides essential information for developers working on the Localess project. |
| 3 | +## TypeScript Best Practices |
4 | 4 |
|
5 | | -## Build/Configuration Instructions |
| 5 | +- Use strict type checking |
| 6 | +- Prefer type inference when the type is obvious |
| 7 | +- Avoid the `any` type; use `unknown` when type is uncertain |
6 | 8 |
|
7 | | -### Project Setup |
| 9 | +## Angular Best Practices |
8 | 10 |
|
9 | | -1. **Node.js Version**: This project requires Node.js version 20 as specified in both the root and functions package.json files. |
| 11 | +- Always use standalone components over NgModules |
| 12 | +- Must NOT set `standalone: true` inside Angular decorators. It's the default. |
| 13 | +- Use signals for state management |
| 14 | +- Implement lazy loading for feature routes |
| 15 | +- Do NOT use the `@HostBinding` and `@HostListener` decorators. Put host bindings inside the `host` object of the `@Component` or `@Directive` decorator instead |
| 16 | +- Use `NgOptimizedImage` for all static images. |
| 17 | + - `NgOptimizedImage` does not work for inline base64 images. |
10 | 18 |
|
11 | | -2. **Install Dependencies**: |
12 | | - ```bash |
13 | | - # Install root project dependencies |
14 | | - npm install |
15 | | - |
16 | | - # Install Firebase Functions dependencies |
17 | | - cd functions |
18 | | - npm install |
19 | | - ``` |
| 19 | +## Components |
20 | 20 |
|
21 | | -### Building the Project |
| 21 | +- Keep components small and focused on a single responsibility |
| 22 | +- Use `input()` and `output()` functions instead of decorators |
| 23 | +- Use `computed()` for derived state |
| 24 | +- Set `changeDetection: ChangeDetectionStrategy.OnPush` in `@Component` decorator |
| 25 | +- Prefer inline templates for small components |
| 26 | +- Prefer Reactive forms instead of Template-driven ones |
| 27 | +- Do NOT use `ngClass`, use `class` bindings instead |
| 28 | +- Do NOT use `ngStyle`, use `style` bindings instead |
22 | 29 |
|
23 | | -The project consists of an Angular frontend and Firebase Functions backend: |
| 30 | +## State Management |
24 | 31 |
|
25 | | -#### Frontend (Angular) |
| 32 | +- Use signals for local component state |
| 33 | +- Use `computed()` for derived state |
| 34 | +- Keep state transformations pure and predictable |
| 35 | +- Do NOT use `mutate` on signals, use `update` or `set` instead |
26 | 36 |
|
27 | | -```bash |
28 | | -# Development build |
29 | | -npm run build |
| 37 | +## Templates |
30 | 38 |
|
31 | | -# Production build |
32 | | -npm run build:prod |
| 39 | +- Keep templates simple and avoid complex logic |
| 40 | +- Use native control flow (`@if`, `@for`, `@switch`) instead of `*ngIf`, `*ngFor`, `*ngSwitch` |
| 41 | +- Use the async pipe to handle observables |
33 | 42 |
|
34 | | -# Docker configuration build |
35 | | -npm run build:docker |
36 | | -``` |
| 43 | +## Services |
37 | 44 |
|
38 | | -#### Backend (Firebase Functions) |
39 | | - |
40 | | -```bash |
41 | | -# Build Firebase Functions |
42 | | -cd functions |
43 | | -npm run build |
44 | | -``` |
45 | | - |
46 | | -### Running the Project |
47 | | - |
48 | | -```bash |
49 | | -# Start Angular development server with proxy configuration |
50 | | -npm run start |
51 | | - |
52 | | -# Start Firebase emulators with data import/export |
53 | | -npm run emulator |
54 | | - |
55 | | -# Start Firebase emulators with debug mode |
56 | | -npm run emulator:debug |
57 | | -``` |
58 | | - |
59 | | -## Testing Information |
60 | | - |
61 | | -### Running Tests |
62 | | - |
63 | | -The project uses Karma and Jasmine for testing the Angular application: |
64 | | - |
65 | | -```bash |
66 | | -# Run all tests |
67 | | -npm run test |
68 | | - |
69 | | -# Run specific tests |
70 | | -npm test -- --include=path/to/test.spec.ts |
71 | | -``` |
72 | | - |
73 | | -### Writing Tests |
74 | | - |
75 | | -Tests follow the standard Angular testing patterns using Jasmine: |
76 | | - |
77 | | -1. **File Naming**: Test files should be named with the `.spec.ts` suffix and placed alongside the file they are testing. |
78 | | - |
79 | | -2. **Basic Test Structure**: |
80 | | - ```typescript |
81 | | - import { YourService } from './your-service'; |
82 | | - |
83 | | - describe('YourService', () => { |
84 | | - describe('specificMethod', () => { |
85 | | - it('should do something specific', () => { |
86 | | - expect(YourService.specificMethod('input')).toBe('expected output'); |
87 | | - }); |
88 | | - }); |
89 | | - }); |
90 | | - ``` |
91 | | - |
92 | | -### Example Test |
93 | | - |
94 | | -Here's an example of a simple utility service and its test: |
95 | | - |
96 | | -**string-utils.service.ts**: |
97 | | -```typescript |
98 | | -export class StringUtils { |
99 | | - /** |
100 | | - * Reverses a string |
101 | | - * @param input The string to reverse |
102 | | - * @returns The reversed string |
103 | | - */ |
104 | | - static reverse(input: string): string { |
105 | | - return input.split('').reverse().join(''); |
106 | | - } |
107 | | - |
108 | | - /** |
109 | | - * Checks if a string is a palindrome (reads the same forward and backward) |
110 | | - * @param input The string to check |
111 | | - * @returns True if the string is a palindrome, false otherwise |
112 | | - */ |
113 | | - static isPalindrome(input: string): boolean { |
114 | | - const normalized = input.toLowerCase().replace(/[^a-z0-9]/g, ''); |
115 | | - return normalized === this.reverse(normalized); |
116 | | - } |
117 | | -} |
118 | | -``` |
119 | | - |
120 | | -**string-utils.service.spec.ts**: |
121 | | -```typescript |
122 | | -import { StringUtils } from './string-utils.service'; |
123 | | - |
124 | | -describe('StringUtils', () => { |
125 | | - describe('reverse', () => { |
126 | | - it('should reverse a string', () => { |
127 | | - expect(StringUtils.reverse('hello')).toBe('olleh'); |
128 | | - expect(StringUtils.reverse('world')).toBe('dlrow'); |
129 | | - expect(StringUtils.reverse('')).toBe(''); |
130 | | - }); |
131 | | - }); |
132 | | - |
133 | | - describe('isPalindrome', () => { |
134 | | - it('should return true for palindromes', () => { |
135 | | - expect(StringUtils.isPalindrome('racecar')).toBe(true); |
136 | | - expect(StringUtils.isPalindrome('A man, a plan, a canal: Panama')).toBe(true); |
137 | | - expect(StringUtils.isPalindrome('No lemon, no melon')).toBe(true); |
138 | | - }); |
139 | | - |
140 | | - it('should return false for non-palindromes', () => { |
141 | | - expect(StringUtils.isPalindrome('hello')).toBe(false); |
142 | | - expect(StringUtils.isPalindrome('world')).toBe(false); |
143 | | - }); |
144 | | - |
145 | | - it('should handle empty strings', () => { |
146 | | - expect(StringUtils.isPalindrome('')).toBe(true); |
147 | | - }); |
148 | | - }); |
149 | | -}); |
150 | | -``` |
151 | | - |
152 | | -## Additional Development Information |
153 | | - |
154 | | -### Code Style |
155 | | - |
156 | | -The project uses ESLint and Prettier for code formatting and linting: |
157 | | - |
158 | | -```bash |
159 | | -# Lint the code |
160 | | -npm run lint |
161 | | - |
162 | | -# Fix linting issues |
163 | | -npm run lint:fix |
164 | | - |
165 | | -# Check formatting |
166 | | -npm run prettier |
167 | | - |
168 | | -# Fix formatting issues |
169 | | -npm run prettier:fix |
170 | | -``` |
171 | | - |
172 | | -### Angular Component Naming Conventions |
173 | | - |
174 | | -- **Component Selector Prefix**: All component selectors should use the `ll` prefix (e.g., `ll-my-component`). |
175 | | -- **Component Selector Style**: Component selectors should use kebab-case. |
176 | | -- **Directive Selector Prefix**: All directive selectors should use the `ll` prefix. |
177 | | -- **Directive Selector Style**: Directive selectors should use camelCase. |
178 | | - |
179 | | -### Firebase Configuration |
180 | | - |
181 | | -The project uses multiple Firebase services: |
182 | | - |
183 | | -- **Firestore**: Database for storing application data. |
184 | | -- **Hosting**: For hosting the Angular application. |
185 | | -- **Functions**: Backend services written in TypeScript. |
186 | | -- **Storage**: For storing files. |
187 | | - |
188 | | -Local development uses Firebase Emulators which can be started with `npm run emulator`. |
189 | | - |
190 | | -### Project Structure |
191 | | - |
192 | | -- **src/app**: Angular application code. |
193 | | -- **functions/src**: Firebase Functions code. |
194 | | -- **src/app/core**: Core functionality used throughout the application. |
195 | | -- **src/app/shared**: Shared components, services, and utilities. |
196 | | - |
197 | | -### Path Aliases |
198 | | - |
199 | | -The project uses TypeScript path aliases for cleaner imports: |
200 | | - |
201 | | -- `@shared/*`: Maps to `src/app/shared/*` |
202 | | -- `@core/*`: Maps to `src/app/core/*` |
| 45 | +- Design services around a single responsibility |
| 46 | +- Use the `providedIn: 'root'` option for singleton services |
| 47 | +- Use the `inject()` function instead of constructor injection |
0 commit comments