# SEO How search visibility works in this project and where each piece is controlled. Everything is data-driven from the admin; no code change is needed to adjust titles, descriptions, indexing, verification, or structured data. ## Admin: Settings → SEO (`/site-settings/seo`) Canonical page: `app/_admin/site-settings/seo/page.tsx` (mirrored under `app/admin-internal/` and `app/root/`). Form: `components/admin/seo-settings-form.tsx`. Action: `saveSeoSettingsAction` in `app/_admin/site-settings/actions.ts`. Stored as one JSON blob in `app_config` under key `seo_settings` (`lib/seo-settings.ts` parses/normalizes; `lib/app-config.ts` exposes `getSeoSettings` / `updateSeoSettings`). | Field | Effect | |---|---| | Indexierung erlauben | Off → `noindex,nofollow` meta on every page, `robots.txt` disallows `/`, `sitemap.xml` becomes empty. Maintenance mode forces the same automatically. | | Google / Bing Verification | `` and `` on all pages. Tokens are restricted to `[A-Za-z0-9_-]`. | | X / Twitter Handle | `twitter:site` + `twitter:creator`. | | Strukturierte Daten | Type (`Person` / `Organization`), name, job title/slogan, `sameAs` profile URLs → JSON-LD publisher on every public page. | | Keywords (per locale) | `` per language. | The page also shows a **checklist** (`lib/seo-report.ts`) — indexing state, public URL, meta description length per locale, OG image, favicon, verification, structured data, published projects, sitemap URL count — and **open buttons** for `/sitemap.xml`, `/robots.txt`, `/manifest.webmanifest`. Titles, descriptions and the title template per locale live under **Settings → Localization**; logos, favicon and the default OG image under **Settings → Brand**. ## Generated files - `app/robots.ts` → `/robots.txt`. Indexable: allow `/`, disallow admin (`/admin-internal`, `/root`), `/api/`, `/success`, `/coming-soon` (+ locale variants), plus the sitemap URL. Not indexable (setting off or maintenance): disallow everything. - `app/sitemap.ts` → `/sitemap.xml`. One entry per locale for home, about, portfolio, contact, every category that has published projects, and every published project — each with `xhtml:link hreflang` alternates and `x-default`. Empty while maintenance mode is on or indexing is disabled. - `app/manifest.ts` → `/manifest.webmanifest` (icons from Brand settings). ## Per-page metadata (`lib/metadata.ts`) - `buildAppMetadata()` — root layout: `metadataBase`, robots, verification, keywords, icons, manifest, OG (`og:locale` as `de_DE`/`en_US`/`ar_AR` + `alternateLocale`), Twitter. - `buildLocalizedMetadata({...})` — every public page: templated title, description (≤300 chars), canonical + hreflang alternates, robots, OG, Twitter. Options: `image` (page-specific share image), `noIndex`, `type: "article"`, `publishedTime`. - Portfolio project pages pass the project **cover** as OG image and `article` type. This is independent of the project's view mode (`GRID` / `STORY` / `CASE_STUDY`), so new view modes inherit full SEO automatically. - `/success` and `/coming-soon` are `noindex`. ## Structured data (JSON-LD) Rendered via `components/seo/json-ld.tsx` (server component; `<` is escaped). - Site layout: `WebSite` + publisher (`Person` or `Organization`) graph linked by `@id` (`buildSiteJsonLd`). - Project page: `CreativeWork` with url, headline, description, image, genre (category), keywords (service label, year), `datePublished`, author `@id`, client as `sourceOrganization` (`buildProjectJsonLd`). ## Slugs Categories and projects share `/portfolio/[slug]`; categories win at resolve time. The admin therefore rejects a project slug that equals an existing category slug and vice versa (`app/_admin/portfolio/actions.ts`). ## Operational checklist before launch 1. `NEXT_PUBLIC_SITE_URL` must be the public `https://` origin (canonical base). 2. Settings → Localization: site name + 50–160 char description in DE/EN/AR. 3. Settings → Brand: default OG image (1200×630) + favicon. 4. Settings → SEO: indexing on, verification codes, Person/Organization data. 5. Maintenance mode off. Verify `/robots.txt` and `/sitemap.xml` from the SEO page. 6. Submit the sitemap in Google Search Console / Bing Webmaster.