8.4 KiB
AGENTS.md
Contributor and agent guide for this repository. Read this before changing routing, copy, styles, or SSR behaviour.
Purpose
This is a bilingual recruiter and B2B portfolio for a software/DevOps engineer. German is the default language and is served at /. English is the full second version and is served under /en. Every public page exists in both locales.
Architecture
- Angular 21 standalone components, no NgModules
- Zoneless change detection
- Signals for local state
- Lazy-loaded feature routes
- SSR with prerendering (
@angular/ssr,outputMode: "server") - Express host in
src/server.ts
Directory map
| Path | Role |
|---|---|
src/app/core/** |
Contracts, services and tokens. No UI. |
src/app/features/** |
Routed page components, one folder per route. |
src/app/shared/** |
Reusable UI primitives used by multiple features. |
src/app/components/** |
Existing decorative/feature widgets (skills grid, dot background). |
public/** |
Static SVG and public assets copied as-is. |
src/styles.scss |
Global design tokens and primitives. The only place raw brand hex values are defined. |
src/_breakpoints.scss |
Breakpoint map (sm 40rem, md 48rem, lg 64rem, xl 80rem) and the respond-to mixin. Components pull it in with @use 'breakpoints'. |
Commands
| Script | Purpose |
|---|---|
npm start |
Dev server (ng serve). |
npm run build |
Production build (default configuration). |
npm run watch |
Development rebuild on change. |
npm test |
Unit tests in watch mode. |
npm run test:ci |
Unit tests once (--watch=false); must exit. |
npm run lint |
ESLint over the workspace. |
npm run lint:fix |
ESLint with autofix. |
npm run format |
Prettier write. |
npm run format:check |
Prettier check (CI). |
npm run serve:ssr |
Serve the production SSR bundle. |
npm run serve:ssr:Portfolio |
Alias of serve:ssr for existing tooling. |
npm run ci |
lint, format:check, test:ci, then build. |
Code conventions
- Standalone components only
inject()over constructor injection for new code- Signals over RxJS for local state
ChangeDetectionStrategy.OnPushon new components- kebab-case file names
- No
any - No default exports
- Templates in separate files
SCSS conventions
- Global design tokens live only in
src/styles.scssas CSS custom properties - Components consume
var(--...)and never redefine raw hex values - Use the documented spacing (
--space-1…--space-12) and typography (--text-xs…--text-3xl) scale - Hover-only affordances must be wrapped in
@media (hover: hover) and (pointer: fine) - All motion must respect
prefers-reduced-motion - Breakpoints and the
respond-tomixin live insrc/_breakpoints.scss; do not invent extra breakpoint names - Shared glass, layout and focus treatments belong on the global primitives (
.glass-surface,.content-container,.stack,.cluster), not copied into component stylesheets - Keep component styles under the
anyComponentStylebudget (4 kB warn, 8 kB error)
Content rules
All user-facing copy comes from the typed bilingual content layer in src/app/core/content. Never inline marketing or page copy in templates.
Keep the four copy roles as separate fields:
headline— the serious headingproof— only a verifiable statementplayfulLine— optional wordplay; never a capability claimcta— action label, kept swappable
German and English are written idiomatically per language, never machine-translated word for word.
Claims policy (non-negotiable)
- No unsupported superlatives
- No invented references, client names, metrics or certifications
- Unproven AI, local-LLM or multi-agent capabilities are phrased as an offering or way of working, never as a delivered reference
- The CV stations HUP, BitWiz and Cybertrading are deliberately excluded from all public pages, cases and timelines
- The legal pages (Impressum, Datenschutz) contain placeholders that MUST be reviewed by the site owner before publication and must visibly say so
i18n rules
- German at
/, English under/en - Every route id exists in both locales
- New pages are added by extending the route-id table in
src/app/core/routing, never by hard-coding paths - Do not swap
LOCALE_ID; the active locale isAppLocalefromLocaleService
SSR rules
- No
window,document,navigator,localStorageormatchMediaaccess outsideafterNextRenderorisPlatformBrowserguards - Use the injected
DOCUMENTtoken when the document element is required (it works on server and browser) - No user-agent sniffing; use CSS media queries for device capability
- Capability helpers live in
src/app/core/platform/browser.tsand return conservative defaults on the server - Helpers that use
inject()must be called from a field initializer or constructor, never from a lifecycle hook or callback, and the resolved value must be stored on the instance - Every addressable route must remain prerenderable
Accessibility checklist
- Skip link as the first focusable element, targeting
#main-content - Single
h1per page - Landmark elements (
header/nav,main,footer) - Visible
:focus-visiblering - Keyboard reachability for every action
aria-currenton the active nav item- At least 4.5:1 text contrast on the base surface
- Reduced-motion alternatives for animation and smooth scrolling
- Navigation remains usable in its server-rendered default state (no JS-only menus)
SEO expectations
- Semantic headings
- Real locale-prefixed URLs
- Server-rendered core text
- Per-route titles from the content layer
Canonical, hreflang document tags and JSON-LD arrive in the integration phase. The language switch already exposes hreflang on the alternate-locale link.
Test checklist
A change is not done until:
npm run lintexits 0npm run format:checkexits 0npm run test:ciexits 0 with no watcher left runningnpm run buildexits 0- New or changed routes appear in
prerenderablePaths()and are prerendered - Routing and locale contracts still have unit coverage (paths, locale helpers, navigation links)
- No new
window/document/navigatorreads were added outside an SSR-safe guard - Placeholder or legal copy was not replaced with invented professional claims
Domain boundaries
| Branch | Owns |
|---|---|
| Foundation | Tooling, tokens, shell, routing and content contracts, SSR safety, test baseline |
| Content | Bilingual copy data and page composition |
| Signature | Systems Map, terminal, dot background and motion |
| Integration | SEO and cross-cutting a11y/performance hardening |
Each branch extends the shared contracts instead of duplicating paths or copy. The Content branch replaces placeholder-content.ts and keeps SITE_CONTENT. The Signature branch may replace the dot-background internals but must keep the SSR-safe init/teardown contract.