9.7 KiB
9.7 KiB
Repository Guidelines
Project Context
This is an Angular portfolio application using Angular 21, TypeScript, SCSS,
Vitest tests, and static hosting for production output. Production
application code lives in src/app; the client entry point lives in
src/main.ts.
Feature views live in folders such as src/app/home, src/app/footer, and
src/app/imprint. Reusable generic UI building blocks belong in
src/app/shared; reusable services belong in src/app/services. Assets and
language content live in src/assets and src/languages. Do not manually
maintain generated or copied output in public/assets/optimized or dist.
Agent Workflow
- Read relevant project files before making changes and follow existing patterns.
- Always validate every change with
npm run check. - Do not run a build unless the user explicitly asks for it.
- If
npm run checkfails, read the cause first.npm run fixmay be used, but it cannot fix every issue. - Always follow the active ESLint, Prettier, and
tsconfigrules. - Change only files that are relevant to the task.
- Do not revert unrelated or unclear local changes.
- Commit, push, or open PRs only when explicitly asked.
Important Commands
npm run dev: generates assets and starts the Angular development server.npm run build: generates assets, builds the production app, and copies static root files. Run this only when explicitly requested.npm start: serves the built static app throughscripts/static-server.mjs.npm test: generates assets and starts Angular tests with Vitest.npm run check: runs linting, format checks, version checks, and source text checks. Always use this as the final validation.npm run fix: places version data, runs ESLint fixes, fixes source text, and formats the project.
Use Node >=24.14.0 and npm >=11.12.0.
Code Style
- TypeScript strict mode is enabled.
strictTemplatesis enabled. - Prettier is authoritative: 2 spaces, single quotes, semicolons, trailing commas, and default print width 100.
- Markdown wraps at 80 characters.
- Angular selectors use the
appprefix. - Components follow the pattern
feature.component.ts,feature.component.html, andfeature.component.spec.ts. - Services follow the pattern
name.service.ts. - Place shared types in
*.types.tsfiles when that matches the local pattern. - Explicitly type public methods, service APIs, and complex return values.
- Use
unknowninstead ofanywhen a value must be checked first. - Use
anyonly when technically necessary, and document the reason. - Use
constinstead ofletwhen reassignment is not needed. - Use
readonlyfor data that should not be changed. - Do not use non-null assertions to hide real nullability issues.
- Do not suppress type errors with
as unknown as. - Use union types for fixed value sets instead of magic strings.
- Keep API DTOs separate from internal UI or domain models.
Angular Architecture
- Components must have exactly one clear responsibility.
- Keep components primarily responsible for UI, user interaction, and view state.
- Put business logic, HTTP access, mapping, and shared state into focused services.
- Structure code by features or domains, not only by file types.
- Put domain-specific logic and domain-specific components in the relevant feature folder.
- Put generic reusable elements in
shared/. - Split container components from presentational components when a view becomes complex.
- Create abstractions only when at least two real use cases exist.
- Avoid cyclic dependencies between components, services, and modules.
- Do not use services as unordered global storage.
Angular Components
- Use
ChangeDetectionStrategy.OnPushunless there is a concrete reason not to. - Use required inputs when a component cannot work meaningfully without the data.
- Name inputs and outputs clearly after their purpose.
- Do not mutate input data directly.
- Keep component classes small and readable.
- Extract repeated UI blocks into their own components.
- Use lifecycle hooks only when they are truly necessary.
- Keep constructors free of logic; prefer dependency injection with
inject()when it fits the existing code. - Do not manipulate the DOM directly when Angular APIs are sufficient.
- Do not use component inheritance when composition is simpler.
State, RxJS, and Data Flows
- Use Signals for local synchronous component state.
- Use computed Signals for derived synchronous values.
- Use RxJS for asynchronous data streams and complex event chains.
- Encapsulate shared state in services.
- Keep state as close as possible to where it is needed.
- Make state changes explicit and easy to follow.
- Name Observables with a
$suffix. - Use the
asyncpipe when a stream is displayed directly in the template. - Choose
switchMap,concatMap,mergeMap, andexhaustMapdeliberately based on their semantics. - Use
combineLatestfor dependent live values andforkJoinfor multiple one-time requests. - End manual subscriptions with
takeUntilDestroyedor an equivalent mechanism. - Do not write
subscribe()insidesubscribe(). - Handle errors with
catchErrorin the right place and do not blindly swallow them withEMPTY. - Do not use RxJS for trivial synchronous state.
HTTP and API
- Encapsulate all HTTP calls in services.
- Define response types for API responses.
- Keep API configuration centralized through environments or injection tokens.
- Use interceptors for recurring technical tasks such as auth, headers, or error handling.
- Include loading, error, and empty states for slow or failed requests.
- Treat external data defensively, and validate or normalize it before broad UI use.
- Map external API data deliberately into internal models.
- Avoid duplicate API calls through shared stream or cache handling.
- Do not hardcode API URLs, tokens, roles, or secrets in components.
Templates
- Keep templates declarative and easy to read.
- Use templates only for presentation and simple bindings.
- Move complex conditions into component code or computed Signals.
- Use
@iffor conditional rendering. - Always use
@forwithtrack. - Use stable unique IDs for
track; use the index only when no stable ID exists. - Do not put business rules, complex ternaries, or expensive method calls in templates.
- Use pipes only for pure formatting.
- Break large templates into smaller components.
- Keep binding expressions short.
Forms
- Use Reactive Forms for complex forms.
- Define validators explicitly.
- Show validation errors clearly in the UI.
- Validate critical rules again on the backend.
- Keep form models and API DTOs separate when they differ.
- Map form data deliberately before sending it.
- Disable submit during active requests when repeated submission is problematic.
- Show server errors visibly in the form.
Styling
- Prefer component-scoped styling.
- Use global styles in
src/styles.scssonly for truly global rules. - Use consistent design tokens, utility classes, or reusable components for recurring UI patterns.
- Consider responsive design for every new view.
- Use semantic HTML before adding complex CSS.
- Keep spacing, colors, and font sizes consistent.
- Use inline styles only for dynamic edge cases.
- Do not use
::ng-deepas a default solution. - Do not write global CSS rules that unintentionally affect unrelated components.
- Do not build fixed-pixel layouts without responsive behavior.
Security
- Treat all external data as potentially unsafe.
- Never trust user input without validation.
- Do not store secrets in the frontend or repository.
- Use
.env.exampleas the documented template; keep real environment-specific values out of version control. - Enforce roles and permissions server-side; use frontend checks only for UX.
- Render HTML from APIs only after controlled sanitization.
- Use
bypassSecurityTrustHtmlonly after an explicit security review. - Check redirect URLs against an allowlist.
- Protect auth flows against XSS and CSRF risks.
- Store tokens only with a deliberate security concept.
Performance
- Lazy-load larger features.
- Use
OnPushto reduce unnecessary change detection. - Always render lists with stable
trackvalues. - Consider virtual scrolling for large lists.
- Do not run expensive calculations in templates.
- Move expensive calculations into computed Signals, memoization, or services.
- Do not add a large dependency for a small helper function.
- Check value, risk, and bundle cost before adding a dependency.
- Optimize images and assets.
- Measure performance problems before implementing complex optimizations.
Tests
- Keep tests next to the code under test with
*.spec.ts. - Test services that contain domain logic.
- Test complex component logic.
- Cover critical user flows with E2E tests when an E2E setup exists or is requested.
- Mock external dependencies in unit tests.
- Do not use real HTTP calls in unit tests.
- Write tests with a clear domain-level assertion.
- Test edge cases and failure cases.
- Do not couple tests unnecessarily to implementation details.
- Test names should describe behavior rather than implementation.
Code Quality and Project Practice
- Remove unused code and unused imports.
- Do not leave commented-out code blocks in the repository.
- Leave TODOs only with context, a ticket, or a documented decision.
- Use comments sparingly and only for context that is not obvious from the code.
- Keep files small enough to understand quickly.
- Follow existing project conventions.
- Prefer small, focused pull requests.
- Write commit messages with a concrete statement, for example
fix:orimprove:followed by a short summary. - Do not write commits named only
fix,stuff,update, orchanges. - Document workarounds when they are unavoidable.