Architecture
Use this page to find your way around the site's code and to follow its coding conventions.
Stack
- Angular 20 with standalone components, no NgModules
- Signals for state
- SCSS for styling, no Tailwind
- FontAwesome through
@fortawesome/angular-fontawesome @ngx-translatefor translations- The
@angular/build:applicationbuilder, with Bun as the package manager
Layout
The source is in src/app/:
app.ts,app.config.ts,app.routes.ts: root component, providers, routing.app.config.server.ts,app.routes.server.ts: server rendering and prerender settings.components/: UI pieces (hero,features,faq,screenshots,download,navigation,footer,legal,language-switcher).pages/: routed views (home,not-found).services/:language,lang.resolver,seo.
Outside src/app/:
public/i18n/: one translation file per language, including themeta.*page metadata.public/_redirects,public/_headers: Cloudflare Pages redirects and headers.functions/index.js: a Cloudflare Pages Function for/only.scripts/postbuild.ts: runs afterng build.
Routes and languages
Every page has a language prefix: de, gsw, fr, it, rm, or en. German is the default; Swiss German is only used when chosen in the menu.
| Route | Page |
|---|---|
/<lang> | Home |
/<lang>/impressum | Impressum |
/<lang>/privacy | Privacy |
/<lang>/terms | Terms |
| Any other path | Not found (404, noindex) |
app.routes.tsgenerates the routes for each language.langResolversets the active language and waits for its translations, so each route prerenders in its own language.- The build uses
outputMode: static.app.routes.server.tslists the routes and languages to prerender. services/seo.tssets each route's title, description, canonical URL, social tags, andhreflangalternates when it prerenders.functions/index.jsredirects/to a language based onAccept-Language.public/_redirectssends/to/deas a fallback and sends the old unprefixed paths to their/deversions. On*.pages.devhosts,public/_headersand the function addX-Robots-Tag: noindex.scripts/postbuild.tswrites404.html(and removes the/404route), writessitemap.xml, removes the rootindex.html, and turns<lang><path>/index.htmlinto<lang><path>.html. Cloudflare Pages servesde.htmlat/dewith 200, so the slash-less canonical URLs need no redirect. When you add a language or a page, updateLANGSorPAGESin that script.
Angular 20 coding conventions
All contributions follow these conventions.
Components
- Use standalone components only. Don't set
standalone: truein decorators, because it's the default. - Use the
input()andoutput()functions instead of the@Input()and@Output()decorators. - Set
changeDetection: ChangeDetectionStrategy.OnPush. - Keep components small, with one responsibility. Prefer inline templates for small components.
- Prefer reactive forms over template-driven forms.
- Put host bindings in the decorator's
hostobject. Don't use@HostBindingor@HostListener. - Use
classandstylebindings, notngClassorngStyle. - Use
NgOptimizedImagefor static images. It doesn't work for inline base64 images. - Lazy load feature routes.
State
- Use signals for local component state and
computed()for derived state. - Use
updateorseton signals, notmutate. - Keep state transformations pure and predictable.
Templates
- Use native control flow (
@if,@for,@switch), not*ngIf,*ngFor, or*ngSwitch. - Use the
asyncpipe for observables. Keep complex logic out of templates.
Services
- Give each service one responsibility, and use
providedIn: 'root'for singletons. - Use the
inject()function instead of constructor injection.
TypeScript
- Use strict type checking. Prefer type inference when the type is obvious.
- Avoid
any. Useunknownwhen the type is uncertain.
