foundation: project guide, tooling, design tokens, bilingual shell and routing contracts
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
148
AGENTS.md
Normal file
148
AGENTS.md
Normal file
@@ -0,0 +1,148 @@
|
||||
# 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.OnPush` on 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.scss` as 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-to` mixin live in `src/_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 `anyComponentStyle` budget (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 heading
|
||||
- `proof` — only a verifiable statement
|
||||
- `playfulLine` — optional wordplay; never a capability claim
|
||||
- `cta` — 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 is `AppLocale` from `LocaleService`
|
||||
|
||||
## SSR rules
|
||||
|
||||
- No `window`, `document`, `navigator`, `localStorage` or `matchMedia` access outside `afterNextRender` or `isPlatformBrowser` guards
|
||||
- Use the injected `DOCUMENT` token 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.ts` and return conservative defaults on the server
|
||||
- Every addressable route must remain prerenderable
|
||||
|
||||
## Accessibility checklist
|
||||
|
||||
- Skip link as the first focusable element, targeting `#main-content`
|
||||
- Single `h1` per page
|
||||
- Landmark elements (`header`/`nav`, `main`, `footer`)
|
||||
- Visible `:focus-visible` ring
|
||||
- Keyboard reachability for every action
|
||||
- `aria-current` on 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:
|
||||
|
||||
1. `npm run lint` exits 0
|
||||
2. `npm run format:check` exits 0
|
||||
3. `npm run test:ci` exits 0 with no watcher left running
|
||||
4. `npm run build` exits 0
|
||||
5. New or changed routes appear in `prerenderablePaths()` and are prerendered
|
||||
6. Routing and locale contracts still have unit coverage (paths, locale helpers, navigation links)
|
||||
7. No new `window` / `document` / `navigator` reads were added outside an SSR-safe guard
|
||||
8. 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.
|
||||
Reference in New Issue
Block a user