feat: enhance project setup and architecture documentation

- Updated `tibi-project-setup` skill to clarify project initialization goals and steps.
- Improved `tibi-ssr-caching` skill to detail SSR architecture, responsibilities, and caching mechanisms.
- Introduced `website-solution-architecture` skill for translating website requirements into coherent solutions.
- Refined `AGENTS.md` to provide a structured roadmap for project development phases.
- Added `ADMIN_ASSET_VERSION` to `api/config.yml.env` for asset versioning.
- Updated SSR request flow and cache invalidation logic in `api/hooks/ssr/AGENTS.md`.
- Removed obsolete `esbuild.config.admin.js` and integrated asset versioning into the main `esbuild.config.js`.
- Adjusted `api/collections/content.yml` to utilize asset versioning for admin scripts.
This commit is contained in:
2026-05-12 20:01:22 +00:00
parent 4a604bab0b
commit 491f495c66
23 changed files with 3189 additions and 225 deletions
+42 -11
View File
@@ -15,6 +15,7 @@ Use this skill when:
- Adding new Svelte 5 reactive patterns
- Understanding the API layer and error handling
- Working with i18n / multi-language features
- Understanding how SSR and SPA loading share one app-level data path
---
@@ -81,6 +82,22 @@ Example: /de/ueber-uns → lang="de", routePath="/ueber-uns"
Root `/` redirects to `/{browserLanguage}/` via `getBrowserLanguage()`.
### SSR interaction with routing
This frontend is not just an SPA. The same top-level app also participates in SSR.
- `frontend/src/ssr.ts` is intentionally thin and should mostly bootstrap locale state and call `render(App, { props: { url } })`.
- `App.svelte` owns page loading for both browser and SSR.
- Browser navigation triggers page loading from `$effect`.
- SSR triggers the same page-loading path directly inside `typeof window === "undefined"`.
This means route changes, i18n path handling, and content-loading behavior must be reasoned about together. If a route works in the browser but SSR returns empty content or 404, inspect the mapping between:
- public URL (`/de/...`)
- stripped route path (`/...`)
- `content.path` in the DB
- `api/hooks/config.js` SSR route validation
### Navigation API
```typescript
@@ -130,6 +147,8 @@ export const ROUTE_TRANSLATIONS: Record<string, Record<SupportedLanguage, string
}
```
Keep in mind that these translations affect the public URL shape and therefore also the SSR route-validation layer. Changing localized slugs is not purely a frontend concern.
---
## State management
@@ -138,17 +157,17 @@ The project uses **Svelte writable/derived stores** (not a centralized state lib
### Store inventory
| Store | File | Purpose |
| ---------------------- | ---------------------- | ----------------------------------------------------------------------------------- |
| `location` | `lib/store.ts` | Current URL state (path, search, hash, push/pop flags) |
| `mobileMenuOpen` | `lib/store.ts` | Whether mobile hamburger menu is open |
| `currentContentEntry` | `lib/store.ts` | Currently displayed page's `translationKey`, `lang`, `path` (for language switcher) |
| `previousPath` | `lib/store.ts` | Previous URL path (for conditional back buttons) |
| `apiBaseOverride` | `lib/store.ts` | Override API base URL (used by admin module) |
| `cookieConsentVisible` | `lib/store.ts` | Whether cookie consent banner is showing |
| `currentLanguage` | `lib/i18n.ts` | Derived from `$location.path` — current language code |
| `selectedLanguage` | `lib/i18n.ts` | Writable — synced with `currentLanguage` on navigation |
| `activeRequests` | `lib/requestsStore.ts` | Number of in-flight API requests (drives `LoadingBar`) |
| Store | File | Purpose |
| ---------------------- | ---------------------- | -------------------------------------------------------------------------------- |
| `location` | `lib/store.ts` | Current URL state (path, search, hash, push/pop flags) |
| `mobileMenuOpen` | `lib/store.ts` | Whether mobile hamburger menu is open |
| `currentContentEntry` | `lib/store.ts` | Currently displayed page entry data such as `translationKey`, `lang`, and `path` |
| `previousPath` | `lib/store.ts` | Previous URL path (for conditional back buttons) |
| `apiBaseOverride` | `lib/store.ts` | Override API base URL (used by admin module) |
| `cookieConsentVisible` | `lib/store.ts` | Whether cookie consent banner is showing |
| `currentLanguage` | `lib/i18n.ts` | Derived from `$location.path` — current language code |
| `selectedLanguage` | `lib/i18n.ts` | Writable — synced with `currentLanguage` on navigation |
| `activeRequests` | `lib/requestsStore.ts` | Number of in-flight API requests (drives `LoadingBar`) |
### Pattern: creating a new store
@@ -244,6 +263,16 @@ Located in `frontend/src/lib/api.ts`. Features:
- **Mock interceptor** — when `__MOCK__` is `true`, routes requests to `frontend/mocking/*.json`
- **Sentry integration** — span instrumentation (when enabled)
### Shared browser/SSR transport
The project intentionally shares the low-level API transport between browser and SSR via `api/hooks/lib/ssr`.
- In the browser, it eventually becomes `fetch(...)`.
- In SSR, `apiRequest(...)` delegates to `context.ssrRequest(...)`.
- GET responses reached during SSR are written into `window.__SSR_CACHE__` for hydration.
This is why SSR can preload both content and navigation without building a separate frontend-only data layer.
### Usage patterns
```typescript
@@ -358,3 +387,5 @@ Return { data, count, buildTime }
- **`_id` not `id` for filters** — API filters use MongoDB's `_id`, but response objects may have both `id` and `_id`.
- **`$location` strips trailing slashes** — `/about/` becomes `/about` (except root `/`).
- **Content cache is 1 hour** — `getCachedEntries` caches in memory for 1h. For admin previews, use `getDBEntries` (uncached).
- **`$effect` alone is not SSR** — server-side rendering must trigger the same data path explicitly outside browser-only reactive effects.
- **A rendered shell is not enough** — always verify that SSR HTML actually contains page-critical content and navigation.