Frontend coding standards, component patterns, and design system for the Guessimate Angular UI. Reference when writing or reviewing frontend code.
This document defines the coding standards, architectural patterns, and design system for the Guessimate Angular frontend.
We follow a Feature-Based directory structure. Code is organized by domain feature rather than technical type.
src/app/
├── core/ # Global singletons (Guards, Interceptors, Global Services)
├── layout/ # Layout components (Navigation, Footer, Shell)
├── features/ # Feature modules (Domain logic)
│ ├── home/
│ ├── session/
│ │ ├── components/ # Dumb/Presentational components
│ │ ├── pages/ # Smart/Container components (Routed)
│ │ ├── services/ # Feature-specific state/logic
│ │ └── models/ # Feature-specific types
│ └── ...
├── websocket/ # WebSocket infrastructure
└── shared/ # Shared utilities (Pipes, Directives, Generic UI)
session-page.component.ts, auth.service.ts).SessionPageComponent, AuthService).app- prefix, kebab-case (e.g., app-user-profile).user(), isLoading()).$ suffix (e.g., user$).standalone: true is default in v19+).
@Component({
selector: 'app-example',
imports: [CommonModule, RouterLink], // Explicit imports
template: `
<div class="p-4 bg-surface-100 rounded-lg">
<h1 class="text-2xl font-bold text-gray-900">{{ title() }}</h1>
</div>
`
})
export class ExampleComponent {
title = signal('Hello World');
}
Use the new built-in Angular Control Flow syntax.
<!-- Good -->
@if (isLoading()) {
<app-spinner/>
} @else {
@for (item of items(); track item.id) {
<app-item [data]="item"/>
}
}
Prefer the inject() function over constructor injection for better type inference and cleaner code.
// Good
private readonly
route = inject(ActivatedRoute);
private readonly
store = inject(SessionStore);
// Avoid if possible
constructor(private