feat: enhance medialib image handling and add asset URL resolution

- Implemented `resolveApiAssetUrl` function to normalize asset URLs based on API base.
- Updated `MedialibImage` component to utilize new asset URL resolution and added support for alt text and class properties.
- Enhanced image loading behavior with improved width measurement and focal point handling.
- Added placeholder image handling and improved accessibility with alt text.
- Introduced new test script for auditing broken links in skill documentation.
- Expanded seeded test content to include medialib entries and updated related tests for pagebuilder previews.
- Improved global setup and teardown logging for clarity on seeded content management.
This commit is contained in:
2026-05-17 00:52:41 +00:00
parent 958b45272d
commit 4020ad62c5
44 changed files with 4276 additions and 867 deletions
+274 -192
View File
@@ -1,6 +1,6 @@
---
name: tibi-project-setup
description: Set up a new tibi project from the tibi-svelte-starter template. Covers cloning, placeholder replacement, environment config, Docker startup, mock mode, demo cleanup, and build verification. Use when creating a new project or onboarding into this template.
description: Set up a new tibi project from the tibi-svelte-starter template. Covers placeholder replacement, env/config setup, Docker startup, optional shared-server registration, and build verification. Use when creating a new project or onboarding into this template.
---
# tibi-project-setup
@@ -9,257 +9,339 @@ description: Set up a new tibi project from the tibi-svelte-starter template. Co
Use this skill when:
- Creating a new project from the `tibi-svelte-starter` template
- Onboarding into a freshly cloned starter project where placeholders haven't been replaced yet
- The user asks to "set up", "initialize", or "bootstrap" a new tibi project
- creating a new project from `tibi-svelte-starter`
- onboarding into a freshly cloned project where starter placeholders are still present
- fixing a project that was renamed but never fully registered/configured in the current tibi stack
Goal: a new website project should end up as a **fully working tibi-server + tibi-admin-nova project**, not just a renamed starter clone.
Goal: end with a project that is not only renamed, but actually reachable as a working website, admin, and API project in the current Docker/tibi-server setup.
## Source of truth
Use these sources when bootstrapping or auditing setup:
- `.agents/BUILD_CHECKLIST.md` phase 0
- `AGENTS.md`
- `README.md`
- `Makefile`
- `docker-compose-local.yml`
- `.env`
- `api/config.yml`
- `api/config.yml.env`
- `api/hooks/config-client.js`
- `.gitea/workflows/deploy.yml`
- `scripts/ci-deploy.sh`
- `scripts/ci-staging.sh`
- tibi-server server-level config requirements from `tibi-server/docs/02-configuration.md` when the project does not run on the starter's local Docker stack
## Core setup rule
Do not stop after placeholder replacement.
A project is only set up when all of these are true:
- placeholders and visible starter identity leftovers are gone
- env and token values are present
- Docker stack comes up
- the intended operator path is explicit: local starter Docker stack or shared/external tibi-server stack
- website, admin, and API respond on the expected project URLs
- if the current stack requires server-level config and project registration, that operator flow is completed
- `yarn build`, `yarn build:server`, and `yarn validate` pass
## Prerequisites
- Code-Server environment at `*.code.testversion.online`
- `git`, `yarn`, `make`, `docker compose` available
- Traefik reverse proxy running on the host (manages `*.code.testversion.online` subdomains automatically via Docker labels)
- `git`, `yarn`, `make`, `docker compose`, `curl`
- current Code-Server / Docker environment for `*.code.testversion.online`
- reverse proxy/Traefik managed by the host environment
## Step 1 — Clone and set up remotes
## Step 1 — Clone and prepare remotes
Skip this step if already inside a cloned project.
Skip if the project is already cloned.
```sh
# In the workspace directory (e.g. /WM_Dev/src/gitbase.de/cms/)
git clone https://gitbase.de/cms/tibi-svelte-starter.git my-project
cd my-project
git remote rename origin template
# Create a new remote repo (e.g. on gitbase.de) and add as origin:
# git remote add origin https://gitbase.de/org/my-project.git
git remote add origin https://gitbase.de/<org>/<repo>.git
```
**Verify:** `git remote -v` shows `template` pointing to the starter and optionally `origin` pointing to the new repo.
## Step 2 — Replace starter placeholders and identity surfaces
## Step 2 — Replace placeholders and starter values
Replace placeholders in all required files:
Replace the starter placeholders and starter-derived values in the correct files:
- `.env`
- `api/config.yml`
- `frontend/.htaccess` when the deployment path uses the shipped Apache rewrite/proxy file
- `api/hooks/config-client.js`
- `package.json`
- `README.md` or other visible starter naming surfaces when the repo is already project-facing
- any other file that still contains starter markers
| Placeholder | Files | Format | Example |
| -------------------- | ---------------------------------------------- | --------------------------------------------------------- | ------------ |
| `__PROJECT_NAME__` | `.env` | kebab-case (used for URLs, Docker containers, subdomains) | `my-project` |
| `__TIBI_NAMESPACE__` | `.env`, `api/config.yml`, `frontend/.htaccess` | kebab-case, same value as `PROJECT_NAME` | `my-project` |
Minimum placeholders to replace:
- `__PROJECT_NAME__`
- `__TIBI_NAMESPACE__`
- `__ORG__`
- `__PROJECT__`
Verify with:
```sh
PROJECT=my-project # kebab-case
NAMESPACE=my-project # same kebab-case value as PROJECT
sed -i "s/__PROJECT_NAME__/$PROJECT/g" .env
sed -i "s/__TIBI_NAMESPACE__/$NAMESPACE/g" .env api/config.yml frontend/.htaccess
rg '__[A-Z0-9_]+__' . --glob '*.{yml,js,env,htaccess,json,md,ts,svelte}'
```
Also update the starter-derived values that are not placeholder tokens anymore, especially `STAGING_PATH`, `STAGING_URL`, `CODING_URL`, `CODING_TIBIADMIN_URL`, `api/hooks/config-client.js`, and starter metadata in `package.json`.
If anything remains, the setup is not complete.
**Important:** The file `api/hooks/config-client.js` contains a **separate** placeholder `__PROJECT__` (not `__PROJECT_NAME__`):
## Step 3 — Fill project env, token, and metadata files
Set the current project URLs in `.env`:
- `LIVE_URL`
- `CODING_URL`
- `STAGING_URL`
- `CODING_TIBIADMIN_URL`
- `CODING_TIBISERVER_URL` only when the current environment exposes a dedicated raw tibi-server host
Generate `api/config.yml.env` values:
```sh
# api/hooks/config-client.js has: const originURL = "https://__PROJECT__.code.testversion.online"
sed -i "s/__PROJECT__/$PROJECT/g" api/hooks/config-client.js
token=$(openssl rand -hex 20)
cat > api/config.yml.env <<EOF
ADMIN_TOKEN=$token
ADMIN_ASSET_VERSION=$(node -e "process.stdout.write(require('crypto').randomBytes(6).toString('hex'))")-dirty-$(date +%s)
EOF
```
**Verify all placeholders:**
Important:
```sh
grep -n '__PROJECT_NAME__\|__TIBI_NAMESPACE__\|__PROJECT__\|__ORG__' .env api/config.yml frontend/.htaccess api/hooks/config-client.js
# Expected: no output (all placeholders replaced)
```
- `ADMIN_TOKEN` is used for collection-level writes through the header name declared by the collection permission key; in this starter that is typically `Token` via `token:${ADMIN_TOKEN}`
- the current deploy scripts also use the same secret as a bearer token on the project-local reload endpoint
- `ADMIN_ASSET_VERSION` is required so Nova picks up the current admin bundle
- `PROJECT_NAME`, `TIBI_NAMESPACE`, `PRODUCTION_PATH`, and `STAGING_PATH` should be project-specific before the first deploy
- `package.json` should no longer advertise the starter repository or default package name once the project is bootstrapped
**Result in `.env`:**
## Step 4 — Install and start the Docker stack
```dotenv
PROJECT_NAME=my-project
TIBI_NAMESPACE=my-project
CODING_URL=https://my-project.code.testversion.online
STAGING_URL=https://dev-my-project.staging.testversion.online
```
### Common mistakes
- **Using different values for `PROJECT` and `NAMESPACE`**: In this starter, `TIBI_NAMESPACE` must match `PROJECT_NAME` and use the same kebab-case value.
- **Forgetting `frontend/.htaccess`**: Contains the namespace for API rewrite rules. If missed, API calls from the frontend will fail silently.
- **Forgetting `api/config.yml`**: First line is `namespace: __TIBI_NAMESPACE__`. If not replaced, tibi-server won't start correctly.
## Step 3 — Page title
The page title is set dynamically via `<svelte:head>` in `frontend/src/App.svelte`. The demo app uses the constant `SITE_NAME` for this. In a new project, `App.svelte` is typically rewritten completely — just make sure `<svelte:head>` with a `<title>` is present. SSR automatically injects it via the `<!--HEAD-->` placeholder in `spa.html`.
Also verify that SSR still renders meaningful page content and not just the shell after the rewrite.
## Step 4 — Admin token and config.yml.env
**How config.yml.env works:** The file `api/config.yml.env` is **not** a standard `.env` file. It is an env-file that the tibi-server reads from the same directory as `config.yml`. The server resolves `${ADMIN_TOKEN}` and `${ADMIN_ASSET_VERSION}` variables in the YAML config from this file. This is separate from the project-root `.env` which serves Docker Compose and the Makefile.
`api/config.yml.env` ships with a default `ADMIN_TOKEN`. For production projects, generate a secure one:
```sh
token=$(openssl rand -hex 20) && sed -i "s/^ADMIN_TOKEN=.*/ADMIN_TOKEN=$token/" api/config.yml.env
```
This updates only `ADMIN_TOKEN` and keeps the other env keys in the file intact.
**Verify:** `cat api/config.yml.env` shows a 40-character hex token while preserving entries such as `ADMIN_ASSET_VERSION`.
**Note:** The `ADMIN_ASSET_VERSION` in the same file is used for cache-busting the admin bundle (`frontend/dist/admin.mjs`). It is auto-generated on build — but if missing, the admin bundle may not load correctly.
## Step 5 — Install, upgrade, and start
Use the Docker targets from the project. Do not try to start the frontend with local dev servers.
```sh
yarn install
make docker-up # Start stack in background
# or
make docker-start # Start stack in foreground (CTRL-C to stop)
make docker-up
```
Do not blindly run a full dependency upgrade as part of project bootstrap unless the task explicitly includes dependency maintenance. First get the starter running as-is, then upgrade intentionally and validate.
Notes:
**Important:** After changing `.env` or `api/config.yml.env`, you must run `make docker-down && make docker-up` for the changes to take effect. Docker Compose reads `.env` at startup time; tibi-server reads `config.yml.env` at reload. A simple `make docker-restart-frontend` is not sufficient for environment variable changes.
- `make docker-up` already depends on `init`; do not duplicate bootstrap steps unless debugging Make targets directly
- for foreground operation use `make docker-start`
**Verify containers are running:**
## Step 5 — Choose the active bootstrap path
### Path A — Local starter Docker stack
This repo's default local path is the Docker stack in `docker-compose-local.yml` started via `make docker-up`.
Important characteristics:
- the project is mounted into `tibiserver` as `/data`
- `DB_DIAL`, `DB_PREFIX`, `MAIL_HOST`, and security overrides are injected via container environment
- the project is served from the repo's own `api/config.yml`
- no extra root `config.yml` or `/api/v1/project` registration step is required for basic local startup
Use this path unless the operator environment clearly tells you otherwise.
### Path B — Shared or external tibi-server stack
Only use this path when the project is not started through the local starter compose stack and the operator environment requires explicit server-level config or project registration.
In that case, confirm all of these with the operator first:
- where the server-level `config.yml` lives
- which admin token is valid for raw system-level APIs
- which base URL exposes `/api/v1/project`
- how the project path is mounted into the shared tibi-server instance
Do not invent Path B steps in the local starter Docker stack just because upstream tibi-server docs mention them.
## Step 6 — Optional server-level config and project registration for Path B
Shared or external tibi-server setups may require a server-level `config.yml` outside the project config. That file defines database connection, JWT secret, and admin tokens used for project CRUD and reload.
Create a root-level `config.yml` such as:
```yaml
db:
dial: mongodb://mongo
prefix: tibi
api:
port: 8080
jwtSecret: <random-secret>
adminTokens:
- token: "<ADMIN_TOKEN>"
label: "admin"
permissions:
- project
- project.reload
- user
- namespace.<PROJECT_NAME>
- server.shutdown
mail:
host: localhost:25
security:
allowAbsolutePaths: false
allowUpperPaths: true
```
Then copy it into the tibi-server container and restart that container if the current environment requires this manual step.
## Step 7 — Verify website, admin, and API reachability
Run the project-local checks after startup:
```sh
make docker-ps # All containers should be "Up"
make docker-logs # Check for errors
curl -I "$CODING_URL"
curl -I "$CODING_TIBIADMIN_URL"
curl -I "$CODING_URL/api/content?limit=1"
```
## Step 6 — Verify URLs
Traefik picks up Docker labels automatically — no manual config needed. After `make docker-up`, these URLs become available:
| Service | URL |
| --------------------- | ------------------------------------------------------------ |
| Website (BrowserSync) | `https://{PROJECT_NAME}.code.testversion.online/` |
| Tibi Admin | `https://{PROJECT_NAME}-tibiadmin.code.testversion.online/` |
| Tibi Server API | `https://{PROJECT_NAME}-tibiserver.code.testversion.online/` |
| Maildev | `https://{PROJECT_NAME}-maildev.code.testversion.online/` |
The subdomains are registered via the Docker label `online.testversion.code.subdomain=${PROJECT_NAME}`. Traefik watches Docker events and creates routes dynamically.
**Verify:** `curl -sI https://{PROJECT_NAME}.code.testversion.online/ | head -1` returns `HTTP/2 200`.
## Step 7 — Mock mode (optional)
For frontend development without a running tibi-server backend:
If the current environment also exposes a raw tibi-server host, add:
```sh
# Set in .env:
MOCK=1
# Then full restart (env change requires docker-down first):
make docker-down && make docker-up
curl -I "$CODING_TIBISERVER_URL/api/v1/version"
```
**When to use mock mode:** Early UI prototyping, frontend-only work, CI environments without a database.
If `/api/...` returns HTML instead of JSON, the reverse-proxy/setup path is still wrong.
## Step 8 — Remove demo content
## Step 8 — Optional project registration for Path B
For a real project, remove or replace the demo files:
Projects are not assumed to exist just because files are present on disk. Register and reload them explicitly when the current stack requires project registration.
| File/Folder | Content |
| ---------------------------------- | ------------------------------------------------------ |
| `frontend/src/blocks/` | Demo block components (HeroBlock, RichtextBlock, etc.) |
| `frontend/mocking/content.json` | Demo mock data for content |
| `frontend/mocking/navigation.json` | Demo mock data for navigation |
| `api/collections/content.yml` | Content collection config |
| `api/collections/navigation.yml` | Navigation collection config |
| `tests/e2e/` | Demo E2E tests |
| `video-tours/tours/` | Demo video tour |
```sh
curl -s -X POST "$CODING_TIBISERVER_URL/api/v1/project" \
-H "Content-Type: application/json" \
-H "X-Admin-Token: $ADMIN_TOKEN" \
-d '{
"name": "<PROJECT_NAME>",
"description": "...",
"configFile": "/data/api/config.yml",
"enabled": true
}'
```
Then adapt `frontend/src/App.svelte` (header, footer, content loading) to your own data model.
Reload after creation or config changes:
But do not delete starter structures blindly. For a serious project build-out, first decide which parts remain useful foundations:
```sh
curl -s -X POST "$CODING_TIBISERVER_URL/api/v1/_/<PROJECT_NAME>/_/admin/reload" \
-H "X-Admin-Token: $ADMIN_TOKEN"
```
- SSR pipeline
- i18n route model
- pagebuilder-based content collection
- navigation collection
- media library and image handling
- tests / tours as scaffolding
### Token header distinction
The goal is not "delete the demo". The goal is "reshape the starter into a project architecture that editors can use productively".
- raw system-level API such as project CRUD or direct admin reload: `X-Admin-Token`
- collection-level CRUD such as content/navigation writes: use the header name from the collection permission key, typically `Token` in this starter via `token:${ADMIN_TOKEN}`
- JWT-authenticated user requests: `X-Auth-Token`
**Decision guide:**
The current starter deploy scripts are a separate case: they call the reverse-proxied reload endpoint on `LIVE_URL` or `STAGING_URL` with `Authorization: Bearer ${ADMIN_TOKEN}`.
- **Keep demo content** if you want to use it as a reference while building your own components.
- **Delete immediately** if you're starting with a completely custom design and the demo files would only cause confusion.
Do not mix these headers casually. A working collection token does not imply project-admin access.
## Step 9 — Build and validate
```sh
yarn build # Frontend bundle for modern browsers
yarn build:server # SSR bundle (for tibi-server goja hooks)
yarn validate # TypeScript + Svelte checks (must show 0 errors and 0 warnings)
```
**These commands must succeed before the project is considered set up.**
## Step 10 — Shape the project for real editor workflows
For a complete website on this starter, setup is not done when Docker runs. It is done when the project has a coherent content/admin model.
Inspect and adapt at least these areas:
- `api/collections/content.yml`: page types, block schema, SEO, i18n, pagebuilder config
- `api/collections/navigation.yml`: header/footer structure and editor UX
- `frontend/src/blocks/`: real block set for the website, not just demo showcase blocks
- `frontend/src/blocks/BlockRenderer.svelte`: final block registry
- `types/global.d.ts`: actual project data model
- `frontend/src/App.svelte`: final shell, content-loading, SSR-safe behavior
For Nova specifically, use current capabilities where they improve the website build process:
- `preview` for readable row, breadcrumb, and foreign-key display
- `sidebar` groups for publication/SEO/settings
- `containerProps.layout` for usable forms
- `dependsOn` for block-specific fields
- `drillDown` for complex arrays
- `pagebuilder` for heterogeneous page content
- `subNavigation`, `singleton`, `viewHint`, and foreign previews where appropriate
For tibi-server specifically, decide early whether the site also needs:
- `actions:` for forms, newsletter, calculators, imports, or webhooks
- publication-aware SSR invalidation
- field-level permissions
- AI/LLM integration for admin/editor workflows
## SSR debugging: manual project reload
After changing collection YAML files, hook code, or `config.js` (SSR route validation), you may need to trigger a project reload for tibi-server to pick up the changes. Hook files auto-reload, but structural changes (new collections, config changes) require explicit reload:
```bash
curl -X POST "$CODING_URL/api/v1/_/$TIBI_NAMESPACE/_/admin/reload" \
-H "Token: $ADMIN_TOKEN"
```
The starter's `api/config.yml` has `allowReload: true` for the admin token by default. Response `{"message": "ok"}` confirms the reload.
Use this when:
- A new collection was added to `api/config.yml` but the API doesn't see it
- Hook files changed but the server hasn't picked them up
- SSR route validation (`api/hooks/config.js`) was updated and the old behavior persists
## Step 11 — Functional verification for a real website project
After the first project shaping pass, verify more than just TypeScript:
```sh
yarn build
yarn build:server
yarn validate
```
Then also verify:
The project is not considered bootstrapped until all three succeed.
- the public site loads via the website URL
- the Nova admin loads via the admin URL
- pages can be created and edited in admin
- pagebuilder blocks are usable in admin
- SSR renders real page content, not only the shell
- navigation and media references render correctly
- forms/actions work if the project uses them
## Step 10 — Optional immediate follow-up work
If the goal is "LLM can build a complete website automatically", the project setup skill must lead to a fully functional content/admin/runtime stack, not merely a placeholder replacement.
Depending on the project state, continue with:
- seed or create initial content/navigation entries
- remove demo content and demo assets
- update project imagery/icons
- run the first targeted Playwright smoke checks
## Recommended verification sequence
Use this exact order when debugging a broken setup:
1. placeholder scan
2. env/token/metadata presence
3. Docker stack or target operator stack up
4. choose Path A or Path B explicitly
5. if Path B: server-level config and project registration/reload succeed
6. website/admin/API reachability
7. build/SSR build/validate
This prevents wasting time in frontend code when the real issue is project registration or server-level config.
## Common failure modes
### Placeholders still present
Symptom:
- URLs or namespace stay wrong even though the project name was changed manually
Fix:
- rerun the placeholder scan and replace every remaining marker
### Website works but API probes return HTML
Symptom:
- `curl "$CODING_URL/api/content?limit=1"` returns HTML
Fix:
- verify reverse-proxy routing and the configured API/admin URLs
### Files exist but the project is invisible to tibi-server
Symptom:
- project does not show in admin or reload endpoint fails
Fix:
- this is a Path B problem; verify the shared-stack server-level config and project registration flow instead of changing the local starter stack
### Admin bundle changes do not appear
Symptom:
- Nova still loads stale admin assets
Fix:
- regenerate or bump `ADMIN_ASSET_VERSION`
### Build passes locally but operational setup is still broken
Symptom:
- files compile, but website/admin/API are not all reachable
Fix:
- return to the reachability and registration checks instead of continuing with feature work
## What an LLM should inspect first
When asked to bootstrap or audit a starter-derived project, inspect in this order:
1. `README.md`
2. `.env`
3. `api/config.yml`
4. `api/config.yml.env`
5. `api/hooks/config-client.js`
6. `docker-compose-local.yml` and `Makefile`
7. whether the current stack is Path A (local starter Docker) or Path B (shared/external tibi-server)
8. whether website, admin, and API URLs all respond
This avoids the common mistake of treating setup as a naming exercise instead of a full stack-registration task.