# SupplierDev — Backend / Web (CLAUDE.md)

> This file defines the architecture rules, naming conventions, and development workflow
> for the Next.js web application and Supabase backend.
> Follow these rules exactly. They exist to maintain parity with the iOS app.

---

## Product Context

**SupplierDev** is a BMW Supplier Development tool for engineers who visit supplier
manufacturing plants. Core use case: measure cycle times, track shift output,
manage improvement actions, compare QAF documents.

**Platforms**: This Next.js repo is both the web frontend AND the API/backend.
The iOS app (`KADi/ios-app`) consumes the same Supabase database.

---

## Handover Context (Adesso / Azure)

This repository is being prepared for handover to **Adesso** for an Azure migration.
Two things follow from that:

- The **iOS feature-parity rules** below apply to KADi's internal iOS team only.
  They are **not** a constraint on Adesso's porting work — Adesso may treat the
  web app as the single source of truth unless told otherwise.
- The app currently runs **single-tenant** (BMW pilot). The multi-tenant control
  plane / provisioning / owner layer was removed 2026-05-26. Do not reintroduce
  tenant-scoping assumptions without an ADR.
- Deployment targets: today **Vercel**; the `Dockerfile` + `docker-compose.yml`
  target **Azure Container Apps** (see `DEPLOYMENT.md`). Infrastructure-coupled
  pieces (Upstash Redis, Vercel Analytics, Sentry) are flagged in the tech stack.

For the full handover package see [`docs/vendor-handover/`](docs/vendor-handover/)
and [`MIGRATIONS.md`](MIGRATIONS.md).

---

## Tech Stack

- **Framework**: Next.js 16 App Router (React 19)
- **Database**: Supabase (PostgreSQL + Auth + Storage)
- **Styling**: Tailwind CSS v4 + shadcn/ui (Radix UI primitives)
- **Charts**: Recharts
- **Exports**: ExcelJS (read + write), PptxGenJS (PowerPoint), jsPDF (PDF)
- **Offline / PWA**: Dexie v4 (IndexedDB) + dexie-react-hooks, service worker `public/sw.js` (versioned at build by `scripts/inject-sw-version.cjs`). See `docs/OFFLINE_ARCHITECTURE.md`.
- **Rate limiting**: `@upstash/ratelimit` + `@upstash/redis` (fails open when unset). Azure migration must map this to Azure Cache for Redis.
- **Observability**: `@sentry/nextjs` + OpenTelemetry (`@vercel/otel`), structured logger in `lib/logger.ts`.
- **Font**: BMW Group TN Pro (body) + BMW Group TN Condensed Pro (headings) + JetBrains Mono (code) — see section below
- **Colors**: BMW Corporate Identity — see globals.css + section "BMW Color System" below

---

## Architecture

### File Structure
```
app/
  (auth)/          ← Login, signup, forgot/reset password pages
  auth/callback/   ← Supabase OAuth callback
  dashboard/       ← Visit list (main entry point)
  project/
    new/           ← Create visit
    [id]/          ← Visit detail + sub-pages
      edit/
      stopwatch/
      shift-output/
      workshop/
      qaf/
      export/
  account/         ← User profile
  management/      ← Cross-visit analytics
components/
  layout/          ← AppShell, AppHeader, UserMenu
  project/         ← Visit forms
  process-steps/   ← Station manager
  stopwatch/       ← Cycle time tool
  shift-output/    ← Shift tracking
  workshop/        ← Improvement actions
  qaf/             ← QAF comparison
  export/          ← Excel export
  management/      ← Analytics dashboard
  takt-diagram/    ← Charts
  account/         ← Profile form
lib/
  supabase/
    client.ts      ← Browser client (createBrowserClient)
    server.ts      ← Server client (createServerClient + cookies)
    proxy.ts       ← Middleware session refresh
```

### Server vs Client Components
- **Server components** (default): Data fetching, page layouts, auth checks
- **Client components** (`'use client'`): Interactive UI, form state, charts, stopwatch
- Rule: Push data fetching UP (server), interactivity DOWN (client)
- Never fetch data in client components if a server component can do it

### Data Fetching Pattern
```typescript
// Server component
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) redirect('/login')
const { data } = await supabase.from('projects').select('*').order('visit_date', { ascending: false })

// Pass to client component as props — never expose Supabase client to client components
// when avoidable
```

---

## Naming Conventions

### Files
- Components: `kebab-case.tsx` (e.g. `process-steps-manager.tsx`)
- Pages: `page.tsx` (Next.js convention)
- Route handlers: `route.ts`

### TypeScript
- Interfaces: PascalCase (e.g. `ProcessStep`, `CycleMeasurement`)
- Functions: camelCase (e.g. `avgCt`, `deleteStep`)
- Constants: camelCase or SCREAMING_SNAKE for true constants
- Props interfaces named `Props`

### Database field → TypeScript mapping
Always use the exact DB field name in TypeScript interfaces:
```typescript
interface Visit {
  id: string
  user_id: string
  supplier_name: string
  customer_takt_time_sec: number | null
  // ...
}
```

### Semantic Naming Alignment with iOS
When writing new code, prefer the semantic names that match iOS:
- `Visit` (not "Project") when naming new types/variables
- `Station` (not "ProcessStep") when writing display text
- `Measurement` (not "CycleMeasurement") in new components
- DB columns keep their existing names — this is about code semantics

---

## BMW Color System (aligned mit DCT Live-Export 22.05.2026)

> **Constitution v1.1 Amendment** — Primary war historisch `#0066B1` (Logo-Roundel),
> ist jetzt `#037493` (DCT-App-Petrol). Live-Export aus `dct.bmwgroup.net/home` zeigte
> dass interne BMW-Mitarbeiter Petrol sehen, nicht Marketing-Blau.
> Brain-Quelle: `05-Referenzen/bmw-ci-dct-2026-05-22.md`.

```
UI-Primary:      #037493  (DCT Petrol — App-Primary)
Primary-Hover:   #035970  (Petrol-Dark)
Primary-Tint:    #A8DFFF  (Active-Tab-BG, PROD-Badge)
Primary-Soft:    #E0F2FF  (Selected-Item-BG)

Logo-Only:       #0066B1  (BMW-Roundel-Blau — NUR in SVG, niemals UI!)

Text Primary:    #353A41
Text Muted:      #69707A
Border Subtle:   #C1C5CB
Border Faint:    #DCDEE1
Disabled BG:     #EFEFEF
Canvas:          #FFFFFF

Status-Red strong:   #F8BBD0  (Risiko hoch)
Status-Red soft:     #FCE4EC  (Risiko sehr hoch leichtere Stufe)
Status-Yellow:       #FFE082  (Risiko mittel)
Status-Grey:         #D7D8DA  (Risiko neutral)
Status-Green:        #C8E6C9  (Risiko niedrig / OK)
Destructive:         #D93025  (Kadi-v2-Extension, DCT hatte kein klares Error-Color)

Radius:          2px (DCT Industrial-Flat ueberall)
```

**Never** use hardcoded colors that aren't in this palette.
Use CSS variables from globals.css (`--primary`, `--border`, etc.) where possible.
`#0066B1` darf NUR in SVG-Files erscheinen (BMW-Roundel-Quadranten),
NIEMALS in `*.tsx` / `*.css` als UI-Color — `check:hardcoded-colors` blockt das.

**Ausnahme — QAF-Chart-Konstanten (KAR-840):** Die `--qaf-stand-*` / `--qaf-bucket-*`
Variablen in globals.css sind die key-stabilen Darstellungskonstanten des
V11-Referenz-Tools (STAND_COLORS/BUCKET_COLORS, Spec 3.10) und bewusst außerhalb
der DCT-Palette. Sie werden NUR in QAF-Vergleichs-Charts verwendet, ausschließlich
über die CSS-Vars (nie als lose Hex in `*.tsx`), und haben Dark-Varianten.

**Ausnahme — Wertstrom (VSM) Editor-Farben (Wertstrom P0, KAR-878):** Die
`--vsm-node-*` / `--vsm-edge*` / `--vsm-grid-*` / `--vsm-connect-preview`
Variablen in globals.css unterscheiden die 7 VSM-Node-Typen + Canvas-Chrome
im Wertstrom-Editor (`components/wertstrom/vsm-config.ts`, `vsm-editor.tsx`)
und sind bewusst außerhalb der DCT-Palette. Sie werden NUR im VSM-Editor
verwendet, ausschließlich über die CSS-Vars (nie als lose Hex in `*.tsx`),
und haben Dark-Varianten.

## Fonts (BMW Group TN)

```
Body / UI:   BMW Group TN Pro     (system-ui Fallback)
Headings:    BMW Group TN Condensed Pro
Mono:        JetBrains Mono / ui-monospace
```

**Lizenz**: BMW-Fonts duerfen NUR auf operator-managed hosting ausgeliefert werden.
- `public/fonts/BMW*.woff2` ist `.gitignore`d.
- Source-of-Truth: operator-managed asset store (not committed to this repository).
- Build-Time-Inject via `scripts/sync-bmw-fonts.sh` (predev + prebuild Hook).
- `check:bmw-fonts` blockt jeden Font-File im Git-Index.
- Fallback bei fehlenden Files: System-Stack via `@font-face` graceful-degradation.

---

## Feature Parity Rules

Every feature implemented in the web app MUST also be specified for iOS in PRODUCT_SPEC.md.
When you add a web feature:
1. Check if it's in PRODUCT_SPEC.md — if not, add it
2. Check if it affects the API contract — if so, update API_SPEC.md
3. Check if the UI flow is defined — if not, update UI_FLOWS.md

The iOS team should never be surprised by a web-only feature.

---

## API-First Principle

All data operations go through Supabase. No custom API routes unless:
- A 3rd party service requires a server-side proxy
- Complex business logic can't be expressed in PostgREST queries
- Sensitive credentials must be kept server-side

When Supabase direct access is insufficient, create a Next.js route handler:
`app/api/{resource}/route.ts`

---

## Development Commands

```bash
npm run dev           # Start dev server (Turbopack)
npm run build         # Production build (run before commits)
npm run typecheck     # TypeScript check (tsc --noEmit)
npm run lint          # ESLint
npm run format        # Prettier
npm run test          # Vitest unit/integration tests (single run)
npm run test:coverage # Vitest with v8 coverage
npm run check:portability  # Full portability gate (see below)
npm run new:module -- <name>  # Scaffold a new lib/ module (ADR-019)
```

`check:portability` runs all of: `check:profiles`, `check:forbidden`,
`check:boundaries`, `check:qaf-core-portability`, `check:openapi`, `check:csp`,
`check:secrets`, `check:hardcoded-colors`, `check:bmw-fonts`. **Before pushing**, run it in
strict mode so it fails on the first hit (CI-equivalent), not warn-only:

```bash
CHECK_FORBIDDEN_LEVEL=error npm run check:portability
```

**Always run `npm run build` and `npm run test` before considering a feature complete.**

---

## Supabase

- **Project ref**: `${SUPABASE_PROJECT_REF}` (operator-managed; the real value is held outside the repository — see `docs/foundation/environment-variables.md`)
- **Schema file**: `supabase/bootstrap/supabase-schema.sql` — source of truth for DB schema
- **Auth env var**: `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY` (not ANON_KEY)
- **Middleware**: Entry is `middleware.ts` (repo root); it delegates to `lib/supabase/proxy.ts` (`updateSession`), which uses `getClaims()` — do NOT use `getUser()` in middleware
- **RLS**: Every table has RLS. Test as an authenticated user only.

---

## Code Style

- No `var` — use `const`/`let`
- No `any` types
- Async/await over `.then()` chains
- Destructure where it improves readability
- No inline styles — Tailwind only
- No magic numbers — extract to named constants
- Error handling: handle `error` from Supabase queries, don't silently ignore

---

## Do Not

- Do not add features not in PRODUCT_SPEC.md without updating it first
- Do not add error handling for scenarios that can't happen
- Do not create helper abstractions for one-off logic
- Do not add comments to explain obvious code
- Do not use `router.refresh()` as a lazy alternative to proper state updates
  (only use it when server data genuinely needs re-validation)
- Do not store sensitive data (tokens, keys) in client-side state

---

## Safe Working Rules & Stop Conditions

Hard rules for any agent (or engineer) working in this repo:

- **No destructive git operations** on `main` or shared branches (no force-push,
  no history rewrite). Work on a feature branch; never overwrite the operator's
  uncommitted changes.
- **No code/file/dependency removal without a usage search** (`grep`, import
  check). Many root SQL files and `MO-*` folders are referenced by `MIGRATIONS.md`
  — do not move or delete them without updating that catalog.
- **No business-logic or schema change without evidence + tests.** RLS policies,
  SECURITY DEFINER RPCs, and migrations are high-risk — see the auto-loaded
  `supabase-migration-review` and `service-role-audit` skills.
- **Never print or commit real secrets.** `.env*` is gitignored; the service-role
  key is read only through `lib/supabase/privileged-env.ts`.

**Stop and ask a human** (flag in your summary, do not proceed autonomously) when:

- a SQL migration must be applied to a real database (apply order / prod state is
  operator-owned — see `MIGRATIONS.md`);
- a test fails and the root cause is unclear;
- documentation contradicts the code and you cannot tell which is correct;
- a change would alter authn/authz, RLS, or the public API contract;
- required secrets, env values, or access rights are missing;
- the production / deployment target is ambiguous.

---

## Documentation Rules

### CHANGELOG.md
- After EVERY completed task, add a new entry to CHANGELOG.md
- Format: `## YYYY-MM-DD – Feature-Name`, with bullet points of what changed/was created
- Newest entries on top

### TODO.md
- Mark completed items with ~~strikethrough~~ or remove them
- Add new open items you notice while developing
- Record open questions or decisions here

### Rules
- Do not create separate versioned documents
- Only change CLAUDE.md itself when architecture or conventions change
- Keep everything in ONE document per purpose (no CHANGELOG_v2.md etc.)

## Git Workflow

- Before `git checkout -b` for any feature branch, verify local main is in sync with origin/main and carries no operator side-commits. Run `git log --oneline origin/main..main` and confirm empty output. If non-empty, either push the side-work as its own PR or stash it before branching. Otherwise the squash-merge will bundle unrelated work under a single-purpose PR title (see PR #22 / follow-up #27 for the precedent).

## gstack (REQUIRED — global install)

**Before doing ANY work, verify gstack is installed:**

```bash
test -d ~/.claude/skills/gstack/bin && echo "GSTACK_OK" || echo "GSTACK_MISSING"
```

If GSTACK_MISSING: STOP. Do not proceed. Tell the user:

> gstack is required for all AI-assisted work in this repo.
> Install it:
> ```bash
> git clone --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack
> cd ~/.claude/skills/gstack && ./setup --team
> ```
> Then restart your AI coding tool.

Do not skip skills, ignore gstack errors, or work around missing gstack.

Using gstack skills: After install, skills like /qa, /ship, /review, /investigate,
and /browse are available. Use /browse for all web browsing.
Use ~/.claude/skills/gstack/... for gstack file paths (the global path).

> **Adesso note:** gstack is a public third-party tool (github.com/garrytan/gstack).
> It is a KADi-internal workflow requirement for AI-assisted edits, **not** a build
> or runtime dependency — `npm install`, `npm run build`, and the test suite do not
> need it. If your corporate GitHub policy blocks external clones, contact the
> operator for a pre-cloned tarball, or skip gstack and rely on the CI gates.


## Claude Code Setup (this repo)

This repo extends the always-loaded CLAUDE.md with on-demand components.
See `docs/foundation/claude-code-setup.md` for the full reference.

Architecture decisions: see `docs/adr/`. Per ADR 020, no customer-specific
exception lands without an ADR.

### Subagents (`.claude/agents/`)

- `architecture-reviewer`: read-only review subagent for import boundaries (rails doc, ADR-010, ADR-015). Invoke via `@architecture-reviewer` mention or via the `/review` orchestrator.
- `security-reviewer`: read-only review subagent for security baseline (ADR-017), CSP enforcement (ADR-018), no-customer-exception (ADR-020), the service-role intent register, and the RLS audit. Invoke via `@security-reviewer` mention. Never prints real secret values.
- `code-quality-reviewer`: read-only review subagent for TypeScript correctness, error handling, React / Next.js patterns, and test patterns. Invoke via `@code-quality-reviewer` mention. Hands off architectural-boundary and security findings to siblings.

### Slash skills (`.claude/skills/`, manual via `/name`)

- `/review`: project reviewer-suite orchestrator for KADi diff review. Dispatches `architecture-reviewer`, `security-reviewer`, and `code-quality-reviewer`, then synthesizes findings into one severity-ordered report.
- `/check`: fast project-health check (`npm run typecheck` + `npm run lint`). Auto-routable.
- `/check-full`: full project-health check (`npm run typecheck` + `npm run lint` + `npm run check:portability`). Auto-routable.

### Auto-loaded skills (`.claude/skills/`, scoped via `paths:`)

- `architecture-rails`: auto-loaded for boundary zones (`lib/customers/**`, `lib/*/index.ts` barrels, `app/api/v1/**`, `openapi/v1/**`, `eslint.config.mjs`, `config/profiles/**`). Reference content; does not run commands.
- `supabase-migration-review`: auto-loaded for Supabase zones (`supabase/bootstrap/supabase-schema.sql`, `supabase/migrations/supabase-migration-*.sql`, `supabase-audit-*.sql`, `lib/supabase/**`, `docs/foundation/rls-*.md`, `docs/foundation/service-role-intent-register.md`). Reference content; does not run commands.
- `service-role-audit`: auto-loaded for `createAdminClient` register zones (`lib/supabase/admin.ts`, `lib/supabase/privileged-env.ts`, `docs/foundation/service-role-intent-register.md`, `app/api/admin/**`, `app/api/demo/**`). Reference content; does not run commands.

### Hooks (`.claude/hooks/`)

- `check-gstack.sh`: wired to `PreToolUse: Skill`. Guards skill invocation behavior and allows repo-local skills listed in `REPO_LOCAL_SKILLS`.
- `warn-sensitive-paths.sh`: wired to `PreToolUse: Edit|Write`. Warns before edits to sensitive paths.
- `block-destructive-bash.sh`: wired to `PreToolUse: Bash`. Blocks destructive Bash patterns configured in `.claude/settings.json`.

### Permissions (`.claude/settings.json`)

- `permissions.allow` — approved git/gh inspection commands + verified read-only validation commands
- `permissions.deny` — sensitive paths (`.env*` via Read/Edit/Write) + destructive bash patterns
- User-local broader allows continue to live in `.claude/settings.local.json` (gitignored)


<!-- BEGIN QAF-V2-ARIA-PACK -->
# SupplierPulse QAF V2

## Quelle der Wahrheit

Verwende diese Priorität:

1. aktueller ausführbarer Repository-Code
2. Tests, Datenbankschema, Migrationen und CI-Gates
3. offizielle QAF-Dateien, Vorlagen und QAF User Guide
4. `docs/qaf-v2/`
5. historische Snapshots und HTML-Referenzen

Bei einem Widerspruch ist der Unterschied zu dokumentieren. Fachliche Primärquellen dürfen nicht still durch allgemeines Wissen ersetzt werden.

## Nicht verhandelbare Regeln

- Der QAF-Vergleich bleibt deterministisch.
- LLMs berechnen keine QAF-Zahlen, Deltas, Formeln, Einheiten, Währungen oder verbindlichen Mappings.
- Die UI berechnet keine Domainwerte.
- Original-QAFs werden niemals überschrieben.
- Keine Zelle, Formel, Tabelle, ausgeblendete Struktur oder unbekannte Information darf still verschwinden.
- `empty_verified`, `not_computed`, `not_applicable`, `blocked` und `failed` sind getrennte Zustände.
- Eine Preisbrücke wird nur dargestellt, wenn ihre Reconciliation innerhalb der festgelegten Toleranz schließt.
- Kein Restbalken darf eine ungeklärte Differenz kaschieren.
- Jede quantitative Aussage benötigt Difference IDs und Source References bis Datei, Blatt, Zelle, Formel und Wertzustand.
- Keine V1-Funktion wird ohne Paritätsnachweis entfernt.
- Keine parallele kanonische Feldregistry.
- Der fachliche QAF-Kern bleibt portabel: keine Datenbankabfrage, kein
  Supabase-Client, kein Cloud-SDK und keine Framework-Laufzeit in der
  deterministischen QAF-Domainlogik. `check:qaf-core-portability` bewacht das
  für die im Skript benannten Pfade (`lib/qaf-differences`, `lib/qaf`,
  `lib/qaf-value-stream`, `lib/qaf-parser.ts`, `lib/simvsm-import`) und friert
  den Bestand in `scripts/qaf-core-portability-baseline.json` ein.
  **Nicht abgedeckt** und deshalb Handarbeit: `app/**` — insbesondere
  `app/qaf-differences/actions.ts`, das Fachlogik und Datenzugriff in einer
  `'use server'`-Datei mischt. Der Kopf des Gate-Skripts führt vier weitere
  Grenzen (berechneter Modulname, Zugriff ohne Importsatz, Indirektion über ein
  Modul außerhalb des Scopes, Fehlalarm bei Import-Text in Strings). Ein grüner
  Lauf heißt „keine versehentliche neue Kopplung in diesen Pfaden", nicht
  „das Repository ist portabel".
- Keine vertraulichen Originaldateien in Git.
- Kein Test wird gelöscht oder abgeschwächt, nur um einen Gate grün zu machen.
- Jeder Loop endet mit Tests, Determinismusprüfung, unabhängigem Review und Handover.
- Arbeite autonom weiter, außer ein dokumentierter externer Blocker erfüllt die Stop-Regeln.

## Arbeitsbeginn nach Loop 0 und Loop 1

Lies zuerst:

1. `docs/qaf-v2/00_START_HERE_AFTER_LOOP_1.md`
2. `docs/qaf-v2/baseline-inputs/06_Autonomous_Loop_Roadmap_v1.0.md`
3. `docs/qaf-v2/baseline-inputs/07_Requirements_Traceability_Matrix_v1.0.md`
4. `docs/qaf-v2/operating-model/AGENT_OPERATING_MODEL.md`
5. den neuesten Bericht unter `docs/qaf-v2/loop-reports/`
6. die tatsächlichen Audit-Artefakte unter `audit/`

Nutze die projektbezogenen Skills unter `.claude/skills/` und die Subagenten unter `.claude/agents/`.

## Lokale Referenzen

Reale QAFs, User Guide, BMW Design System und HTML-Referenzen liegen unter:

`/.local/qaf-reference/`

Dieser Pfad ist gitignoriert. Inhalte dürfen nur anonymisiert oder synthetisch in Tests übernommen werden.
<!-- END QAF-V2-ARIA-PACK -->

## AUTONOMOUS MERGE AND DEPLOY POLICY

> Dauerhafte Anweisung des Product Owners vom 2026-08-04 für dieses Repository.
> Ergänzt die bestehenden Regeln, ersetzt keine davon.

**Ein Pull Request allein gilt nicht als abgeschlossener Auftrag.** Verantwortet
wird der vollständige Ablauf: analysieren, implementieren, testen, unabhängig
reviewen, Fehler beheben, committen, pushen, PR erstellen und pflegen, CI
überwachen, Review-Kommentare bearbeiten, nach bestandenen Gates mergen, den
vorhandenen Deployment-Prozess ausführen oder überwachen, Smoke-Tests und
Post-Deployment-Prüfungen durchführen, bei kritischen Fehlern sicher zurückrollen,
Abschlussbericht erzeugen und anschließend mit dem nächsten freigegebenen Loop
fortfahren.

### Merge ist erlaubt, wenn alles davon zutrifft

- alle verbindlichen Tests grün
- Typecheck, Lint und Build grün
- Security- und Portability-Gates grün
- Determinismusprüfungen bestanden
- Reconciliation und Provenienz geprüft
- keine offenen Review-Blocker
- keine bekannte Regression
- Migration und Rollback dokumentiert
- keine unbeabsichtigten Dateien enthalten
- keine Konflikte
- alle vorgeschriebenen GitHub-Checks und Reviews erfüllt

### Unverhandelbar

- Branch-Protection-, Compliance- oder Freigaberegeln werden weder umgangen noch
  abgeschwächt.
- Kein Force-Push auf `main` oder `master`.
- Kein Administrations-Override, um Pflichtprüfungen zu überspringen.
- Keine Tests löschen, abschwächen oder durch stilles Catchen grün machen.

### Deployment

Ausschließlich über die vorhandene Infrastruktur des Repositorys. Nach jedem
erfolgreichen Merge: Deployment-Workflow vollständig beobachten, zuerst Preview
oder Staging verwenden sofern vorhanden, Smoke- und E2E-Tests ausführen, danach
Produktion sofern bestehende Regeln und Berechtigungen das erlauben, die konkret
geänderte Funktion im Zielsystem prüfen, Logs, Healthchecks und Fehlerraten
kontrollieren, sowie Deployment-ID, Commit, Umgebung und Prüfergebnisse
dokumentieren.

Bei kritischer Regression: Rollout stoppen, letzte stabile Version wiederherstellen,
keine produktiven Daten löschen, Datenbank nur mit geprüfter Rückwärtsstrategie
zurückrollen, Healthchecks danach erneut ausführen, Ursache dokumentieren und
fachlich korrekt beheben.

### Keine Rückfrage mehr für

Branch, Commit, Push, Pull Request, Review-Bearbeitung, Merge, Deployment,
Smoke-Tests, sicheren Rollback, Start des nächsten Loops.

### Rückfrage weiterhin erforderlich bei

- fehlender technischer Berechtigung
- zwingender externer Freigabe
- irreversibler Migration ohne sichere Rückwärtsstrategie
- realem Risiko für produktive Daten
- nicht auflösbarem fachlichem Konflikt
- einer echten Produktentscheidung mit mehreren fachlich unterschiedlichen Ergebnissen

### Ergänzung vom 2026-08-04 abends (Product Owner)

**Blocker-Klassifikation ist Pflicht.** Jeder Blocker wird eingeordnet als:

| Klasse | Wirkung |
| --- | --- |
| `global_blocker` | stoppt das Gesamtprogramm. Nur echte Fälle. |
| `loop_local_blocker` | stoppt diesen Loop, nicht die anderen. |
| `deployment_only_blocker` | Bauen, Testen, Reviewen, Mergen laufen weiter; nur das Anwenden auf Produktion wartet. |
| `external_validation_pending` | eine Aussage bleibt offen, die Arbeit nicht. |

Ein fehlender Produktions-Dump oder fehlender Produktionszugang ist **kein**
globaler Blocker. Fehlt eine externe Voraussetzung, wird alles Übrige fertig
gebaut, der offene Punkt benannt und mit dem nächsten nicht blockierten Loop
weitergemacht.

**Meldungen an den Product Owner nur bei:** unlösbarer fachlicher
Produktentscheidung · Risiko für produktive Daten · irreversibler Migration ohne
Rollback · fehlender Berechtigung, wenn keine unabhängige Arbeit mehr möglich
ist · vollständig abgeschlossenem, gemergtem und verifiziertem Meilenstein ·
finalem Programmabschluss. Sonst still weiterarbeiten.

**Zugriffsmodell.** Die Trennung zwischen `open_business_data_model` und
`protected_security_control_plane` ist verbindlich und in
`supabase/migrations/supabase-migration-internal-open-access-model.sql`
umgesetzt; die Zuordnung jeder Tabelle steht nach dem Anwenden in
`public.rls_access_class`. Das offene Modell (`USING (true)`) gilt **nur** für
Fachdaten. Rollen, Rechte, Benutzerverwaltung, Einladungen, administrative und
sicherheitsrelevante Konfiguration, Protokolle, technische Konten und
Credential-Metadaten bleiben beim Schreiben geschützt. Kein Nutzer darf die
eigene oder eine fremde Rolle ändern; Protokolle sind für normale Nutzer
append-only; `anon` bekommt nirgends Zugriff. Runbook:
`docs/runbooks/internal-access-model-rollout.md`.

**Scope-Grenze QAF-V2.** G60 und Multi-QAF sind `deferred_by_product_owner`:
nicht erweitern, nicht refactoren, nicht als Exit-Kriterium verwenden, nicht als
neue Fixture-Familie aufbauen. Bestehende Funktionalität darf sich dabei nicht
verschlechtern.
