Thank you for your interest in contributing to the AI Horde frontend.
# Prerequisites: Node.js 24 via NVM
nvm use 24.12.0
# Install dependencies
npm ci
# Start dev server (port 4209)
npm start- Standalone components — All components are standalone. Do NOT set
standalone: truein decorators (it's the default in Angular 21+). - OnPush change detection — Every component must set
changeDetection: ChangeDetectionStrategy.OnPush. - Signal-based state — Use
signal(),computed(), andinput()/output()functions. viewChild()signal — UseviewChild()instead of@ViewChilddecorator.inject()function — Useinject()instead of constructor injection.takeUntilDestroyed()— All RxJS subscriptions in components must usetakeUntilDestroyed(destroyRef)for cleanup.- Native control flow — Use
@if,@for,@switchinstead of*ngIf,*ngFor,*ngSwitch. - Lazy loading — Routes use
loadComponent()for code splitting.
Use the setPageTitle() helper from src/app/helper/page-title.ts:
import { setPageTitle } from '../helper/page-title';
ngOnInit(): void {
setPageTitle(this.translator, this.title, this.destroyRef, 'page.title_key');
}For the homepage, use setAppTitle() instead.
All HTTP requests to the AI Horde API go through HordeApiCacheService with CacheTTL constants:
private readonly cache = inject(HordeApiCacheService);
this.cache.cachedGet<MyType>(url, { context }, { ttl: CacheTTL.LONG, category: 'myCategory' });Use ToastService for user-facing messages:
private readonly toast = inject(ToastService);
this.toast.success('message', { transloco: true });
this.toast.error('message', { transloco: true, rawError: error });Use IconComponent (<app-icon name="icon-name" />) instead of inline <svg> elements. Icon assets live in src/assets/img/icons/.
All styles are centralized in src/styles/. Component .css files must be empty. Use semantic CSS classes rather than inline Tailwind utilities.
See STYLING.md for the full conventions and docs/design-system.md for the token reference.
- All interactive elements must have visible focus states.
- Color alone must not convey information — pair with text or icons.
- Modals must trap focus and restore it on close.
- Must pass AXE checks and meet WCAG AA minimums.
The project uses Husky + lint-staged. On commit, the following run automatically:
- ESLint (
--fix) on.tsand.htmlfiles - Prettier on
.ts,.html,.css, and.jsonfiles
Pull requests run these checks (all must pass):
- Lint —
npm run lint - Format —
npm run format-check - Typecheck —
npx tsc --noEmit - Test —
npm test(Vitest with coverage thresholds) - Build —
npm run build(SSR production build)
- Create a feature branch from
main. - Make focused, single-purpose changes.
- If adding a style or component, update the relevant documentation in
STYLING.mdordocs/component-patterns.md. - Ensure all CI checks pass locally before pushing.
- Write a clear PR description explaining what changed and why.
- README.md — Project overview and quick start
- ARCHITECTURE.md — Technical overview: routes, services, data flow
- STYLING.md — Style conventions and file organization
- docs/design-system.md — Design tokens, surface primitives, color system
- docs/component-patterns.md — CSS class catalog
- docs/plans/ — Outstanding improvement plans