Refresh HiveGrid Cloud reference snapshot

This commit is contained in:
david committed 2026-08-03 15:31:14 +02:00
1 parent 5e99e14772
commit 7f88026f79
5955 files changed
+1177325 -188362

No files matched your search

@@ -0,0 +1,169 @@
---
name: plan-ticket
description: Create a complete implementation plan for a HiveGrid ticket from AGENTS.md,
its ticket doc, linked planning sources, live Plane context, and current git
state. Use when a user provides a HiveGrid ticket ID or asks to analyze,
scope, sequence, or plan a ticket without implementing it yet.
---
# Plan Ticket
Plan only. Do not edit code, ticket docs, Plane, or external systems. Stop after
the plan and ask for approval before implementation.
## 1. Resolve the ticket
Require a ticket ID such as `AK-P3`. Then:
1. Read `AGENTS.md` completely enough to apply the current rules relevant to the
ticket.
2. Read `.planning/ticket-docs/README.md` and
`.planning/ticket-docs/<TICKET-ID>.md` completely. Stop if the ticket doc is
missing.
3. Follow only the granular sources linked by the ticket doc. Give
`.planning/ENTITY-MODEL.md` priority where `AGENTS.md` requires it.
4. Read the current branch, recent commits, and diff against `origin/main` to
establish what is already implemented.
5. Pull the live Plane ticket, comments, `blocked-by`, and `blocks` using
`.planning/plane-sync/fetch_ticket.py` or the available Plane integration. If
Plane is unavailable, continue from Git and the ticket doc but state that
evidence gap.
6. Never infer completion from a status badge alone.
## 2. Audit dependencies with three sources
Check both dependency directions. For every blocker or consumer, compare:
1. Plane state and all relevant comments.
2. Git/code reality, including merged commits and implementation notes.
3. The blocker and dependent ticket docs.
Decide whether the exact contract needed by this ticket exists. When sources
conflict, apply the precedence rules in `AGENTS.md`; otherwise expose the
conflict instead of inventing a resolution. For cross-cutting contracts,
schemas, shared services, or `blocks` consumers, include the dependent
verification work in the plan.
## 3. Decide the delivery strategy
Classify every open item as:
- `selbst machbar`
- `extern/blockiert`
- `bewusst v2/out-of-scope`
Recommend `jetzt bauen`, `teilweise bauen`, or `zurückstellen`, with a reason.
Do not pull work forward from later tickets.
For UI-heavy work, read `.planning/INTERIM-UI-PLAYBOOK.md` and
`.planning/INTERIM-UI-DESIGN-STANDARDS.md`. Missing final design does not
automatically block the ticket: plan the AD-28 interim screen when the ticket
permits it, and track final visual work as `design-nachzug`. Use finished
Automation/Forms screens and existing Settings Subscription/Billing interim
screens as style references.
If the ticket specifically integrates new or changed Subframe pages, also use
`$subframe-einbinden` and incorporate its inventory and integration
requirements.
## 4. Produce the plan in this order
1. Plain-language introduction
2. Current state and DoD percentage
3. Dependencies and delivery strategy
4. DoD-to-slices mapping
5. Ordered build plan by slice
6. Verification gates before commit
7. Open questions and risks
8. Reminder for post-build ticket-doc + Plane updates
## 5. Map every DoD item
For every DoD item, state:
- **Status:** done, open, or blocked.
- **Fertigkeitskriterium:** what must be true for full completion.
- **Proof:** the code path, test, screen, external artifact, or Plane evidence
that proves it.
- **Zählt NICHT als fertig:** which partial implementation would be
insufficient.
- **Slice:** where the work and verification happen.
Cross-check each DoD item against `Was wir bauen`, `Benötigte Screens`,
technical building blocks, Plane comments, and design notes. Count only fully
satisfied points. Report `% = completed DoD points / total DoD points`,
separating blocked work from work the developer can still do.
## 6. Make each slice executable
For each slice, name concrete files and include all applicable constraints:
- Loader/action builds the view model; UI receives VMs and callbacks.
- No `@prisma/client` or `~/db` in `packages/ui-app/**`.
- No direct `packages/ui-subframe` import from routes.
- No `useLoaderData` inside `packages/ui-app/**`.
- Reuse audit, activity, notifications, search, permissions, tenant scope, and
other cross-cutting services from `AGENTS.md`.
- Use i18n keys and the existing clear-text error/state patterns.
- For UI, include interim/final visual state, smoke, hot-swap, and
visual-baseline work as required.
- For schema work, use a module schema, develop with `prisma db push`, and plan
the current pre-merge migration/parity gates from `docs/AGENT-CHECKLIST.md`
without guessing around AD-21 timing.
Call out central registries whenever a slice adds or changes their inputs:
- Tenant-scoped Prisma model: tenant model registry plus ordering/tests.
- Workspace package subpath export: explicit Vitest alias plus consumer suites.
- Feature key: entitlements feature, blueprint, plan, and key-list tests.
- Permission key: permission seed, defaults, scope display, and de/en strings.
- Sidebar/navigation ID: UI registry, sidebar tests, and UI inventory mapping.
- UI text: de/en translations and i18n gates.
- Prisma schema: migration parity and the RLS live migration-chain gate.
## 7. Define verification before commit and push
Derive exact commands from `docs/AGENT-CHECKLIST.md`, the affected workspaces,
and `.gitea/workflows/ci.yml`. Include:
- typecheck, lint, and targeted tests for every affected package
- existing consumer suites for shared files, not only new tests
- applicable `verify:*` registry, i18n, RLS, migration, bundle, or Docker gates
- seed idempotency and browser/staging proof when the ticket requires them
- the no-US-provider and architectural anti-pattern checks when relevant
Do not schedule external writes, pushes, Plane changes, or Done transitions
without explicit authorization.
## 8. Include the post-build audit reminder
Before any completion report or Done-state recommendation, perform a
**Ticket-Abschluss-Audit**:
1. Re-read the ticket doc and current Plane comments.
2. Compare code state against every DoD item, required screen, and technical
building block.
3. Separate remaining work into `selbst machbar`, `extern/blockiert`, and
`bewusst v2`.
4. Count percentage only from fully satisfied DoD points. Partial backend-only
or UI-only work does not count as a full DoD point.
5. If a design ticket such as `D-*` is referenced, state whether its delta is
integrated, replaced by a valid interim baseline, or still blocking.
6. Update the ticket doc with date, proof, DoD checkboxes, and percentage before
any Plane completion action.
7. Mirror the result to Plane only with the required identity check and explicit
authorization; set Done only at 100% DoD.
8. If an interim screen was created, offer the optional David handover described
in `.planning/INTERIM-HANDOVER-GUIDE.md` instead of creating it silently.
End the response after the plan and ask whether it should be approved or
adjusted.
## Mandatory constraints
- Follow `AGENTS.md` strictly.
- Stay in ticket scope.
- Keep generated Subframe app chrome out of app screen components.
- Mark out-of-scope ideas explicitly as
`💡 Vorschlag (außerhalb Ticket-Scope): ...`.
- If a source is ambiguous, stop and ask instead of inventing.
@@ -0,0 +1,4 @@
interface:
display_name: "Ticket planen"
short_description: "HiveGrid-Tickets vollständig und belastbar planen"
default_prompt: "Use $plan-ticket to create a complete implementation plan for a HiveGrid ticket."
@@ -0,0 +1,179 @@
---
name: subframe-einbinden
description: Integrate new or changed Subframe pages and David design deltas into HiveGrid
through a screen inventory, Soll/Ist comparison, loader/view-model boundaries,
demo data, documentation, tests, and staging verification. Use when a user
asks to pull, compare, implement, update, or finish Subframe screens, pages,
flows, or a tracked design-nachzug.
---
# Subframe einbinden
Integrate Subframe design artifacts into the existing HiveGrid application.
Treat exported pages as design input, not drop-in application code.
## 1. Read the current contracts
Read before planning or changing code:
1. `AGENTS.md` and the relevant ticket doc.
2. `.planning/SUBFRAME-FLOW-INVENTAR.md` for the current flow/page integration
state.
3. `.planning/INTERIM-UI-PLAYBOOK.md` for app-shell, scrolling, local-kit,
layer, and tracking rules.
4. `.planning/INTERIM-UI-DESIGN-STANDARDS.md` for spacing, controls, dialogs,
states, and copy.
5. `.planning/INTERIM-HANDOVER-GUIDE.md` only when an interim-to-David handover
is in scope or must be offered.
If a Subframe MCP or product-specific design skill is available, load its
required instructions before calling it. Keep this HiveGrid workflow
authoritative for repository integration.
## 2. Establish an isolated branch
Start from current `origin/main` with the repository session/worktree helper.
Keep one flow, or one deliberately bounded flow subset, per branch and PR.
Preserve unrelated dirty worktrees.
Do not push, write Plane, or mutate Subframe without the user's authorization.
## 3. Inventory the Subframe target
Remember that `.subframe/sync.json` and component sync cover components,
layouts, and theme under `apps/web/app/ui`; they do not import complete pages or
application wiring.
Use the available Subframe integration in this order:
1. Call `list_flows`.
2. Call `get_flow_info` for the selected flow and page inventory.
3. Call `get_page_info` for each relevant page individually.
4. Exclude pages explicitly marked `_backlog_` unless the user includes them.
5. Record each screen's visible fields, filters, actions, states, dialogs,
navigation, and responsive variants.
Use project `f023064a5ca0` only when it remains the configured project in
`.subframe/sync.json`; otherwise use the current configured project. Avoid
loading huge page exports wholesale during inventory when a structural/text
extraction is sufficient.
## 4. Build the Soll/Ist delta
Inspect existing routes, loaders/actions, screens, view models, services,
permissions, Prisma models, tests, demo data, and current ticket ownership.
For each design page, classify:
- already integrated and current
- visual delta only
- needs loader/view-model/route-operation support
- lacks backend capability and must remain an explicit rest delta
- backlog or out of scope
Never invent backend behavior to make a design control appear functional. Wire
every visible action to an authorized capability, remove it, or render it
disabled with a documented reason. Respect ticket ownership and dependency
boundaries.
Before implementation, present the per-screen Soll/Ist delta, affected
files/layers, test plan, and remaining unsupported design delta. Ask for
approval when the user has requested planning or the implementation scope is not
already explicit.
## 5. Integrate behind the application boundary
Place app-chrome-free screens under `apps/web/app/components/screens/<domain>/`,
with dialogs in a local `dialogs/` folder when useful. Follow these rules:
- Routes own `useLoaderData`, `useSubmit`, fetchers, CSRF handling, redirects,
and loader/action wiring.
- Screens receive view models and action callbacks as props.
- Never nest `~/ui/layouts/DefaultPageLayout` or another generated
sidebar/header inside the HiveGrid app shell.
- Never import `packages/ui-subframe` directly from routes.
- Never import Prisma or `~/db` into `packages/ui-app/**`.
- Preserve host-aware paths for admin, app, and portal surfaces.
- Format dates and times through HiveGrid locale helpers with the configured
application timezone.
- Put every user-facing string in de/en i18n files; edit translation JSON
surgically.
- Keep rendering deterministic: no render-time `Math.random()`, `Date.now()`, or
unscoped locale formatting.
Use existing Automation and Forms screens plus Settings Subscription/Billing
interim screens as implementation references. Verify actual local component APIs
under `apps/web/app/ui/**`; cloud exports may use different props.
## 6. Apply the known Subframe footguns
1. **Document flow:** Remove page-export roots that combine
`h-full`/`overflow-hidden` with `basis-0`/inner `overflow-y-auto` where they
collapse inside the app shell. Register new screens in
`subframe-layout-boundary.test.ts`.
2. **Single app shell:** Keep sidebar, header, and breadcrumbs owned by HiveGrid
routes/layouts.
3. **Local kit first:** Read local `SearchInput`, table, badge, dropdown, and
dialog APIs instead of trusting cloud-export props.
4. **Title contract:** Return `data.title` and the route `meta` needed by
breadcrumbs and the browser tab.
5. **Timezone:** Use `useLocaleFormatters()` or the canonical server formatter.
6. **i18n:** Add de and en keys without JSON round-tripping or `defaultValue`
workarounds.
7. **Host-aware navigation:** Derive redirects/links from the current surface or
use the canonical path helper.
8. **No dead controls:** Wire, remove, or explicitly disable every exported
placeholder handler.
9. **Schema changes:** Keep changes additive and module-scoped; follow the
current AD-21 and pre-merge migration gates in `docs/AGENT-CHECKLIST.md`.
Treat `.planning/INTERIM-UI-PLAYBOOK.md` as the maintained source for newer
footguns.
## 7. Provide representative demo data
When the integrated screens depend on demo states, update
`scripts/seed-hivegrid-demo.ts` with deterministic IDs, `isDemoData: true`, and
idempotent upserts. Cover relevant populated, empty, warning, and error states.
Run the seed twice against the approved disposable local database and prove the
second run is stable.
Do not expand seed or schema scope merely to imitate unsupported design
behavior.
## 8. Update tracking and documentation
In the same implementation change:
- Update `.planning/SUBFRAME-FLOW-INVENTAR.md` with page count, status, date,
integrated delta, and explicit rest delta.
- Update the owning ticket doc with date, proof, DoD progress, and design
follow-up state.
- Add dependency-aware cross-reference notes to affected owner tickets when
required by `AGENTS.md`.
- Record reusable new footguns in `.planning/INTERIM-UI-PLAYBOOK.md`.
- Keep `/planning` authoritative for `design-nachzug`; Plane mirrors it only
after identity verification and authorization.
- Offer, but do not silently create, the David handover artifacts described in
`.planning/INTERIM-HANDOVER-GUIDE.md` when an interim screen was added.
## 9. Verify end to end
Run the applicable gates from `docs/AGENT-CHECKLIST.md`, including:
- affected workspace typechecks and lint
- targeted screen, route, loader/action, and view-model tests
- `subframe-layout-boundary.test.ts`
- i18n and hardcoded-string gates
- smoke, hot-swap, accessibility, and visual-baseline checks required by the
ticket
- seed idempotency when demo data changed
- migration/RLS gates when schema changed
After an authorized merge and deployment, verify the affected staging screens in
a real browser: content must be visibly rendered, breadcrumbs and titles must be
correct, actions must work, responsive states must hold, and the console must be
free of hydration errors.
Report what was integrated and list every remaining design/backend delta
explicitly.
@@ -0,0 +1,4 @@
interface:
display_name: "Subframe einbinden"
short_description: "Subframe-Screens sicher in HiveGrid integrieren"
default_prompt: "Use $subframe-einbinden to integrate the latest Subframe pages for a HiveGrid flow."
@@ -0,0 +1,10 @@
---
name: plan-ticket
description: Create an implementation plan for a HiveGrid ticket without changing code. Use when planning, scoping, sequencing, or analyzing a ticket before implementation.
---
# Plan Ticket
Read and follow `../../../.agents/skills/plan-ticket/SKILL.md` completely
before acting. Treat that file as the canonical workflow. If it is unavailable,
stop and report the missing workflow.
@@ -0,0 +1,10 @@
---
name: subframe-einbinden
description: Integrate Subframe pages or design deltas into HiveGrid. Use when pulling, comparing, implementing, updating, or finishing Subframe screens and tracked design follow-ups.
---
# Subframe einbinden
Read and follow `../../../.agents/skills/subframe-einbinden/SKILL.md` completely
before acting. Treat that file as the canonical workflow. If it is unavailable,
stop and report the missing workflow.
@@ -7,6 +7,8 @@
.vscode
.agents
.planning
/.gitea
/.github
cli-tokens
node_modules
**/node_modules
@@ -21,6 +23,18 @@ pnpm-store
# Repository docs and generated verification artifacts are not Docker build inputs.
/docs
/secrets
/tests
/e2e
**/*.test.ts
**/*.test.tsx
**/*.test.mjs
**/*.test.js
**/*.spec.ts
/scripts/ci/deploy-buildkitd.toml
/scripts/ci/verify-deploy-buildkit-config.mjs
/scripts/verify-gitea-ci-workflow.mjs
/scripts/verify-gitea-deploy-workflow.mjs
.cache
**/.cache
.eslintcache
@@ -52,6 +66,8 @@ blob-report
public/build
/build
/apps/*/build
/apps/*/build-portal
/apps/*/build-sourcemaps
apps/*/dist
packages/*/dist
@@ -0,0 +1,9 @@
# EditorConfig — https://editorconfig.org
root = true
# Prisma's generated client contains trailing whitespace in its raw output.
# The repo must store exactly what `prisma generate` emits so regeneration is
# a no-op — editors must never trim/reformat these files on save.
[packages/db/generated/**]
trim_trailing_whitespace = false
insert_final_newline = unset
@@ -6,7 +6,7 @@
# BRAND_LEGAL_IMPRINT_URL=https://acme.example/imprint
# BRAND_LEGAL_PRIVACY_URL=https://acme.example/privacy
# BRAND_LEGAL_TERMS_URL=https://acme.example/terms
# BRAND_LOGO_URL=/android-chrome-512x512.png
# BRAND_LOGO_URL=https://hivegrid.de/hivegrid-logo.png
# BRAND_FAVICON_URL=/favicon.ico
# BRAND_MAIL_PRIMARY=#2563eb
# BRAND_MAIL_PRIMARY_TEXT=#ffffff
@@ -16,15 +16,40 @@
# Core
APP_NAME=HiveGrid
# DATABASE_URL: pooled connection for application traffic. Point at PgBouncer
# on port 6432 in environments where the pooler is deployed and append
# `?pgbouncer=true&connection_limit=10` so Prisma disables prepared-statement
# caching (transaction-mode pooling cannot keep them). DIRECT_URL (below) is
# the unpooled connection used by `prisma migrate`. See docs/ops/pgbouncer.md.
DATABASE_URL="postgres://user:pass@localhost:6432/hivegrid?pgbouncer=true&connection_limit=10"
# on port 6432 in environments where the pooler is deployed (staging/prod).
# PrismaPg uses an explicit node-postgres pool; URL query parameters such as
# `connection_limit` do not configure it. DIRECT_URL (below) remains unpooled
# for migrations.
# The default below is the LOCAL one: `pnpm dev:services` starts Postgres on
# 5432 with these credentials and no pooler in front of it, so dev points
# straight at the database. 127.0.0.1 rather than localhost on purpose — on
# Windows localhost resolves to ::1 first, while the container publishes on
# IPv4 only.
DATABASE_URL="postgres://hivegrid:hivegrid@127.0.0.1:5432/hivegrid"
# Hard per-process limits for both primary and read-replica pools.
DATABASE_POOL_MAX=10
DATABASE_POOL_IDLE_TIMEOUT_MS=10000
DATABASE_POOL_CONNECTION_TIMEOUT_MS=5000
# Local development can run before the RLS cutover migration. Production
# defaults to `required` even when this value is omitted.
RLS_RUNTIME_MODE=off
# Enabled worker processes default their readiness check to hivegrid_worker.
DATABASE_RUNTIME_ROLE=hivegrid_app
# The web image defaults to the core surface in local development. Set this
# explicitly on deployed web resources; the portal container uses `portal`.
# WEB_RUNTIME_SURFACE=core
# SESSION_SECRET signs the session cookie. Min 32 bytes of entropy recommended (openssl rand -hex 32).
SESSION_SECRET=
# CRYPTO_SECRET is the AES key for stored workflow credentials. Use a SEPARATE secret from SESSION_SECRET.
# The portal runtime owns a separate cookie-signing boundary. Never configure
# this key on the core web resource.
# PORTAL_SESSION_SECRET=
# AUDIT_CHAIN_SECRET authenticates AuditEvent hashes and retention checkpoints. Min 32 bytes; never rotate without a documented chain transition.
AUDIT_CHAIN_SECRET=
# CRYPTO_SECRET is the shared tenant-envelope AES key used by web/API and worker-mail. Use a SEPARATE secret from SESSION_SECRET and the exact same value on hivegrid-web and worker-mail.
CRYPTO_SECRET=
# Dedicated platform-admin integration envelope key. Use different random values
# in staging and production; never reuse CRYPTO_SECRET or SESSION_SECRET.
ADMIN_CONNECTION_MASTER_KEY=
# Local dev: include the vite port so cross-host redirects (login -> app/admin host)
# keep :3000 — routing derives app.localhost:3000 etc. and hostMatches tolerates it.
APP_BASE_DOMAIN=localhost:3000
@@ -33,6 +58,7 @@ WEB_APP_HOST=app.localhost:3000
# APP_URL=http://app.localhost:3000
ADMIN_APP_HOST=admin.localhost:3000
API_HOST=api.localhost:3000
PORTAL_APP_HOST=portal.localhost:3000
# MCP runs as its own public connector host, not below app/api.
MCP_HOST=0.0.0.0
MCP_PORT=8080
@@ -62,11 +88,40 @@ API_KEY_HASH_SECRET=
# SEED_DEMO_DATA=true
# DEMO_USER is read only when NODE_ENV=development.
# DEMO_USER=admin@email.com:password
# `pnpm dev:local` enforces this exact local-only admin fallback allowlist.
# ADMIN_FALLBACK_LOGIN_ENABLED=true
# ADMIN_FALLBACK_LOGIN_EMAILS=admin@email.com
# Production seed bootstrap credentials. Required for `NODE_ENV=production pnpm seed`.
# They never override the canonical local credentials.
# SEED_ADMIN_EMAIL=admin@example.com
# SEED_ADMIN_PASSWORD=replace-with-production-bootstrap-password
# WEBHOOKS_URL=https://...ngrok-free.app
# Aircall Technology Partner OAuth (optional). Use the fixed public app callback
# and API webhook URL registered for the same staging/production environment.
# AIRCALL_CLIENT_ID=
# AIRCALL_CLIENT_SECRET=
# AIRCALL_REDIRECT_URI=http://app.localhost:3000/integrations/aircall/oauth/callback
# AIRCALL_WEBHOOK_URL=https://...ngrok-free.app/v1/webhooks/telephony/aircall
# HALLOPETRA_WEBHOOK_URL=https://...ngrok-free.app/v1/webhooks/telephony/hallopetra
# KWP OAuth2/PKCE (optional). The callback URI is derived from APP_PROTOCOL and
# WEB_APP_HOST; do not configure a separate redirect key.
# KWP_OAUTH_CLIENT_ID=
# KWP_OAUTH_CLIENT_SECRET=
# KWP_OAUTH_SCOPES=
# KWP_CUSTOMER_CODE=
# KWP_OIDC_ISSUER=
# KWP_HIVEGRID_TENANT_ID=
# Deprecated and ignored by new connections; choose the bnWin mandant in the setup flow.
# KWP_MANDANT=
# Web Push (VAPID). Production web requires the public key and worker-webhook
# requires the complete stable pair; never copy the private key into browser code.
# WEB_PUSH_VAPID_SUBJECT=mailto:ops@hivegrid.de
# WEB_PUSH_VAPID_PUBLIC_KEY=
# WEB_PUSH_VAPID_PRIVATE_KEY=
# S3-compatible storage. HiveGrid prod/staging nutzt Hetzner Object Storage (ADR-009),
# Endpoint-Format z.B. https://nbg1.your-objectstorage.com (S3-API identisch; ebenso nutzbar: Wasabi, Backblaze B2, MinIO, AWS S3).
# Werte gehoeren in die Coolify-Secrets je Umgebung, nicht ins Repo. Leave STORAGE_ENDPOINT empty to use local filesystem (STORAGE_LOCAL_ROOT).
@@ -77,6 +132,20 @@ STORAGE_ACCESS_KEY_ID=
STORAGE_SECRET_ACCESS_KEY=
STORAGE_SESSION_TOKEN=
STORAGE_PUBLIC_BASE_URL=
# The staging Compose reference maps runtime STORAGE_* keys from isolated
# host-side credentials. Never point these three groups at the same principal.
# WEB_STORAGE_ACCESS_KEY_ID=
# WEB_STORAGE_SECRET_ACCESS_KEY=
# WEB_STORAGE_SESSION_TOKEN=
# WORKER_GENERAL_STORAGE_ACCESS_KEY_ID=
# WORKER_GENERAL_STORAGE_SECRET_ACCESS_KEY=
# WORKER_GENERAL_STORAGE_SESSION_TOKEN=
# WORKER_IMPORT_STORAGE_ACCESS_KEY_ID=
# WORKER_IMPORT_STORAGE_SECRET_ACCESS_KEY=
# WORKER_IMPORT_STORAGE_SESSION_TOKEN=
# Server-only SSE-C key for portal/privacy GDPR exports: `openssl rand -base64 32`.
# Configure the same value on both web surfaces and the dedicated GDPR export worker.
GDPR_EXPORT_SSE_C_KEY_BASE64=
# Set to true for providers that require path-style bucket addressing (MinIO, some Wasabi regions).
# Leave false for AWS S3 default virtual-hosted style.
STORAGE_FORCE_PATH_STYLE=false
@@ -92,6 +161,8 @@ LAGO_TIMEOUT_MS=10000
MOLLIE_API_KEY=
MOLLIE_PROFILE_ID=
MOLLIE_TIMEOUT_MS=10000
# General worker only. Use staging-api.hivegrid.de in staging and api.hivegrid.de in production.
BILLING_MOLLIE_WEBHOOK_URL=
# Worker delivery credentials for queued transactional email (hivegrid.email -> Mailjet)
MAILJET_API_KEY=
@@ -113,7 +184,8 @@ ANALYTICS_TOKEN=
# Self-hosted captcha. mCaptcha remains the compatibility default; set
# CAPTCHA_PROVIDER=cap to use Cap Standalone (see infra/cap/README.md).
# Public bits (instance URL + per-surface sitekeys) are safe to expose; secrets
# are server-only. Verification fails open by default (CAPTCHA_FAIL_OPEN).
# are server-only. Deployed runtimes always fail closed; local development/test
# may explicitly set CAPTCHA_FAIL_OPEN=true when provider availability is not required.
CAPTCHA_PROVIDER=mcaptcha
CAP_INSTANCE_URL=
CAP_SITE_SECRET=
@@ -128,7 +200,7 @@ MCAPTCHA_ACCOUNT_SECRET=
MCAPTCHA_SITEKEY_LOGIN=
MCAPTCHA_SITEKEY_FORMS=
MCAPTCHA_SITEKEY_BOOKING=
CAPTCHA_FAIL_OPEN=true
CAPTCHA_FAIL_OPEN=false
AUTH_MAGIC_LINK_ENABLED=false
AUTH_MAGIC_LINK_TOKEN_TTL_MINUTES=15
@@ -162,6 +234,10 @@ WORKER_ENABLED=false
# WORKER_CONCURRENCY_IMPORT=1
# WORKER_CONCURRENCY_WEBHOOK=20
# WORKER_CONCURRENCY_PLUGIN=5
# Nested active-tenant maintenance sweeps share one process-wide budget. Keep
# this below DATABASE_POOL_MAX so queue jobs and health probes retain headroom.
# Default 2, hard-capped at 4.
# WORKER_TENANT_SWEEP_CONCURRENCY=2
# Health HTTP port for /healthz and /readyz (per-worker). Defaults to 9100;
# the five-service worker layout uses 9101-9105.
# WORKER_HEALTH_PORT=9100
@@ -171,6 +247,9 @@ WORKER_ENABLED=false
# WORKER_REDIS_POOL_SIZE=
EXPORT_RETENTION_QUEUE_ENABLED=false
IMPORT_QUEUE_ENABLED=false
# Internal worker-import fallback: consume only hivegrid.exports for portal/privacy GDPR exports.
# Keep false unless both IMPORT_QUEUE_* gates are unset/false and complete STORAGE_* wiring is present.
PORTAL_GDPR_EXPORT_QUEUE_ENABLED=false
# Outbox dispatcher (transactional outbox pattern; see docs/architecture/outbox-pattern.md).
# Defaults: off in dev so workers without Redis can still boot. Set true on staging+prod.
OUTBOX_DISPATCHER_ENABLED=false
@@ -182,8 +261,18 @@ OUTBOX_MAX_RETRIES=6
# Daily worker-general maintenance that purges DONE outbox rows after the replay/debug window.
OUTBOX_DONE_RETENTION_HOURS=720
OUTBOX_DONE_RETENTION_BATCH_SIZE=1000
BULLMQ_REDIS_URL=redis://localhost:6379/0
# REDIS_URL is a fallback only when BULLMQ_REDIS_URL is absent; keep it commented if a platform injects it.
BULLMQ_REDIS_URL=redis://127.0.0.1:6379/0
# Central ClamAV INSTREAM endpoint. Production uses the mesh-only estate
# service; inside the compose network the host is `clamav`.
# Uploads are fail-closed: without a reachable clamd, every malware-gated
# upload (profile picture, HR documents) is rejected. `pnpm dev:services`
# starts it — the first boot pulls ~250MB of signatures before it goes healthy.
CLAMD_HOST=127.0.0.1
CLAMD_PORT=3310
CLAMD_TIMEOUT_MS=30000
SCAN_QUEUE_ENABLED=true
# REDIS_URL is required by MCP in production; queue runtimes safely fall back to it
# (using the shared-store's separate logical DB and namespace) when it is absent.
# REDIS_URL=redis://localhost:6379/0
# Two-tier cache pub/sub invalidation (subscription + tenant; entitlements piggy-back on subscription).
# Set CACHE_INVALIDATION_ENABLED=false to disable cross-replica pub/sub (emergency switch — L1 TTL becomes
@@ -204,8 +293,6 @@ BROWSER_SESSION_TIMEOUT_MS=60000
IPSTACK_API_KEY=
# ipapi.is — alternative provider with similar response shape; free tier available.
IPAPIIS_API_KEY=
PORTAL_SERVER_URL=
PORTAL_SERVER_FLY_TOKEN=
# Meilisearch — full-text search engine consumed by packages/search and the
# search-indexer worker job. MEILI_API_KEY is the SaaS-scoped client key the app
@@ -213,7 +300,7 @@ PORTAL_SERVER_FLY_TOKEN=
# Local dev uses the docker-compose meilisearch service whose master key defaults
# to `devkey`, so the app key is `devkey` too. Production injects a scoped key
# (infra STANDARDS §4 / docs/deploy/meilisearch.md, docs/features/search.md).
MEILI_URL=http://localhost:7700
MEILI_URL=http://127.0.0.1:7700
MEILI_API_KEY=devkey
# MEILI_ENV=development
# Toggle search backend hot-path strategy. `meilisearch` (default) goes
@@ -248,6 +335,10 @@ MEILI_API_KEY=devkey
# SENTRY_DSN_API=https://public-api@sentry.example/3
# SENTRY_DSN_WORKER=https://public-worker@sentry.example/4
# SENTRY_ENVIRONMENT=production
# Runtime-selectable product locales. New review locales are enabled on staging
# one at a time and remain rejected in production until their review manifest is approved.
I18N_ENABLED_LOCALES=de,en
# SENTRY_RELEASE=
# SENTRY_TRACES_SAMPLE_RATE=0.1
# SENTRY_PROFILES_SAMPLE_RATE=0.0
@@ -273,7 +364,7 @@ MEILI_API_KEY=devkey
# VITE_SENTRY_REPLAYS_SESSION_SAMPLE_RATE=0.1
# VITE_SENTRY_REPLAYS_ON_ERROR_SAMPLE_RATE=1.0
# Sentry source-map upload + release tagging (CI-only; never commit the auth token).
# Required by .github/workflows/_sentry-release.yml and the @sentry/vite-plugin step.
# Required by .gitea/workflows/_sentry-release.yml and the @sentry/vite-plugin step.
# SENTRY_AUTH_TOKEN=
# SENTRY_ORG=
# SENTRY_PROJECT=hivegrid-web
@@ -341,17 +432,21 @@ MEILI_API_KEY=devkey
# `form-widget-turnstile` feature flag. See docs/features/form-widget.md.
# FORM_WIDGET_CDN_URL=https://forms.example.com
# Marketing-funnel (Phase 05 #78 — apps/web/public/embed/marketing.js).
# MARKETING_ALLOWED_ORIGINS is a CSV of origins (with `*.host` wildcards
# allowed) from which the public `/api/leads/capture` endpoint accepts
# submissions. Fail-closed: empty list rejects all browser submissions.
# MARKETING_RATE_LIMIT_PER_MIN is the per-IP submission limit (default 5).
# Captcha is the shared self-hosted captcha provider; flag is gated via
# the `marketing-funnel-turnstile` feature flag.
# Retired browser lead-capture compatibility (R-LEADS).
# `/api/leads/capture` now returns 410 and the old marketing.js SDK is removed.
# MARKETING_ALLOWED_ORIGINS only controls CORS headers on that drain response.
# MARKETING_RATE_LIMIT_PER_MIN is deprecated and ignored; it remains listed
# temporarily so existing environment inventories can be cleaned up safely.
# See docs/features/marketing-funnel.md.
# MARKETING_ALLOWED_ORIGINS=https://marketing.example.com,https://*.example.com
# MARKETING_RATE_LIMIT_PER_MIN=5
# Native platform-lead intake (R-LEADS). Enabled by default; set false on the
# API runtime to stop POST /v1/platform/leads before authentication or writes.
# Admin navigation/routes are controlled separately by the global database
# feature flag `platform_admin_leads`.
# PLATFORM_LEADS_INGRESS_ENABLED=true
# Marketing-funnel Phase 2 (Phase 05 #79 — self-service conversion +
# outbound webhooks + attribution reports).
# LEAD_CONVERSION_SECRET is the HMAC key (min 32 bytes) signing the
@@ -383,6 +478,13 @@ MEILI_API_KEY=devkey
# MARKETING_TOKEN_SECRET=
# MARKETING_SEQUENCES_ENABLED=false
# Provider-neutral normalized delivery/bounce webhook for Admin Sales email.
# ADMIN_EMAIL_EVENT_WEBHOOK_SECRET=
# Signed, rotatable BCC logging capabilities. The domain defaults to
# bcc.<APP_BASE_DOMAIN> and needs a dedicated provider catch-all/MX.
# ADMIN_EMAIL_BCC_CAPABILITY_SECRET=
# ADMIN_EMAIL_BCC_INBOUND_DOMAIN=
# Realtime collaboration (Phase 05 #59 — apps/hocuspocus + Novel-Editor).
# HOCUSPOCUS_AUTH_SECRET signs the 15-min JWTs the web app issues via
# `/api/collab/token`. The Hocuspocus container verifies them in
@@ -403,6 +505,10 @@ MEILI_API_KEY=devkey
# HOCUSPOCUS_HOST=0.0.0.0
# HOCUSPOCUS_MAX_PAYLOAD_BYTES=10485760
# Team Chat WebSocket identity tokens. Shared by web (issuer) and API
# (`/ws/chat` verifier), but never shared with Hocuspocus. Min 32 bytes.
# CHAT_GATEWAY_AUTH_SECRET=
# ---------------------------------------------------------------------------
# Admin-Panel SSO via Authentik (Phase 09 #82 — apps/web/app/modules/admin-sso)
# ---------------------------------------------------------------------------
@@ -413,6 +519,9 @@ MEILI_API_KEY=devkey
# (`hivegrid-admin-panel` per infra/authentik/bootstrap/blueprints/03-*).
# AUTHENTIK_ADMIN_CLIENT_SECRET is fetched from the Authentik admin UI
# after the blueprint applies; rotate via Authentik then redeploy.
# AUTHENTIK_ADMIN_JIT_DATABASE_URL uses the separately provisioned
# hivegrid_authentik_jit login. That role can execute only the verified
# callback's JIT function and owns no table privileges.
# AUTHENTIK_ADMIN_REDIRECT_URI is the exact callback URI registered with
# the Authentik provider — must match the deployed admin host.
# AUTHENTIK_ADMIN_POST_LOGOUT_REDIRECT_URI is the URI Authentik redirects
@@ -429,6 +538,7 @@ MEILI_API_KEY=devkey
# AUTHENTIK_ISSUER_URL=https://auth.example.com/application/o/hivegrid-admin-panel/
# AUTHENTIK_ADMIN_CLIENT_ID=hivegrid-admin-panel
# AUTHENTIK_ADMIN_CLIENT_SECRET=
# AUTHENTIK_ADMIN_JIT_DATABASE_URL=postgresql://hivegrid_authentik_jit:<PASSWORD>@localhost:5432/hivegrid
# AUTHENTIK_ADMIN_REDIRECT_URI=https://admin.example.com/auth/admin/callback
# AUTHENTIK_ADMIN_POST_LOGOUT_REDIRECT_URI=https://admin.example.com/login?logged_out=1
# ADMIN_FALLBACK_LOGIN_ENABLED=false
@@ -481,4 +591,3 @@ PLUGIN_REQUIRE_CAPABILITY_CONSENT=true
PLUGIN_INSTALL_RATE_LIMIT_PER_MIN=5
PLUGIN_SETTINGS_WRITE_RATE_LIMIT_PER_MIN=60
PLUGIN_SETTINGS_FRAME_VIOLATION_RATE_LIMIT_PER_MIN=120
PLUGIN_RATE_LIMIT_FAIL_OPEN=false
@@ -1,8 +1,11 @@
# Core local development
APP_NAME=HiveGrid Local
DATABASE_URL="file:./dev.db?connection_limit=1&connect_timeout=30"
APP_NAME="HiveGrid Local"
DATABASE_URL="postgresql://hivegrid:hivegrid@127.0.0.1:5432/hivegrid"
DIRECT_URL="postgresql://hivegrid:hivegrid@127.0.0.1:5432/hivegrid"
SESSION_SECRET=replace-with-local-session-secret
AUDIT_CHAIN_SECRET=replace-with-local-audit-chain-secret
CRYPTO_SECRET=replace-with-local-crypto-secret
ADMIN_CONNECTION_MASTER_KEY=replace-with-local-admin-connection-master-key
APP_BASE_DOMAIN=localhost:3000
WEB_APP_HOST=app.localhost:3000
ADMIN_APP_HOST=admin.localhost:3000
@@ -17,7 +20,25 @@ JWT_SECRET=replace-with-local-jwt-secret
SEED_DEMO_DATA=true
# Matches the local seed admin only; ignored outside NODE_ENV=development.
DEMO_USER=admin@email.com:password
ADMIN_FALLBACK_LOGIN_ENABLED=true
ADMIN_FALLBACK_LOGIN_EMAILS=admin@email.com
# WEBHOOKS_URL=https://...ngrok-free.app
# AIRCALL_CLIENT_ID=
# AIRCALL_CLIENT_SECRET=
# AIRCALL_REDIRECT_URI=http://app.localhost:3000/integrations/aircall/oauth/callback
# AIRCALL_WEBHOOK_URL=https://...ngrok-free.app/v1/webhooks/telephony/aircall
# KWP_OAUTH_CLIENT_ID=
# KWP_OAUTH_CLIENT_SECRET=
# KWP_OAUTH_SCOPES=
# KWP_CUSTOMER_CODE=
# KWP_OIDC_ISSUER=
# KWP_HIVEGRID_TENANT_ID=
# Deprecated and ignored by new connections; choose the bnWin mandant in the setup flow.
# KWP_MANDANT=
# CHAT_GATEWAY_AUTH_SECRET=replace-with-local-chat-gateway-secret-at-least-32-bytes
# WEB_PUSH_VAPID_SUBJECT=mailto:dev@hivegrid.test
# WEB_PUSH_VAPID_PUBLIC_KEY=
# WEB_PUSH_VAPID_PRIVATE_KEY=
# Optional local providers; MailerSend is the default transactional runtime provider
# STORAGE_ENDPOINT=
@@ -36,7 +57,7 @@ DEMO_USER=admin@email.com:password
# EXPORT_RETENTION_QUEUE_ENABLED=false
# IMPORT_QUEUE_ENABLED=false
# BULLMQ_REDIS_URL=redis://localhost:6379/0
# REDIS_URL is a fallback only when BULLMQ_REDIS_URL is absent; keep it commented if a platform injects it.
# REDIS_URL is required by MCP in production and a queue fallback elsewhere; keep it commented if the platform injects it.
# REDIS_URL=redis://localhost:6379/0
# BROWSER_RUNTIME_URL=
# BROWSER_RUNTIME_API_KEY=
@@ -5,12 +5,36 @@ APP_NAME=HiveGrid
# statement caching (transaction-mode pooling cannot keep them). DIRECT_URL
# below is the unpooled link used by Prisma Migrate. See docs/ops/pgbouncer.md.
DATABASE_URL="postgres://{USER}:{PASSWORD}@{POOL_HOST}:6432/{DATABASE}?pgbouncer=true&connection_limit=10"
# Explicit node-postgres/PrismaPg process pool cap. Initial production values:
# hivegrid-web=10; hivegrid-portal=5. Every other runtime sets its own approved
# positive value. The URL connection_limit does not replace this runtime cap.
DATABASE_POOL_MAX=10
# Runtime traffic must authenticate directly as the restricted NOBYPASSRLS
# role. The migration user belongs only in DIRECT_URL.
RLS_RUNTIME_MODE=required
# Every worker resource needs its own DATABASE_URL whose username is
# hivegrid_worker, plus this explicit override: DATABASE_RUNTIME_ROLE=hivegrid_worker.
DATABASE_RUNTIME_ROLE=hivegrid_app
# Required on the web resource when Authentik Admin SSO is enabled. Use a
# separate PgBouncer credential for the execute-only callback capability.
# AUTHENTIK_ADMIN_JIT_DATABASE_URL="postgres://hivegrid_authentik_jit:{PASSWORD}@{POOL_HOST}:6432/{DATABASE}?pgbouncer=true&connection_limit=2"
# The same immutable web image serves two isolated resources. Core uses the
# values below; hivegrid-portal changes the surface and DB role, removes
# SESSION_SECRET, and injects only PORTAL_SESSION_SECRET.
WEB_RUNTIME_SURFACE=core
SESSION_SECRET=
# WEB_RUNTIME_SURFACE=portal
# DATABASE_RUNTIME_ROLE=hivegrid_portal
# DATABASE_POOL_MAX=5
# PORTAL_SESSION_SECRET=<PORTAL_SESSION_SECRET>
AUDIT_CHAIN_SECRET=
CRYPTO_SECRET=
ADMIN_CONNECTION_MASTER_KEY=
APP_BASE_DOMAIN=your-domain.invalid
WEB_APP_HOST=app.your-domain.invalid
ADMIN_APP_HOST=admin.your-domain.invalid
API_HOST=api.your-domain.invalid
PORTAL_APP_HOST=portal.your-domain.invalid
MCP_HOST=0.0.0.0
MCP_PORT=8080
MCP_ALLOWED_HOSTS=mcp.your-domain.invalid,staging-mcp.your-domain.invalid
@@ -41,6 +65,30 @@ DIRECT_URL="postgres://{USER}:{PASSWORD}@{POSTGRES_HOST}:5432/{DATABASE}"
# DATABASE_READ_URL="postgres://{READ_USER}:{PASSWORD}@{REPLICA_HOST}:6432/{DATABASE}?pgbouncer=true&connection_limit=10"
# SERVER_URL=https://app.example.com
# Optional Aircall Technology Partner OAuth integration. Values are environment-
# specific Coolify secrets; callback and webhook URLs must match the Aircall app.
# AIRCALL_CLIENT_ID=
# AIRCALL_CLIENT_SECRET=
# AIRCALL_REDIRECT_URI=https://app.your-domain.invalid/integrations/aircall/oauth/callback
# AIRCALL_WEBHOOK_URL=https://api.your-domain.invalid/v1/webhooks/telephony/aircall
# Optional KWP OAuth2/PKCE integration. Configure values as environment-specific
# Coolify secrets; the callback URI is derived from APP_PROTOCOL and WEB_APP_HOST.
# KWP_OAUTH_CLIENT_ID=
# KWP_OAUTH_CLIENT_SECRET=
# KWP_OAUTH_SCOPES=
# KWP_CUSTOMER_CODE=
# KWP_OIDC_ISSUER=
# KWP_HIVEGRID_TENANT_ID=
# Deprecated and ignored by new connections; choose the bnWin mandant in the setup flow.
# KWP_MANDANT=
# Web Push for ringing notifications. Production web requires the public key;
# worker-webhook requires the complete stable pair from the same Coolify secret source.
WEB_PUSH_VAPID_SUBJECT=mailto:ops@hivegrid.de
WEB_PUSH_VAPID_PUBLIC_KEY=<WEB_PUSH_VAPID_PUBLIC_KEY>
WEB_PUSH_VAPID_PRIVATE_KEY=<WEB_PUSH_VAPID_PRIVATE_KEY>
# Production seed bootstrap. Set in Coolify before first migration/seed run; blank values are rejected.
# SEED_ADMIN_EMAIL=owner@example.com
# SEED_ADMIN_PASSWORD=replace-with-a-strong-one-time-bootstrap-password
@@ -54,6 +102,10 @@ STORAGE_SECRET_ACCESS_KEY=
STORAGE_SESSION_TOKEN=
STORAGE_PUBLIC_BASE_URL=
STORAGE_FORCE_PATH_STYLE=false
# Public build-time browser endpoint; the Gitea deploy maps the repository
# variable with the same name into the web-only Docker build.
VITE_HOCUSPOCUS_URL=
CHAT_GATEWAY_AUTH_SECRET=<CHAT_GATEWAY_AUTH_SECRET>
MAILJET_API_KEY=
MAILJET_SECRET_KEY=
MAILJET_FROM_EMAIL=
@@ -77,7 +129,7 @@ MCAPTCHA_ACCOUNT_SECRET=
MCAPTCHA_SITEKEY_LOGIN=
MCAPTCHA_SITEKEY_FORMS=
MCAPTCHA_SITEKEY_BOOKING=
CAPTCHA_FAIL_OPEN=true
CAPTCHA_FAIL_OPEN=false
AUTH_MAGIC_LINK_ENABLED=false
AUTH_MAGIC_LINK_TOKEN_TTL_MINUTES=15
NOTIFICATIONS_NOVU_API_KEY=
@@ -85,9 +137,11 @@ NOTIFICATIONS_NOVU_API_KEY=
# WORKER_ENABLED=false
EXPORT_RETENTION_QUEUE_ENABLED=false
IMPORT_QUEUE_ENABLED=false
# Dedicated worker-import mode only: both IMPORT_QUEUE_* gates false/unset and complete STORAGE_* required.
PORTAL_GDPR_EXPORT_QUEUE_ENABLED=false
# Set this on worker resources only.
# BULLMQ_REDIS_URL=redis://default:<redis-password>@redis.your-domain.invalid:6379/0
# REDIS_URL is a fallback only when BULLMQ_REDIS_URL is absent; keep it commented if a platform injects it.
# REDIS_URL is required by MCP in production and a queue fallback elsewhere; keep it commented if the platform injects it.
# REDIS_URL=redis://localhost:6379/0
# Plugin worker runtime. Set these on WORKER_QUEUE_GROUP=plugin resources.
@@ -104,6 +158,4 @@ BROWSER_RUNTIME_API_KEY=
BROWSER_SESSION_TIMEOUT_MS=60000
IPSTACK_API_KEY=
IPAPIIS_API_KEY=
PORTAL_SERVER_URL=
PORTAL_SERVER_FLY_TOKEN=
# SITE_KEY_EXAMPLE_SITE=
@@ -1,9 +1,11 @@
# Non-secret test fixture used by env-contract checks.
# Values are deterministic placeholders only; never copy production secrets here.
APP_NAME=HiveGrid Test
APP_NAME="HiveGrid Test"
DATABASE_URL="file:./test.db?connection_limit=1&connect_timeout=30"
SESSION_SECRET=test-session-secret-placeholder
AUDIT_CHAIN_SECRET=test-audit-chain-secret-placeholder
CRYPTO_SECRET=test-crypto-secret-placeholder
ADMIN_CONNECTION_MASTER_KEY=test-admin-connection-key-placeholder
APP_BASE_DOMAIN=localhost.test
WEB_APP_HOST=app.localhost.test
ADMIN_APP_HOST=admin.localhost.test
@@ -47,7 +49,7 @@ MAILJET_API_KEY=test-mailjet-api-key-placeholder
MAILJET_SECRET_KEY=test-mailjet-secret-key-placeholder
MAILJET_FROM_EMAIL=test@example.com
SUPPORT_EMAIL=support@example.com
COMPANY_NAME=Example Test Company
COMPANY_ADDRESS=123 Test Street
COMPANY_NAME="Example Test Company"
COMPANY_ADDRESS="123 Test Street"
ANALYTICS_TOKEN=test-analytics-token-placeholder
SITE_KEY_EXAMPLE_SITE=test-site-key-placeholder
@@ -3,5 +3,3 @@
!app/utils/services/.server/urlService.test.ts
!app/utils/services/apiService.entity-resolver.test.ts
!utils/services/apiService.entity-resolver.test.ts
!test/isolation/fixtures/user-session-isolation.test.ts
!test/isolation/fixtures/user-session-isolation.ts
@@ -18,7 +18,6 @@
"ignorePatterns": [
".react-router/",
"apps/web/.react-router/",
"app/",
"app/generated/",
"apps/web/app/generated/",
"build/",
@@ -37,12 +36,28 @@
"no-console": "warn",
"no-debugger": "error",
"jsx-a11y/no-autofocus": "off",
"jsx-a11y/no-noninteractive-tabindex": [
"error",
{
"tags": [],
"roles": ["tabpanel", "region"],
"allowExpressionValues": true
}
],
"import/first": "off",
"@typescript-eslint/consistent-type-imports": "off",
"prefer-const": "off",
"@typescript-eslint/ban-ts-comment": "off",
"no-var": "off",
"@typescript-eslint/no-unused-vars": "warn",
"@typescript-eslint/no-unused-vars": [
"warn",
{
"argsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_",
"destructuredArrayIgnorePattern": "^_",
"ignoreRestSiblings": true
}
],
"no-restricted-imports": [
"error",
{
@@ -293,6 +308,32 @@
}
]
}
},
{
"files": ["apps/web/app/**/*.ts", "apps/web/app/**/*.tsx"],
"excludedFiles": [
"**/*.test.ts",
"**/*.test.tsx",
"**/*.spec.ts",
"**/*.spec.tsx"
],
"rules": {
"no-restricted-properties": [
"error",
{
"property": "toLocaleString",
"message": "Time-zone-dependent formatting causes SSR/client hydration mismatches (React #418). Use useLocaleFormatters()/formatDate from ~/locale/format (fixed APP_TIME_ZONE) instead."
},
{
"property": "toLocaleDateString",
"message": "Time-zone-dependent formatting causes SSR/client hydration mismatches (React #418). Use useLocaleFormatters()/formatDate from ~/locale/format (fixed APP_TIME_ZONE) instead."
},
{
"property": "toLocaleTimeString",
"message": "Time-zone-dependent formatting causes SSR/client hydration mismatches (React #418). Use useLocaleFormatters()/formatDate from ~/locale/format (fixed APP_TIME_ZONE) instead."
}
]
}
}
]
}
@@ -0,0 +1,31 @@
# SOPS-verschlüsselte Secrets müssen LF behalten.
# Auf Windows wandelt git (core.autocrlf=true) sonst LF->CRLF, was das SOPS-Format
# zerstört (Fehler: parsing time "...Z\r": extra text). eol=lf erzwingt LF auf allen OS.
secrets/*.sops.env text eol=lf
# Generierter Prisma-Client wird mit LF eingecheckt. Auf Windows (core.autocrlf=true)
# schreibt `prisma generate` / `pnpm install` ihn sonst mit CRLF raus -> 193 Dateien
# als "modified" obwohl inhaltlich identisch. eol=lf erzwingt LF auf allen OS.
packages/db/generated/** text eol=lf
# Shell-Skripte laufen in Linux-Containern/CI; CRLF bricht den Shebang
# (exec ./start.sh: no such file or directory). eol=lf erzwingt LF auf allen OS.
*.sh text eol=lf
# Source and contract-test fixtures must be byte-stable across platforms.
# Besides making exact source assertions deterministic, LF is required when
# Vite imports an .mjs verifier with a shebang on Windows.
*.ts text eol=lf
*.tsx text eol=lf
*.mts text eol=lf
*.cts text eol=lf
*.js text eol=lf
*.jsx text eol=lf
*.mjs text eol=lf
*.cjs text eol=lf
*.json text eol=lf
*.md text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.prisma text eol=lf
*.sql text eol=lf
@@ -1,7 +1,7 @@
name: Sentry Release
# Reusable workflow for Gitea Actions. Mirrors the GitHub equivalent at
# .github/workflows/_sentry-release.yml. Requires Gitea Actions runner
# Requires a Gitea Actions runner
# capable of workflow_call (Gitea >= 1.21). For older runners use the
# composite action at .gitea/actions/sentry-release/action.yml instead.
@@ -57,19 +57,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
- name: Enable Corepack
run: corepack enable
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Download source-map artifact
if: ${{ inputs.sourcemaps-artifact != 'none' }}
uses: actions/download-artifact@v3
uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3
with:
name: ${{ inputs.sourcemaps-artifact }}
path: ${{ inputs.sourcemaps-path }}
@@ -1,20 +1,18 @@
name: Accessibility
# Runs the axe-core vitest suites (apps/web ui components, SkipToContent)
# and the WCAG-2.2-AA color-contrast verifier on every PR + push to main.
#
# Mirror of .github/workflows/a11y.yml for the Gitea runner.
# and the WCAG-2.2-AA color-contrast verifier on manual demand.
#
# Docs: docs/contributing/wcag-audit.md
on:
push:
branches:
- main
pull_request:
# TEMPORARY RUNNER RELIEF (2026-07-19): automatic PR/main triggers are paused
# through 2026-07-22. Re-enable them with UI-focused path filters afterwards.
# The fast accessibility contracts in ci.yml remain active meanwhile.
# Cancel superseded runs so rapid pushes don't pile up unclaimed on the runner
# (mirrors ci.yml). Without this each push stacked a new a11y run on the queue.
on:
workflow_dispatch:
# Keep duplicate manual runs from occupying the shared runner queue.
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
@@ -52,19 +50,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -0,0 +1,102 @@
name: Bundle Budget Baseline
# Captures the main-branch bundle report. The report is both attached to the
# run and cached under a main-only prefix consumed by the pull-request gate.
on:
push:
branches: [main]
paths:
- "apps/web/**"
- "packages/brand/**"
- "packages/config/**"
- "packages/entitlements/**"
- "packages/form-widget/**"
- "packages/foundation/**"
- "packages/i18n/**"
- "packages/plugin-runtime/**"
- "packages/ui*/**"
- "packages/url/**"
- "packages/view-models/**"
- "package.json"
- "pnpm-lock.yaml"
- "scripts/bundle-budgets.json"
- "scripts/verify-bundle-size.mjs"
- ".gitea/workflows/bundle-budget-baseline.yml"
workflow_dispatch:
env:
HIVEGRID_GITEA_HOST_IP: ${{ vars.HIVEGRID_GITEA_HOST_IP }}
jobs:
capture:
name: Capture bundle baseline
runs-on: toolctrl-ci
timeout-minutes: 30
env:
DATABASE_URL: postgresql://hivegrid:hivegrid@localhost:5432/hivegrid?schema=public
steps:
- name: Resolve internal Gitea host
run: |
if [ -n "${HIVEGRID_GITEA_HOST_IP:-}" ]; then
if ! HIVEGRID_GITEA_HOST_IP="$HIVEGRID_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.HIVEGRID_GITEA_HOST_IP || "") ? 0 : 1)'; then
echo "HIVEGRID_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
exit 1
fi
printf '%s git.tool-ctrl.de\n' "$HIVEGRID_GITEA_HOST_IP" >> /etc/hosts
fi
- name: Checkout main
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Prepare baseline cache
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: baseline/main-bundle-report.json
key: bundle-baseline-main-${{ gitea.sha }}
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Build web
run: pnpm --filter @hivegrid/web build
- name: Verify aggregate bundle budgets
run: pnpm run verify:bundle-size
- name: Measure bundle sizes
run: |
mkdir -p baseline
node scripts/verify-bundle-size.mjs --json > baseline/main-bundle-report.json
- name: Upload baseline report
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3
with:
name: bundle-baseline-main-${{ gitea.run_id }}
path: baseline/main-bundle-report.json
retention-days: 30
@@ -1,8 +1,7 @@
name: Bundle Budget
# Gitea variant of .github/workflows/bundle-budget.yml. Uses Gitea-API to
# post / upsert a sticky PR comment with per-route gzip sizes.
# Docs: docs/architecture/bundle-budgets.md
# Enforces aggregate bundle budgets for pull requests. The current report and
# its comparison with the latest cached main baseline are attached to the run.
on:
pull_request:
@@ -22,14 +21,20 @@ on:
- "pnpm-lock.yaml"
- "scripts/bundle-budgets.json"
- "scripts/verify-bundle-size.mjs"
- "scripts/render-bundle-budget-comment.mjs"
- ".gitea/workflows/bundle-budget.yml"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
HIVEGRID_GITEA_HOST_IP: ${{ vars.HIVEGRID_GITEA_HOST_IP }}
jobs:
measure:
name: Measure & report bundle sizes
name: Measure and report bundle sizes
runs-on: toolctrl-ci
timeout-minutes: 30
env:
@@ -45,56 +50,65 @@ jobs:
printf '%s git.tool-ctrl.de\n' "$HIVEGRID_GITEA_HOST_IP" >> /etc/hosts
fi
- name: Checkout PR head
uses: actions/checkout@v4
- name: Checkout pull request
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Restore latest main bundle baseline
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: baseline/main-bundle-report.json
key: bundle-baseline-pr-${{ gitea.sha }}
restore-keys: |
bundle-baseline-main-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Build web (PR head)
- name: Build web
run: pnpm --filter @hivegrid/web build
- name: Verify aggregate bundle budgets
run: pnpm run verify:bundle-size
- name: Measure PR bundle sizes
- name: Measure bundle sizes
if: always()
run: node scripts/verify-bundle-size.mjs --json > pr-bundle-report.json
- name: Render PR comment markdown
# Baseline download from Gitea artifact storage is opt-in via
# BUNDLE_BASELINE_URL; falls back to no-diff mode otherwise.
run: |
if [ -n "${BUNDLE_BASELINE_URL:-}" ]; then
curl -sSfL "$BUNDLE_BASELINE_URL" -o main-bundle-report.json || true
fi
node scripts/render-bundle-budget-comment.mjs \
--current pr-bundle-report.json \
--baseline main-bundle-report.json \
--out bundle-comment.md
env:
BUNDLE_BASELINE_URL: ${{ vars.BUNDLE_BASELINE_URL }}
- name: Render bundle report
if: always()
run: node scripts/render-bundle-budget-comment.mjs --current pr-bundle-report.json --baseline baseline/main-bundle-report.json --out bundle-report.md
- name: Upsert Gitea PR comment
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_HOST: ${{ vars.GITEA_HOST || 'git.tool-ctrl.de' }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
run: node scripts/post-bundle-budget-gitea-comment.mjs
- name: Upload bundle report
if: always()
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3
with:
name: bundle-report-pr-${{ gitea.run_id }}
path: |
pr-bundle-report.json
bundle-report.md
retention-days: 14
@@ -6,12 +6,81 @@ on:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
# Every Docker runtime resource is run-scoped; mutable pnpm stores are exclusively
# locked, and root production closures share one atomic parallel bundle vertex.
# Superseded runs can therefore stop instead of occupying the shared runner queue.
cancel-in-progress: true
env:
HIVEGRID_GITEA_HOST_IP: ${{ vars.HIVEGRID_GITEA_HOST_IP }}
jobs:
# Keep the longest independent job at the front of Gitea's dispatch order. On the
# eight-slot shared runner this prevents short service jobs from making Docker wait
# for a second scheduling wave; all runtime resources remain run-scoped.
docker-smoke:
name: Docker Smoke
runs-on: toolctrl-ci
timeout-minutes: 45
env:
DOCKER_BUILDKIT: "1"
DOCKER_SMOKE_RUN_ID: ${{ gitea.run_id }}-${{ gitea.run_attempt }}
DOCKER_SMOKE_REVISION: ${{ gitea.sha }}
DOCKER_SMOKE_COMMAND_TIMEOUT_SECONDS: "90"
DOCKER_SMOKE_ARTIFACT_TIMEOUT_SECONDS: "180"
DOCKER_SMOKE_SUITE_TIMEOUT_SECONDS: "2520"
# No needs: the Docker images are built from source inside this job (no dependency on the
# quality/build jobs' outputs), so it runs fully in parallel instead of waiting on the
# ~4 min quality phase -> off the critical tail. Trade-off: if quality fails, the images
# still build (wasted compute), but the run fails overall anyway.
steps:
- name: Setup hosts override and Docker CLI
run: |
if [ -n "${HIVEGRID_GITEA_HOST_IP:-}" ]; then
if ! HIVEGRID_GITEA_HOST_IP="$HIVEGRID_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.HIVEGRID_GITEA_HOST_IP || "") ? 0 : 1)'; then
echo "HIVEGRID_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
exit 1
fi
printf '%s git.tool-ctrl.de\n' "$HIVEGRID_GITEA_HOST_IP" >> /etc/hosts
fi
if ! command -v docker >/dev/null 2>&1 || ! docker buildx version >/dev/null 2>&1 || ! docker compose version >/dev/null 2>&1; then
if ! command -v apt-get >/dev/null 2>&1 || [ "$(id -u)" != "0" ]; then
echo "Docker CLI/buildx missing and apt-get is not available as root"
exit 1
fi
apt-get update -qq
apt-get install -qq -y --no-install-recommends ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
. /etc/os-release
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list
apt-get update -qq
apt-get install -qq -y --no-install-recommends docker-ce-cli docker-buildx-plugin docker-compose-plugin
fi
docker --version
docker buildx version
docker compose version
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
# Run/attempt-scoped runtime resources and one locked parallel closure bundle let the suite
# build all images in parallel, then validate all isolated runtimes in parallel. The
# two-wave barrier guarantees the web migrator image exists before service validation;
# the Node hard cap remains authoritative on older runners.
- name: Run isolated Docker smoke suite
shell: bash
run: |
set -euo pipefail
node scripts/lib/run-command-with-timeout.mjs \
--stage docker-smoke:suite \
--timeout-seconds "$DOCKER_SMOKE_SUITE_TIMEOUT_SECONDS" \
--grace-seconds 45 \
-- bash scripts/ci/docker-smoke-suite.sh all
# The former single "verify" gate is split into two parallel jobs (verify-1 + verify-2)
# to halve CI wallclock. The two heavy UI checks (ui-visual + hot-swap) sit in verify-1,
# the two heavy accessibility checks (a11y-coverage + a11y smoke) in verify-2, with the
@@ -35,19 +104,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -57,8 +134,8 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Verify GitHub CI workflow
run: pnpm run verify:github-ci-workflow
- name: Verify immutable action pins
run: pnpm run verify:action-pins
- name: Verify Gitea CI workflow
run: pnpm run verify:gitea-ci-workflow
@@ -69,6 +146,12 @@ jobs:
- name: Verify deploy readiness
run: pnpm run verify:deploy-readiness
- name: Verify production dependency licenses
run: pnpm run verify:licenses
- name: Audit production dependencies
run: pnpm audit --prod --audit-level high
- name: Verify Docker baseline
run: pnpm run verify:docker-baseline
@@ -117,19 +200,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -142,7 +233,7 @@ jobs:
- name: Verify tenant isolation report
run: pnpm run verify:tenant-isolation-report
- name: Verify cross-cutting model registry completeness
- name: Verify tenant-scope manifest and lifecycle registries
run: pnpm run verify:cross-cutting-models
- name: Verify sidebar routes
@@ -159,7 +250,7 @@ jobs:
- name: Verify Phase C package boundaries
run: pnpm run verify:phase-c-boundaries
- name: Verify Feature Manifest removed modules
- name: Verify removed modules
run: pnpm run verify:removed-modules
- name: Verify accessibility coverage
@@ -169,11 +260,7 @@ jobs:
run: pnpm run test:a11y
- name: Verify documentation gates
run: |
pnpm run verify:porting-docs-baseline
pnpm run verify:production-docs
pnpm run verify:release-docs
pnpm run verify:docs-links
run: pnpm run verify:docs-links
typecheck-test:
name: Quality Typecheck and Tests
@@ -193,19 +280,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -215,20 +310,8 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Typecheck
run: pnpm typecheck
- name: Lint
run: pnpm lint
- name: Foundation package tests
run: pnpm run test:foundation
- name: Workspace package tests
run: pnpm run test:packages
- name: Unit tests
run: pnpm test
- name: Run parallel quality groups
run: bash scripts/ci/run-quality-groups.sh
build:
name: Quality Build and Bundle
@@ -248,19 +331,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -278,17 +369,17 @@ jobs:
HIVEGRID_BUILD_SOURCEMAPS: "1"
run: pnpm run build:ci
- name: Verify bundle size
run: pnpm run verify:bundle-size
- name: Verify web runtime dependency closure
run: pnpm run verify:runtime-closures -- --runtime=web
- name: Verify web Sentry sourcemaps
run: test -n "$(find apps/web/build/client -type f -name '*.map' -print -quit)"
run: test -n "$(find apps/web/build-sourcemaps/core -type f -name '*.map' -print -quit)" && test -n "$(find apps/web/build-sourcemaps/portal -type f -name '*.map' -print -quit)"
- name: Upload web Sentry sourcemaps
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3
with:
name: web-client-sourcemaps
path: apps/web/build/client
path: apps/web/build-sourcemaps
if-no-files-found: error
retention-days: 7
@@ -313,19 +404,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -347,6 +446,9 @@ jobs:
- name: Build API
run: pnpm --filter @hivegrid/api build
- name: Verify API runtime dependency closure
run: pnpm run verify:runtime-closures -- --runtime=api
mcp:
name: MCP Service
runs-on: toolctrl-ci
@@ -365,19 +467,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -396,6 +506,69 @@ jobs:
- name: Build MCP
run: pnpm --filter @hivegrid/mcp build
- name: Verify MCP runtime dependency closure
run: pnpm run verify:runtime-closures -- --runtime=mcp
hocuspocus:
name: Hocuspocus Service
runs-on: toolctrl-ci
timeout-minutes: 20
env:
DATABASE_URL: postgresql://hivegrid:hivegrid@localhost:5432/hivegrid?schema=public
steps:
- name: Resolve internal Gitea host
run: |
if [ -n "${HIVEGRID_GITEA_HOST_IP:-}" ]; then
if ! HIVEGRID_GITEA_HOST_IP="$HIVEGRID_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.HIVEGRID_GITEA_HOST_IP || "") ? 0 : 1)'; then
echo "HIVEGRID_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
exit 1
fi
printf '%s git.tool-ctrl.de\n' "$HIVEGRID_GITEA_HOST_IP" >> /etc/hosts
fi
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Typecheck Hocuspocus
run: pnpm --filter @hivegrid/hocuspocus typecheck
- name: Test Hocuspocus
run: pnpm --filter @hivegrid/hocuspocus test
- name: Build Hocuspocus
run: pnpm --filter @hivegrid/hocuspocus build
- name: Verify Hocuspocus runtime dependency closure
run: pnpm run verify:runtime-closures -- --runtime=hocuspocus
worker:
name: Worker Service
runs-on: toolctrl-ci
@@ -414,19 +587,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -448,11 +629,75 @@ jobs:
- name: Build Worker
run: pnpm --filter @hivegrid/worker build
- name: Verify worker runtime dependency closure
run: pnpm run verify:runtime-closures -- --runtime=worker
- name: Health Check Worker
run: pnpm --filter @hivegrid/worker health
env:
WORKER_ENABLED: "false"
portal-domain-controller:
name: Portal Domain Controller Service
runs-on: toolctrl-ci
timeout-minutes: 20
steps:
- name: Resolve internal Gitea host
run: |
if [ -n "${HIVEGRID_GITEA_HOST_IP:-}" ]; then
if ! HIVEGRID_GITEA_HOST_IP="$HIVEGRID_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.HIVEGRID_GITEA_HOST_IP || "") ? 0 : 1)'; then
echo "HIVEGRID_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
exit 1
fi
printf '%s git.tool-ctrl.de\n' "$HIVEGRID_GITEA_HOST_IP" >> /etc/hosts
fi
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Typecheck portal-domain controller
run: pnpm --filter @hivegrid/portal-domain-controller typecheck
- name: Test portal-domain controller
run: pnpm --filter @hivegrid/portal-domain-controller test
- name: Build portal-domain controller
run: pnpm --filter @hivegrid/portal-domain-controller build
- name: Verify portal-domain controller runtime dependency closure
run: pnpm run verify:runtime-closures -- --runtime=portal-domain-controller
- name: Verify portal-domain controller deploy contract
run: pnpm run verify:portal-domain-controller-deploy
database:
name: Database Checks
runs-on: toolctrl-ci
@@ -469,19 +714,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -516,9 +769,29 @@ jobs:
docker --version
- name: Verify tenant policy contract
run: pnpm run verify:tenant-policy-contract
- name: Verify RLS release readiness
run: pnpm run verify:rls-release-readiness
- name: Verify identity and invite legacy migration
run: pnpm run verify:identity-invite-migration
- name: Verify SHK first-steps legacy migration
run: pnpm run verify:shk-first-steps-migration
- name: Verify migrations schema parity
run: pnpm run verify:migrations-parity
- name: Verify Prisma baseline equivalence
run: pnpm run verify:prisma-baseline-equivalence
- name: Verify RLS against fresh PostgreSQL
run: pnpm run verify:rls-live
env:
HIVEGRID_RLS_REQUIRE_MIGRATION_CHAIN_PARITY: "1"
- name: Verify database migration status
if: gitea.event_name != 'pull_request'
run: pnpm run verify:db-migrate-status:staging
@@ -530,102 +803,3 @@ jobs:
- name: Test database package
run: pnpm --filter @hivegrid/db test
docker-smoke:
name: Docker Smoke
runs-on: toolctrl-ci
timeout-minutes: 30
# No needs: the Docker images are built from source inside this job (no dependency on the
# quality/build jobs' outputs), so it runs fully in parallel instead of waiting on the
# ~4 min quality phase -> off the critical tail. Trade-off: if quality fails, the images
# still build (wasted compute), but the run fails overall anyway.
steps:
- name: Setup hosts override and Docker CLI
run: |
if [ -n "${HIVEGRID_GITEA_HOST_IP:-}" ]; then
if ! HIVEGRID_GITEA_HOST_IP="$HIVEGRID_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.HIVEGRID_GITEA_HOST_IP || "") ? 0 : 1)'; then
echo "HIVEGRID_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
exit 1
fi
printf '%s git.tool-ctrl.de\n' "$HIVEGRID_GITEA_HOST_IP" >> /etc/hosts
fi
if ! command -v docker >/dev/null 2>&1 || ! docker buildx version >/dev/null 2>&1 || ! docker compose version >/dev/null 2>&1; then
if ! command -v apt-get >/dev/null 2>&1 || [ "$(id -u)" != "0" ]; then
echo "Docker CLI/buildx missing and apt-get is not available as root"
exit 1
fi
apt-get update -qq
apt-get install -qq -y --no-install-recommends ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
. /etc/os-release
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian ${VERSION_CODENAME} stable" > /etc/apt/sources.list.d/docker.list
apt-get update -qq
apt-get install -qq -y --no-install-recommends docker-ce-cli docker-buildx-plugin docker-compose-plugin
fi
docker --version
docker buildx version
docker compose version
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Layer-cache strategy: this job runs on the self-hosted toolctrl-ci runner against the
# mounted host Docker daemon, whose BuildKit keeps a persistent local layer cache between
# CI runs (proven by the fact the `docker run hivegrid-*:smoke` steps below find images the
# build loaded into the host store). The Dockerfile additionally persists the pnpm store via
# `RUN --mount=type=cache,id=hivegrid-pnpm-store`. The three targets share base/deps/build
# stages, so a single daemon dedupes them within a run. No explicit `--cache-to/--cache-from`
# (type=local/registry) is configured: it would add cold first runs, import/export overhead
# and would require `--load` for the smoke steps, for no gain over the warm host cache.
# `type=gha` is intentionally not used here — it is GitHub-hosted-runner-only.
- name: Build Docker smoke targets
shell: bash
run: |
set -euo pipefail
docker build --target web --build-arg APP_REVISION=ci-smoke-revision --tag hivegrid-web:smoke . &
web_pid=$!
docker build --target api --build-arg APP_REVISION=ci-smoke-revision --tag hivegrid-api:smoke . &
api_pid=$!
docker build --target mcp --build-arg APP_REVISION=ci-smoke-revision --tag hivegrid-mcp:smoke . &
mcp_pid=$!
docker build --target worker --build-arg APP_REVISION=ci-smoke-revision --tag hivegrid-worker:smoke . &
worker_pid=$!
status=0
wait "$web_pid" || status=$?
wait "$api_pid" || status=$?
wait "$mcp_pid" || status=$?
wait "$worker_pid" || status=$?
exit "$status"
- name: Validate web Docker artifacts
run: docker run --rm --entrypoint /bin/sh hivegrid-web:smoke -lc 'test -f /myapp/apps/web/build/server/index.js && test -d /myapp/apps/web/build/client && test -f /myapp/build/server-runtime/server.js'
- name: Validate web Docker runtime
run: bash scripts/docker-web-runtime-smoke.sh hivegrid-web:smoke
env:
DOCKER_WEB_SMOKE_TRANSPORT: exec
- name: Validate API Docker runtime
run: bash scripts/docker-api-runtime-smoke.sh hivegrid-api:smoke
env:
DOCKER_API_SMOKE_TRANSPORT: exec
- name: Validate MCP Docker runtime
run: bash scripts/docker-mcp-runtime-smoke.sh hivegrid-mcp:smoke
env:
DOCKER_MCP_SMOKE_TRANSPORT: exec
- name: Validate worker Docker runtime
run: bash scripts/docker-worker-runtime-smoke.sh hivegrid-worker:smoke
- name: Validate Docker Compose config
run: docker compose config
@@ -1,10 +1,8 @@
name: Coverage
# Gitea variant of .github/workflows/coverage.yml. Runs vitest with --coverage
# and the per-path gate (scripts/verify-test-coverage.mjs) and upserts a
# sticky PR comment via the Gitea API.
#
# Docs: docs/architecture/test-coverage.md
# Enforces the per-path Vitest coverage thresholds on the self-hosted Gitea
# runner. The rendered report is attached to the run so it remains available
# without a GitHub-specific PR-comment action.
on:
pull_request:
@@ -16,6 +14,13 @@ on:
- "scripts/coverage-summary.mjs"
- "vitest.config.ts"
- ".gitea/workflows/coverage.yml"
push:
branches: [main]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
env:
HIVEGRID_GITEA_HOST_IP: ${{ vars.HIVEGRID_GITEA_HOST_IP }}
@@ -36,20 +41,28 @@ jobs:
printf '%s git.tool-ctrl.de\n' "$HIVEGRID_GITEA_HOST_IP" >> /etc/hosts
fi
- name: Checkout PR head
uses: actions/checkout@v4
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -59,20 +72,21 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Run vitest with coverage (enforces per-path gates)
- name: Run Vitest coverage gate
run: pnpm run verify:test-coverage
- name: Render PR coverage comment
if: always()
run: node scripts/coverage-summary.mjs --pr-comment > coverage-comment.md
- name: Upsert Gitea PR comment
- name: Render coverage report
if: always()
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_HOST: ${{ vars.GITEA_HOST || 'git.tool-ctrl.de' }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPO: ${{ github.repository }}
COMMENT_PATH: coverage-comment.md
COMMENT_MARKER: "<!-- coverage-report -->"
run: node scripts/post-coverage-gitea-comment.mjs
COVERAGE_SUMMARY_PATH: coverage-gate/coverage-summary.json
run: node scripts/coverage-summary.mjs --pr-comment > coverage-report.md
- name: Upload coverage report
if: always()
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3
with:
name: coverage-report-${{ gitea.run_id }}
path: |
coverage-gate/
coverage-report.md
retention-days: 14
File diff suppressed because it is too large. Load diff
@@ -9,6 +9,11 @@ name: E2E Readiness
on:
workflow_dispatch:
inputs:
customer_portal_invitation:
description: "Operator-approved disposable VA-P26a invitation, delivered-mail, setup and replay proof"
required: false
default: "false"
type: boolean
plugin_lifecycle_mutation:
description: "Operator-approved disposable run: persist plugin grant/revoke and enable/disable state"
required: false
@@ -64,27 +69,23 @@ env:
E2E_TENANT_ACCOUNT_NAME: E2E Readiness
E2E_TENANT_ACCOUNT_SLUG: e2e-readiness
E2E_TENANT_DASHBOARD_PATH: /e2e-readiness/dashboard
E2E_TENANT_SETTINGS_ACCOUNT_PATH: /e2e-readiness/settings/account
E2E_TENANT_CHAT_PATH: /e2e-readiness/chat/chat_e2e_readiness
E2E_TENANT_SETTINGS_ACCOUNT_PATH: /e2e-readiness/settings/workspace
E2E_TENANT_SETTINGS_PROFILE_PATH: /e2e-readiness/settings/profile
E2E_TENANT_SUBSCRIPTION_PATH: /e2e-readiness/settings/subscription
E2E_TENANT_MEMBERS_PATH: /e2e-readiness/settings/members
E2E_TENANT_ROLES_AND_PERMISSIONS_PATH: /e2e-readiness/settings/roles-and-permissions
E2E_TENANT_NOTIFICATIONS_PATH: /e2e-readiness/settings/notifications
E2E_TENANT_LOGS_PATH: /e2e-readiness/settings/logs
E2E_TENANT_LOG_EVENTS_PATH: /e2e-readiness/settings/logs/events
E2E_TENANT_AUDIT_EXPORT_PATH: /e2e-readiness/settings/audit-export
E2E_TENANT_PRIVACY_PATH: /e2e-readiness/settings/privacy
E2E_TENANT_CHATBOT_PATH: /e2e-readiness/settings/chatbot
E2E_TENANT_AI_USAGE_PATH: /e2e-readiness/settings/ai-usage
E2E_TENANT_API_PATH: /e2e-readiness/settings/api
E2E_TENANT_API_KEYS_PATH: /e2e-readiness/settings/api/keys
E2E_TENANT_API_DOCS_PATH: /e2e-readiness/settings/api/docs
E2E_TENANT_API_LOGS_PATH: /e2e-readiness/settings/api/logs
E2E_TENANT_POLICIES_PATH: /e2e-readiness/settings/policies
E2E_TENANT_PORTAL_ANALYTICS_PATH: /e2e-readiness/portals/e2e-readiness/analytics
E2E_TENANT_PORTAL_SETTINGS_PATH: /e2e-readiness/portals/e2e-readiness/settings
E2E_TENANT_SUBSCRIPTION_PATH: /e2e-readiness/settings/billing
E2E_TENANT_MEMBERS_PATH: /e2e-readiness/settings/team
E2E_TENANT_ROLES_AND_PERMISSIONS_PATH: /e2e-readiness/settings/team/roles
E2E_TENANT_NOTIFICATIONS_PATH: /e2e-readiness/settings/profile/notifications
E2E_TENANT_LOGS_PATH: /e2e-readiness/settings/compliance
E2E_TENANT_LOG_EVENTS_PATH: /e2e-readiness/settings/compliance/events
E2E_TENANT_AUDIT_EXPORT_PATH: /e2e-readiness/settings/compliance/audit-export
E2E_TENANT_PRIVACY_PATH: /e2e-readiness/settings/profile/data
E2E_TENANT_API_PATH: /e2e-readiness/settings/integrations/api
E2E_TENANT_API_KEYS_PATH: /e2e-readiness/settings/integrations/api/keys
E2E_TENANT_API_LOGS_PATH: /e2e-readiness/settings/integrations/api/logs
E2E_TENANT_POLICIES_PATH: /e2e-readiness/settings/workspace/policies
E2E_ADMIN_EMAIL_SEQUENCES_PATH: /email-sequences
E2E_PLUGIN_SETTINGS_PATH: /e2e-readiness/settings/plugins
E2E_PLUGIN_SETTINGS_PATH: /e2e-readiness/settings/integrations/plugins
E2E_WORKFLOW_ENGINE_PATH: /e2e-readiness/workflow-engine/workflows
E2E_WORKFLOW_BUILDER_PATH: /e2e-readiness/workflow-engine/workflows/wf_123
E2E_WORKFLOW_RUN_API_PATH: /e2e-readiness/workflow-engine/workflows/wf_123/run/api
@@ -122,19 +123,27 @@ jobs:
fi
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -142,7 +151,7 @@ jobs:
${{ runner.os }}-pnpm-
- name: Cache Playwright browsers
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
@@ -199,9 +208,40 @@ jobs:
- name: Run strict E2E readiness suite
run: pnpm run verify:e2e-a11y
- name: Run operator-gated VA-P26a invitation lifecycle
if: ${{ github.event_name == 'workflow_dispatch' && inputs.customer_portal_invitation }}
env:
E2E_BASE_URL: https://staging-app.hivegrid.de
E2E_TENANT_EMAIL: ${{ secrets.E2E_PORTAL_INVITATION_ADMIN_EMAIL }}
E2E_TENANT_PASSWORD: ${{ secrets.E2E_PORTAL_INVITATION_ADMIN_PASSWORD }}
E2E_TENANT_CUSTOMER_PORTAL_SETTINGS_PATH: /demo-pro-crm/settings/customer-portal
E2E_PORTAL_BASE_URL: https://staging-portal.hivegrid.de
E2E_PORTAL_TENANT_SLUG: demo-pro-crm
E2E_PORTAL_INVITATION_ENTRYPOINT: admin
E2E_PORTAL_INVITATION_EXPECTED_PROJECT: ${{ vars.E2E_PORTAL_INVITATION_EXPECTED_PROJECT }}
E2E_PORTAL_INVITATION_SETUP_PASSWORD: ${{ secrets.E2E_PORTAL_INVITATION_SETUP_PASSWORD }}
E2E_PORTAL_SETUP_MAIL_FIXTURE_URL: ${{ secrets.E2E_PORTAL_SETUP_MAIL_FIXTURE_URL }}
E2E_PORTAL_SETUP_MAIL_FIXTURE_TOKEN: ${{ secrets.E2E_PORTAL_SETUP_MAIL_FIXTURE_TOKEN }}
E2E_PORTAL_SETUP_MAIL_FIXTURE_TIMEOUT_MS: "90000"
E2E_ALLOW_CUSTOMER_PORTAL_P26A_INVITATION_MUTATION: "1"
REQUIRE_E2E_READINESS: "1"
REQUIRE_E2E_MUTATING_READINESS: "1"
run: |
run_id="${GITHUB_RUN_ID:-}"
run_attempt="${GITHUB_RUN_ATTEMPT:-1}"
case "$run_id:$run_attempt" in
*[!0-9:]*|":"|*:*:*) echo "Invalid workflow run identity" >&2; exit 1 ;;
esac
correlation_key="p26a-${run_id}-${run_attempt}"
export E2E_PORTAL_SETUP_MAIL_FIXTURE_KEY="$correlation_key"
export E2E_PORTAL_INVITATION_EMAIL="customer-portal-invitation+${correlation_key}@saas-ctrl.com"
export E2E_PORTAL_INVITATION_FIRST_NAME="Portal"
export E2E_PORTAL_INVITATION_LAST_NAME="Invitation E2E"
pnpm run verify:e2e-customer-portal-invitation
- name: Upload Playwright traces
if: always()
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3
with:
name: e2e-readiness-results
path: test-results/
@@ -37,7 +37,15 @@ jobs:
fi
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Mint Lighthouse session cookie
run: node scripts/rotate-lighthouse-session-cookie.mjs
@@ -46,11 +54,11 @@ jobs:
LIGHTHOUSE_LOGIN_EMAIL: ${{ secrets.LIGHTHOUSE_LOGIN_EMAIL }}
LIGHTHOUSE_LOGIN_PASSWORD: ${{ secrets.LIGHTHOUSE_LOGIN_PASSWORD }}
LIGHTHOUSE_SESSION_COOKIE: ${{ secrets.LIGHTHOUSE_SESSION_COOKIE }}
LIGHTHOUSE_SESSION_COOKIE_NAME: hivegrid_session
LIGHTHOUSE_SESSION_COOKIE_NAME: __Host-hivegrid_app_session
LIGHTHOUSE_COOKIE_DOMAIN: app.hivegrid.de
- name: Install Chromium
# The Gitea runner image (node:20-bookworm) ships no browser; LHCI's
# The Gitea runner base image ships no browser; LHCI's
# healthcheck otherwise fails with "Chrome installation not found".
run: |
apt-get update
@@ -58,14 +66,14 @@ jobs:
rm -rf /var/lib/apt/lists/*
- name: Run Lighthouse-CI against staging
run: npx --yes @lhci/cli@0.13.x autorun --config=./.lighthouserc.staging.json
run: npx --yes @lhci/cli@0.13.0 autorun --config=./.lighthouserc.staging.json
env:
# chromium installs to /usr/bin/chromium on Debian bookworm.
CHROME_PATH: /usr/bin/chromium
- name: Upload Lighthouse artifacts
if: always()
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3
with:
name: lighthouse-ci-results
path: .lighthouseci/
@@ -0,0 +1,223 @@
name: Repository Metrics
on:
push:
branches:
- main
workflow_dispatch:
concurrency:
group: loc-history-main
cancel-in-progress: true
permissions:
contents: write
env:
GITEA_HOST: ${{ vars.GITEA_HOST || 'git.tool-ctrl.de' }}
HIVEGRID_GITEA_HOST_IP: ${{ vars.HIVEGRID_GITEA_HOST_IP }}
LOC_METRICS_OUTPUT_DIR: /tmp/hivegrid-loc-history
SOURCE_REF: ${{ gitea.ref }}
SOURCE_SHA: ${{ gitea.sha }}
jobs:
publish:
name: Generate and publish repository metrics
runs-on: toolctrl-ci
timeout-minutes: 10
steps:
- name: Resolve internal Gitea host
run: |
if [ -n "${HIVEGRID_GITEA_HOST_IP:-}" ]; then
if ! HIVEGRID_GITEA_HOST_IP="$HIVEGRID_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.HIVEGRID_GITEA_HOST_IP || "") ? 0 : 1)'; then
echo "HIVEGRID_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
exit 1
fi
printf '%s git.tool-ctrl.de\n' "$HIVEGRID_GITEA_HOST_IP" >> /etc/hosts
fi
- name: Checkout full mainline history
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Verify source revision
run: |
set -eu
if [ "$SOURCE_REF" != "refs/heads/main" ]; then
echo "Repository metrics may only be published from refs/heads/main"
exit 1
fi
if ! printf '%s' "$SOURCE_SHA" | grep -Eq '^[0-9a-f]{40}$'; then
echo "Gitea SHA must be a full 40-character commit SHA"
exit 1
fi
if [ "$(git rev-parse HEAD)" != "$SOURCE_SHA" ]; then
echo "Checked-out HEAD does not match the Gitea event SHA"
exit 1
fi
- name: Generate repository metrics
run: |
mkdir -p "$LOC_METRICS_OUTPUT_DIR"
node scripts/metrics/loc-history.mjs \
--ref HEAD \
--label origin/main \
--output-dir "$LOC_METRICS_OUTPUT_DIR"
node scripts/metrics/commit-history.mjs \
--ref HEAD \
--label origin/main \
--days 60 \
--output-dir "$LOC_METRICS_OUTPUT_DIR"
test -s "$LOC_METRICS_OUTPUT_DIR/commit-history.csv"
test -s "$LOC_METRICS_OUTPUT_DIR/commit-history.svg"
test -s "$LOC_METRICS_OUTPUT_DIR/loc-history.csv"
test -s "$LOC_METRICS_OUTPUT_DIR/loc-history.svg"
- name: Verify repository-scoped Actions token
env:
LOC_METRICS_GITEA_TOKEN: ${{ gitea.token }}
run: |
node --input-type=module <<'NODE'
const host = process.env.GITEA_HOST ?? "";
const token = process.env.LOC_METRICS_GITEA_TOKEN ?? "";
if (!/^[A-Za-z0-9.-]+(?::\d+)?$/.test(host)) {
throw new Error("GITEA_HOST must be a hostname with an optional port");
}
if (!token) {
throw new Error("The built-in Gitea Actions token is required");
}
const response = await fetch(`https://${host}/api/v1/repos/toolctrl-labs/HiveGrid-Cloud`, {
headers: { Accept: "application/json", Authorization: `token ${token}` },
signal: AbortSignal.timeout(15_000),
});
if (!response.ok) {
throw new Error(`Actions token repository lookup failed with HTTP ${response.status}`);
}
const repository = await response.json();
if (
repository.full_name !== "toolctrl-labs/HiveGrid-Cloud" ||
repository.private !== true ||
repository.permissions?.pull !== true ||
repository.permissions?.push !== true ||
repository.permissions?.admin === true
) {
throw new Error("Actions token must have non-admin write access to exactly HiveGrid-Cloud");
}
const releases = await fetch(`https://${host}/api/v1/repos/toolctrl-labs/HiveGrid-Cloud/releases?limit=1`, {
headers: { Accept: "application/json", Authorization: `token ${token}` },
signal: AbortSignal.timeout(15_000),
});
if (releases.status === 403) {
throw new Error(
"The Actions token cannot read releases. Releases sit in Gitea's repository scope, which the workflow grants via `permissions: contents: write` — `code: write` only covers Git pushes.",
);
}
if (!releases.ok) {
throw new Error(`Actions token release lookup failed with HTTP ${releases.status}`);
}
console.log("Verified repository-scoped non-admin Actions write token with release access");
NODE
- name: Publish repository metrics as release assets
env:
LOC_METRICS_GITEA_TOKEN: ${{ gitea.token }}
run: |
node --input-type=module <<'NODE'
import { readFile } from "node:fs/promises";
// The LOC artefacts used to live on a long-lived `loc-metrics` branch, which
// showed up as abandoned work in every branch listing. They are release
// assets now: one reusable container, stable download URLs for the README,
// and nothing pushed into the repository's Git history.
const REPOSITORY = "toolctrl-labs/HiveGrid-Cloud";
const TAG = "loc-metrics";
const FILES = ["commit-history.csv", "commit-history.svg", "loc-history.csv", "loc-history.svg"];
const host = process.env.GITEA_HOST ?? "";
const token = process.env.LOC_METRICS_GITEA_TOKEN ?? "";
const outputDir = process.env.LOC_METRICS_OUTPUT_DIR ?? "";
const sourceSha = process.env.SOURCE_SHA ?? "";
if (!/^[A-Za-z0-9.-]+(?::\d+)?$/.test(host)) {
throw new Error("GITEA_HOST must be a hostname with an optional port");
}
if (!token) {
throw new Error("The built-in Gitea Actions token is required");
}
const api = `https://${host}/api/v1/repos/${REPOSITORY}`;
async function call(path, init = {}) {
return fetch(`${api}${path}`, {
...init,
headers: { Accept: "application/json", Authorization: `token ${token}`, ...(init.headers ?? {}) },
signal: AbortSignal.timeout(30_000),
});
}
let release;
const lookup = await call(`/releases/tags/${TAG}`);
if (lookup.ok) {
release = await lookup.json();
} else if (lookup.status === 404) {
const created = await call("/releases", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
tag_name: TAG,
target_commitish: sourceSha,
name: "Repository metrics",
body: "Automatically maintained LOC and commit-history artefacts. Not a product release.",
draft: false,
prerelease: false,
}),
});
if (!created.ok) {
throw new Error(`Creating the ${TAG} release failed with HTTP ${created.status}`);
}
release = await created.json();
} else {
throw new Error(`Looking up the ${TAG} release failed with HTTP ${lookup.status}`);
}
const listed = await call(`/releases/${release.id}/assets`);
if (!listed.ok) {
throw new Error(`Listing release assets failed with HTTP ${listed.status}`);
}
const assets = await listed.json();
for (const name of FILES) {
// Gitea cannot replace an asset in place, so the old one is removed
// first. The README link is unavailable for those few seconds.
for (const asset of assets.filter((candidate) => candidate.name === name)) {
const removed = await call(`/releases/${release.id}/assets/${asset.id}`, { method: "DELETE" });
if (!removed.ok && removed.status !== 404) {
throw new Error(`Deleting the previous ${name} failed with HTTP ${removed.status}`);
}
}
const attachment = new FormData();
attachment.set("attachment", new Blob([await readFile(`${outputDir}/${name}`)]), name);
const uploaded = await call(`/releases/${release.id}/assets?name=${encodeURIComponent(name)}`, {
method: "POST",
body: attachment,
});
if (!uploaded.ok) {
throw new Error(`Uploading ${name} failed with HTTP ${uploaded.status}`);
}
console.log(`Published ${name} to the ${TAG} release`);
}
NODE
@@ -1,7 +1,6 @@
name: SDK Codegen Drift
# Gitea variant of .github/workflows/sdk-codegen.yml. Re-runs the
# @hivegrid/api-client-ts generation pipeline on PRs that touch the
# Re-runs the @hivegrid/api-client-ts generation pipeline on PRs that touch the
# upstream OpenAPI surface or the SDK package, then verifies the
# committed src/generated/ tree is in sync with openapi.json.
#
@@ -36,19 +35,27 @@ jobs:
fi
- name: Checkout PR head
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Set up Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version-file: .nvmrc
- name: Persist Node.js toolchain
run: bash scripts/ci/persist-node-toolchain.sh
- name: Enable Corepack
run: corepack enable
run: corepack enable --install-directory /usr/local/bin
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Prepare pnpm 11.12.0
run: corepack prepare pnpm@11.12.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
@@ -1,75 +0,0 @@
# Dependabot configuration for supply-chain hygiene.
# Docs: https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
#
# Notes:
# - Dependabot's `npm` ecosystem reads root package.json + the pnpm-lock.yaml.
# Workspace packages under apps/* and packages/* are covered transitively via
# the root lockfile, so a single `directory: "/"` entry is sufficient.
# - assignees/reviewers are intentionally left empty so each fork/clone can
# wire them up via repo-level settings without editing this file.
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
commit-message:
prefix: "chore(deps):"
labels:
- dependencies
assignees: []
reviewers: []
groups:
ai-providers:
patterns:
- "@mistralai/*"
- "mistralai"
- "@scaleway/*"
- "scaleway"
- "@scaleway-sdk/*"
- "aleph-alpha*"
- "@aleph-alpha/*"
react-stack:
patterns:
- "react"
- "react-dom"
- "react-router"
- "@react-router/*"
- "vite"
- "@vitejs/*"
test-tooling:
patterns:
- "vitest"
- "@vitest/*"
- "@testing-library/*"
lint-tooling:
patterns:
- "eslint"
- "eslint-*"
- "@eslint/*"
- "@typescript-eslint/*"
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
commit-message:
prefix: "chore(deps):"
labels:
- dependencies
assignees: []
reviewers: []
- package-ecosystem: docker
directory: "/"
schedule:
interval: monthly
open-pull-requests-limit: 10
commit-message:
prefix: "chore(deps):"
labels:
- dependencies
assignees: []
reviewers: []
@@ -1,82 +0,0 @@
name: Sentry Release
# Reusable workflow that tags a release in our self-hosted Sentry,
# optionally uploads source-maps, correlates commits and marks a deploy.
# Consumed via `uses: ./.github/workflows/_sentry-release.yml`.
on:
workflow_call:
inputs:
project:
description: "Sentry project slug (hivegrid-api|hivegrid-worker|hivegrid-web)"
required: true
type: string
environment:
description: "Deployment environment label (production|staging|preview)"
required: true
type: string
sourcemaps-path:
description: "Directory containing source-maps to upload, or 'none'"
required: false
type: string
default: "none"
sourcemaps-artifact:
description: "Optional workflow artifact to download before source-map upload, or 'none'"
required: false
type: string
default: "none"
secrets:
SENTRY_AUTH_TOKEN:
description: "Sentry auth token (project:releases scope)"
required: true
SENTRY_ORG:
description: "Sentry organisation slug"
required: true
SENTRY_URL:
description: "Sentry self-hosted base URL"
required: true
jobs:
release:
name: Sentry release (${{ inputs.project }})
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Download source-map artifact
if: ${{ inputs.sourcemaps-artifact != 'none' }}
uses: actions/download-artifact@v4
with:
name: ${{ inputs.sourcemaps-artifact }}
path: ${{ inputs.sourcemaps-path }}
- name: Verify sentry-cli is reachable
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_URL: ${{ secrets.SENTRY_URL }}
run: |
node -v
npx --yes @sentry/cli@2.41.1 --version
- name: Tag Sentry release
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_URL: ${{ secrets.SENTRY_URL }}
run: |
bash scripts/ci/sentry-release.sh \
--project "${{ inputs.project }}" \
--environment "${{ inputs.environment }}" \
--release "${{ github.sha }}" \
--sourcemaps "${{ inputs.sourcemaps-path }}"
@@ -1,66 +0,0 @@
name: Accessibility
# Runs the axe-core vitest suites (apps/web ui components, SkipToContent)
# and the WCAG-2.2-AA color-contrast verifier on every PR + push to main.
#
# Docs: docs/contributing/wcag-audit.md
on:
push:
branches:
- main
pull_request:
permissions:
contents: read
concurrency:
group: a11y-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
axe:
name: axe-core + color-contrast
runs-on: ubuntu-latest
timeout-minutes: 20
env:
DATABASE_URL: postgresql://hivegrid:hivegrid@localhost:5432/hivegrid?schema=public
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Run color-contrast verifier
run: pnpm run verify:color-contrast
- name: Verify accessibility coverage
run: pnpm run verify:a11y-coverage
- name: Run axe vitest suite (test:a11y)
run: pnpm run test:a11y
- name: Verify accessibility lint baseline
run: pnpm run verify:a11y-baseline
- name: Lint accessibility rules (eslint-plugin-jsx-a11y)
run: pnpm run lint
@@ -1,74 +0,0 @@
name: Bundle Budget Baseline
# Captures the main-branch bundle report as an artifact so the
# bundle-budget PR workflow can render Δ-from-main columns. Runs on
# push to main; downstream PR workflow downloads `bundle-baseline-main`.
# Docs: docs/architecture/bundle-budgets.md
on:
push:
branches: [main]
paths:
- "apps/web/**"
- "packages/brand/**"
- "packages/config/**"
- "packages/entitlements/**"
- "packages/form-widget/**"
- "packages/foundation/**"
- "packages/i18n/**"
- "packages/plugin-runtime/**"
- "packages/ui*/**"
- "packages/url/**"
- "packages/view-models/**"
- "package.json"
- "pnpm-lock.yaml"
- "scripts/bundle-budgets.json"
- "scripts/verify-bundle-size.mjs"
- ".github/workflows/bundle-budget-baseline.yml"
permissions:
contents: read
jobs:
capture:
name: Capture bundle baseline
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build web
run: pnpm --filter @hivegrid/web build
- name: Verify aggregate bundle budgets
run: pnpm run verify:bundle-size
- name: Measure bundle sizes
run: node scripts/verify-bundle-size.mjs --json > main-bundle-report.json
- name: Upload baseline artifact
uses: actions/upload-artifact@v4
with:
name: bundle-baseline-main
path: main-bundle-report.json
retention-days: 30
@@ -1,99 +0,0 @@
name: Bundle Budget
# Posts a sticky PR comment with per-route gzip sizes vs scripts/bundle-budgets.json.
# Non-blocking: exceeds-limit routes show a warning row but never fail the PR check.
# Docs: docs/architecture/bundle-budgets.md
on:
pull_request:
paths:
- "apps/web/**"
- "packages/brand/**"
- "packages/config/**"
- "packages/entitlements/**"
- "packages/form-widget/**"
- "packages/foundation/**"
- "packages/i18n/**"
- "packages/plugin-runtime/**"
- "packages/ui*/**"
- "packages/url/**"
- "packages/view-models/**"
- "package.json"
- "pnpm-lock.yaml"
- "scripts/bundle-budgets.json"
- "scripts/verify-bundle-size.mjs"
- ".github/workflows/bundle-budget.yml"
permissions:
contents: read
pull-requests: write
jobs:
measure:
name: Measure & report bundle sizes
runs-on: ubuntu-latest
timeout-minutes: 30
env:
DATABASE_URL: postgresql://hivegrid:hivegrid@localhost:5432/hivegrid?schema=public
steps:
- name: Checkout PR head
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build web (PR head)
run: pnpm --filter @hivegrid/web build
- name: Verify aggregate bundle budgets
run: pnpm run verify:bundle-size
- name: Measure PR bundle sizes
run: node scripts/verify-bundle-size.mjs --json > pr-bundle-report.json
- name: Upload PR bundle report
uses: actions/upload-artifact@v4
with:
name: bundle-report-pr-${{ github.event.pull_request.number }}
path: pr-bundle-report.json
retention-days: 14
- name: Download main baseline (if available)
id: baseline
uses: dawidd6/action-download-artifact@v6
with:
name: bundle-baseline-main
workflow: bundle-budget-baseline.yml
branch: main
path: baseline
if_no_artifact_found: warn
continue-on-error: true
- name: Render PR comment markdown
run: node scripts/render-bundle-budget-comment.mjs \
--current pr-bundle-report.json \
--baseline baseline/main-bundle-report.json \
--out bundle-comment.md
- name: Post sticky PR comment
uses: marocchino/sticky-pull-request-comment@v2
with:
header: bundle-budget-report
path: bundle-comment.md
@@ -1,402 +0,0 @@
name: CI
on:
push:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
quality:
name: Quality Gates
runs-on: ubuntu-latest
timeout-minutes: 45
env:
DATABASE_URL: postgresql://hivegrid:hivegrid@localhost:5432/hivegrid?schema=public
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Verify GitHub CI workflow
run: pnpm run verify:github-ci-workflow
- name: Verify Gitea CI workflow
run: pnpm run verify:gitea-ci-workflow
- name: Verify Gitea deploy workflow
run: pnpm run verify:deploy-workflow
- name: Verify deploy readiness
run: pnpm run verify:deploy-readiness
- name: Verify CI baseline
run: pnpm run verify:ci-baseline
- name: Verify source health
run: pnpm run verify:source-health
- name: Verify ESLint baseline
run: pnpm run verify:eslint-baseline
- name: Verify env drift
run: pnpm run verify:env-drift
- name: Verify health baseline
run: pnpm run verify:health-baseline
- name: Verify API inventory
run: pnpm run verify:api-inventory
- name: Verify tenant isolation report
run: pnpm run verify:tenant-isolation-report
- name: Verify sidebar routes
run: pnpm run verify:sidebar-routes
- name: Verify i18n keys
run: pnpm run verify:i18n
- name: Verify Tenant Auth tenant and onboarding gates
run: |
pnpm run verify:tenant-auth-baseline
pnpm run verify:onboarding-flow
- name: Verify Phase C package boundaries
run: pnpm run verify:phase-c-boundaries
- name: Verify Feature Manifest plugin removal gates
run: |
pnpm run verify:core-build-without-plugins-smoke
pnpm run verify:removed-modules
- name: Verify UI mock static baseline
run: pnpm run verify:ui-visual
- name: Test UI mock hot-swap
run: pnpm run test:hot-swap
- name: Verify accessibility coverage
run: pnpm run verify:a11y-coverage
- name: Test accessibility smoke
run: pnpm run test:a11y
- name: Verify documentation gates
run: |
pnpm run verify:porting-docs-baseline
pnpm run verify:production-docs
pnpm run verify:release-docs
pnpm run verify:docs-links
- name: Typecheck
run: pnpm typecheck
- name: Lint
run: pnpm lint
- name: Foundation package tests
run: pnpm run test:foundation
- name: Workspace package tests
run: pnpm run test:packages
- name: Unit tests
run: pnpm test
- name: Build
env:
HIVEGRID_BUILD_SOURCEMAPS: "1"
run: pnpm run build:ci
- name: Verify bundle size
run: pnpm run verify:bundle-size
- name: Verify web Sentry sourcemaps
run: test -n "$(find apps/web/build/client -type f -name '*.map' -print -quit)"
- name: Upload web Sentry sourcemaps
uses: actions/upload-artifact@v4
with:
name: web-client-sourcemaps
path: apps/web/build/client
if-no-files-found: error
retention-days: 7
- name: Verify production seed artifact
run: pnpm run verify:production-seed-artifact
api:
name: API Service
runs-on: ubuntu-latest
timeout-minutes: 25
env:
DATABASE_URL: postgresql://hivegrid:hivegrid@localhost:5432/hivegrid?schema=public
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Verify OpenAPI security
run: pnpm run verify:openapi-security
- name: Typecheck API
run: pnpm --filter @hivegrid/api typecheck
- name: Test API
run: pnpm exec vitest run apps/api/src
- name: Build API
run: pnpm --filter @hivegrid/api build
worker:
name: Worker Service
runs-on: ubuntu-latest
timeout-minutes: 25
env:
DATABASE_URL: postgresql://hivegrid:hivegrid@localhost:5432/hivegrid?schema=public
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Typecheck Worker
run: pnpm --filter @hivegrid/worker typecheck
- name: Test Worker
run: pnpm --filter @hivegrid/worker exec vitest run
- name: Build Worker
run: pnpm --filter @hivegrid/worker build
- name: Health Check Worker
run: pnpm --filter @hivegrid/worker health
env:
WORKER_ENABLED: "false"
database:
name: Database Checks
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Generate database client
run: pnpm run db:generate
env:
DATABASE_URL: postgresql://hivegrid:hivegrid@localhost:5432/hivegrid?schema=public
- name: Verify migrations schema parity
run: pnpm run verify:migrations-parity
- name: Verify database migration status
if: github.event_name != 'pull_request'
run: pnpm run verify:db-migrate-status
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
- name: Test database package
run: pnpm --filter @hivegrid/db test
docker-smoke:
name: Docker Smoke
runs-on: ubuntu-latest
timeout-minutes: 30
needs: [quality, api, worker, database]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build web Docker target
uses: docker/build-push-action@v7
with:
context: .
target: web
build-args: APP_REVISION=ci-smoke-revision
tags: hivegrid-web:smoke
load: true
push: false
cache-from: type=gha,scope=hivegrid-web-smoke
cache-to: type=gha,mode=max,scope=hivegrid-web-smoke
- name: Validate web Docker artifacts
run: docker run --rm --entrypoint /bin/sh hivegrid-web:smoke -lc 'test -f /myapp/apps/web/build/server/index.js && test -d /myapp/apps/web/build/client && test -f /myapp/build/server-runtime/server.js'
- name: Validate web Docker runtime
run: bash scripts/docker-web-runtime-smoke.sh hivegrid-web:smoke
- name: Build API Docker target
uses: docker/build-push-action@v7
with:
context: .
target: api
build-args: APP_REVISION=ci-smoke-revision
tags: hivegrid-api:smoke
load: true
push: false
cache-from: type=gha,scope=hivegrid-api-smoke
cache-to: type=gha,mode=max,scope=hivegrid-api-smoke
- name: Validate API Docker runtime
run: bash scripts/docker-api-runtime-smoke.sh hivegrid-api:smoke
- name: Build worker Docker target
uses: docker/build-push-action@v7
with:
context: .
target: worker
build-args: APP_REVISION=ci-smoke-revision
tags: hivegrid-worker:smoke
load: true
push: false
cache-from: type=gha,scope=hivegrid-worker-smoke
cache-to: type=gha,mode=max,scope=hivegrid-worker-smoke
- name: Validate worker Docker runtime
run: bash scripts/docker-worker-runtime-smoke.sh hivegrid-worker:smoke
- name: Validate Docker Compose config
run: docker compose config
resolve-sentry-environment:
name: Resolve Sentry environment
runs-on: ubuntu-latest
timeout-minutes: 5
needs: docker-smoke
outputs:
environment: ${{ steps.resolve.outputs.environment }}
steps:
- name: Resolve target environment from ref
id: resolve
run: |
REF="${GITHUB_REF:-}"
if [ "$REF" = "refs/heads/main" ]; then
echo "environment=production" >> "$GITHUB_OUTPUT"
elif [ "$REF" = "refs/heads/staging" ]; then
echo "environment=staging" >> "$GITHUB_OUTPUT"
else
echo "environment=preview" >> "$GITHUB_OUTPUT"
fi
sentry-release-api:
name: Sentry release (api)
needs: resolve-sentry-environment
uses: ./.github/workflows/_sentry-release.yml
with:
project: hivegrid-api
environment: ${{ needs.resolve-sentry-environment.outputs.environment }}
sourcemaps-path: none
secrets:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_URL: ${{ secrets.SENTRY_URL }}
sentry-release-worker:
name: Sentry release (worker)
needs: resolve-sentry-environment
uses: ./.github/workflows/_sentry-release.yml
with:
project: hivegrid-worker
environment: ${{ needs.resolve-sentry-environment.outputs.environment }}
sourcemaps-path: none
secrets:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_URL: ${{ secrets.SENTRY_URL }}
sentry-release-web:
name: Sentry release (web)
needs: resolve-sentry-environment
uses: ./.github/workflows/_sentry-release.yml
with:
project: hivegrid-web
environment: ${{ needs.resolve-sentry-environment.outputs.environment }}
sourcemaps-path: apps/web/build/client
sourcemaps-artifact: web-client-sourcemaps
secrets:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_URL: ${{ secrets.SENTRY_URL }}
@@ -1,25 +0,0 @@
name: "CLA Assistant"
on:
issue_comment:
types: [created]
pull_request_target:
types: [opened,closed,synchronize]
jobs:
CLAAssistant:
runs-on: ubuntu-latest
steps:
- name: "CLA Assistant"
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I acknowledge that I have read the LegacySourceProduct CLA Document and I hereby sign the CLA. I acknowledge that I understand this code is not open source and for commercial purposes. I acknowledge that I am waiving all Intellectual Property Rights; including, but not limited to copyright.') || github.event_name == 'pull_request_target'
# Beta Release
uses: contributor-assistant/github-action@v2.2.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# the below token should have repo scope and must be manually added by you in the repository's secret
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
with:
path-to-signatures: 'signatures/version1/cla.json'
path-to-document: 'https://gist.github.com/AlexandroMtzG/27a8c5dcc65735a8f744efff84e6693f'
branch: 'main'
allowlist: user1,bot*
custom-notsigned-prcomment: 'Thank you for your contribution, please kindly read and sign our [Contributor License Agreement](https://gist.github.com/AlexandroMtzG/27a8c5dcc65735a8f744efff84e6693f) by commenting the following:'
@@ -1,80 +0,0 @@
name: Coverage
# Runs vitest with --coverage and the per-path threshold gate
# (scripts/verify-test-coverage.mjs reads scripts/coverage-targets.json).
# Uploads the lightweight gate summary as an artifact and posts a sticky PR
# comment with the coverage-summary.json totals.
#
# Docs: docs/architecture/test-coverage.md
on:
pull_request:
paths:
- "apps/**"
- "packages/**"
- "scripts/coverage-targets.json"
- "scripts/verify-test-coverage.mjs"
- "scripts/coverage-summary.mjs"
- "vitest.config.ts"
- ".github/workflows/coverage.yml"
push:
branches: [main]
permissions:
contents: read
pull-requests: write
jobs:
coverage:
name: Measure coverage and gate thresholds
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Run vitest with coverage (enforces per-path gates)
env:
HIVEGRID_COVERAGE_GATE: "1"
run: pnpm run verify:test-coverage
- name: Upload coverage gate summary
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-gate-summary-${{ github.run_id }}
path: coverage-gate/coverage-summary.json
retention-days: 14
- name: Render PR coverage comment
if: github.event_name == 'pull_request'
env:
COVERAGE_SUMMARY_PATH: coverage-gate/coverage-summary.json
run: node scripts/coverage-summary.mjs --pr-comment > coverage-comment.md
- name: Post sticky PR comment
if: github.event_name == 'pull_request'
uses: marocchino/sticky-pull-request-comment@v2
with:
header: coverage-report
path: coverage-comment.md
@@ -1,198 +0,0 @@
name: E2E Readiness
# Runs the deployed staging/readiness browser suite in fail-closed mode.
# Main CI intentionally remains browser-free; this lane proves the authenticated
# Playwright/mobile/a11y contract against a live target on schedule or demand.
#
# Docs: docs/testing/e2e-readiness.md
on:
workflow_dispatch:
inputs:
plugin_lifecycle_mutation:
description: "Operator-approved disposable run: persist plugin grant/revoke and enable/disable state"
required: false
default: "false"
type: boolean
plugin_settings_write:
description: "Operator-approved disposable run: persist plugin settings iframe writes"
required: false
default: "false"
type: boolean
workflow_outbox_drain:
description: "Operator-approved run: require worker/outbox drain to terminal WorkflowExecution status"
required: false
default: "false"
type: boolean
workflow_webhook_run:
description: "Operator-approved run: execute the webhook workflow against workflow_webhook_target_url"
required: false
default: "false"
type: boolean
workflow_webhook_target_url:
description: "Operator-owned disposable webhook target URL, required when workflow_webhook_run is true"
required: false
default: ""
type: string
subscription_success:
description: "Operator-approved run: require Stripe checkout success return smoke"
required: false
default: "false"
type: boolean
subscription_success_path:
description: "Externally acquired Stripe checkout success return path, required when subscription_success is true"
required: false
default: ""
type: string
schedule:
# 04:00 UTC nightly, after deploy and Lighthouse windows have settled.
- cron: "0 4 * * *"
permissions:
contents: read
env:
E2E_BASE_URL: https://app.hivegrid.de
E2E_A11Y_STRICT: "1"
E2E_BROWSER_MATRIX: "1"
E2E_ALLOW_WORKFLOW_RUN: "1"
REQUIRE_E2E_A11Y: "1"
REQUIRE_AUTH_E2E: "1"
REQUIRE_E2E_READINESS: "1"
E2E_REGISTRATION_EXPECTS_EMAIL_VERIFICATION: "0"
E2E_TENANT_ACCOUNT_NAME: E2E Readiness
E2E_TENANT_ACCOUNT_SLUG: e2e-readiness
E2E_TENANT_DASHBOARD_PATH: /e2e-readiness/dashboard
E2E_TENANT_SETTINGS_ACCOUNT_PATH: /e2e-readiness/settings/account
E2E_TENANT_SETTINGS_PROFILE_PATH: /e2e-readiness/settings/profile
E2E_TENANT_SUBSCRIPTION_PATH: /e2e-readiness/settings/subscription
E2E_TENANT_MEMBERS_PATH: /e2e-readiness/settings/members
E2E_TENANT_ROLES_AND_PERMISSIONS_PATH: /e2e-readiness/settings/roles-and-permissions
E2E_TENANT_NOTIFICATIONS_PATH: /e2e-readiness/settings/notifications
E2E_TENANT_LOGS_PATH: /e2e-readiness/settings/logs
E2E_TENANT_LOG_EVENTS_PATH: /e2e-readiness/settings/logs/events
E2E_TENANT_AUDIT_EXPORT_PATH: /e2e-readiness/settings/audit-export
E2E_TENANT_PRIVACY_PATH: /e2e-readiness/settings/privacy
E2E_TENANT_CHATBOT_PATH: /e2e-readiness/settings/chatbot
E2E_TENANT_AI_USAGE_PATH: /e2e-readiness/settings/ai-usage
E2E_TENANT_API_PATH: /e2e-readiness/settings/api
E2E_TENANT_API_KEYS_PATH: /e2e-readiness/settings/api/keys
E2E_TENANT_API_DOCS_PATH: /e2e-readiness/settings/api/docs
E2E_TENANT_API_LOGS_PATH: /e2e-readiness/settings/api/logs
E2E_TENANT_POLICIES_PATH: /e2e-readiness/settings/policies
E2E_TENANT_PORTAL_ANALYTICS_PATH: /e2e-readiness/portals/e2e-readiness/analytics
E2E_TENANT_PORTAL_SETTINGS_PATH: /e2e-readiness/portals/e2e-readiness/settings
E2E_ADMIN_EMAIL_SEQUENCES_PATH: /email-sequences
E2E_PLUGIN_SETTINGS_PATH: /e2e-readiness/settings/plugins
E2E_WORKFLOW_ENGINE_PATH: /e2e-readiness/workflow-engine/workflows
E2E_WORKFLOW_BUILDER_PATH: /e2e-readiness/workflow-engine/workflows/wf_123
E2E_WORKFLOW_RUN_API_PATH: /e2e-readiness/workflow-engine/workflows/wf_123/run/api
E2E_WORKFLOW_RUN_MANUAL_PATH: /e2e-readiness/workflow-engine/workflows/wf_123/run/manual
E2E_WORKFLOW_WEBHOOK_BUILDER_PATH: /e2e-readiness/workflow-engine/workflows/wf_webhook_123
E2E_WORKFLOW_WEBHOOK_RUN_MANUAL_PATH: /e2e-readiness/workflow-engine/workflows/wf_webhook_123/run/manual
E2E_WORKFLOW_WAITING_BUILDER_PATH: /e2e-readiness/workflow-engine/workflows/wf_waiting_123
E2E_WORKFLOW_WAITING_RUN_MANUAL_PATH: /e2e-readiness/workflow-engine/workflows/wf_waiting_123/run/manual
E2E_WORKFLOW_WAITING_RUN_API_PATH: /e2e-readiness/workflow-engine/workflows/wf_waiting_123/run/api
E2E_WORKFLOW_WAITING_EXECUTIONS_PATH: /e2e-readiness/workflow-engine/workflows/wf_waiting_123/executions
E2E_WORKFLOW_WAITING_EXECUTION_ID: wfe_waiting_123
PLUGIN_BINARY_BASE_PATH: /tmp/e2e-plugins
PLAYWRIGHT_BROWSERS_PATH: .cache/ms-playwright
jobs:
readiness:
name: Strict Playwright readiness
runs-on: ubuntu-latest
timeout-minutes: 45
env:
E2E_TENANT_EMAIL: ${{ secrets.E2E_TENANT_EMAIL }}
E2E_TENANT_PASSWORD: ${{ secrets.E2E_TENANT_PASSWORD }}
E2E_PLUGIN_READONLY_EMAIL: ${{ secrets.E2E_PLUGIN_READONLY_EMAIL }}
E2E_PLUGIN_READONLY_PASSWORD: ${{ secrets.E2E_PLUGIN_READONLY_PASSWORD }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: .cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-playwright-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Install Playwright browsers
run: pnpm exec playwright install --with-deps chromium webkit
- name: Apply manual operator E2E opt-ins
if: ${{ github.event_name == 'workflow_dispatch' }}
# Bind dispatch inputs to env vars instead of interpolating ${{ inputs.* }}
# straight into the shell, so a crafted value cannot inject commands or
# extra lines into $GITHUB_ENV (CI script injection). Free-form URL/path
# inputs are additionally allowlist-validated before being written.
env:
OPT_PLUGIN_LIFECYCLE_MUTATION: ${{ inputs.plugin_lifecycle_mutation }}
OPT_PLUGIN_SETTINGS_WRITE: ${{ inputs.plugin_settings_write }}
OPT_WORKFLOW_OUTBOX_DRAIN: ${{ inputs.workflow_outbox_drain }}
OPT_WORKFLOW_WEBHOOK_RUN: ${{ inputs.workflow_webhook_run }}
OPT_WORKFLOW_WEBHOOK_TARGET_URL: ${{ inputs.workflow_webhook_target_url }}
OPT_SUBSCRIPTION_SUCCESS: ${{ inputs.subscription_success }}
OPT_SUBSCRIPTION_SUCCESS_PATH: ${{ inputs.subscription_success_path }}
run: |
if [ "$OPT_PLUGIN_LIFECYCLE_MUTATION" = "true" ]; then
echo "E2E_ALLOW_PLUGIN_LIFECYCLE_MUTATION=1" >> "$GITHUB_ENV"
fi
if [ "$OPT_PLUGIN_SETTINGS_WRITE" = "true" ]; then
echo "E2E_ALLOW_PLUGIN_SETTINGS_WRITE=1" >> "$GITHUB_ENV"
fi
if [ "$OPT_WORKFLOW_OUTBOX_DRAIN" = "true" ]; then
echo "E2E_REQUIRE_WORKFLOW_OUTBOX_DRAIN=1" >> "$GITHUB_ENV"
fi
if [ "$OPT_WORKFLOW_WEBHOOK_RUN" = "true" ]; then
echo "E2E_ALLOW_WORKFLOW_WEBHOOK_RUN=1" >> "$GITHUB_ENV"
case "$OPT_WORKFLOW_WEBHOOK_TARGET_URL" in
"") ;;
*[!a-zA-Z0-9:/?._~=%\&-]*) echo "Invalid workflow_webhook_target_url" >&2; exit 1 ;;
*) printf 'E2E_WORKFLOW_WEBHOOK_TARGET_URL=%s\n' "$OPT_WORKFLOW_WEBHOOK_TARGET_URL" >> "$GITHUB_ENV" ;;
esac
fi
if [ "$OPT_SUBSCRIPTION_SUCCESS" = "true" ]; then
echo "E2E_REQUIRE_SUBSCRIPTION_SUCCESS=1" >> "$GITHUB_ENV"
case "$OPT_SUBSCRIPTION_SUCCESS_PATH" in
"") ;;
*[!a-zA-Z0-9:/?._~=%\&-]*) echo "Invalid subscription_success_path" >&2; exit 1 ;;
*) printf 'E2E_TENANT_SUBSCRIPTION_SUCCESS_PATH=%s\n' "$OPT_SUBSCRIPTION_SUCCESS_PATH" >> "$GITHUB_ENV" ;;
esac
fi
- name: Run strict E2E readiness suite
run: pnpm run verify:e2e-a11y
- name: Upload Playwright traces
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e-readiness-results
path: test-results/
if-no-files-found: ignore
retention-days: 14
@@ -1,43 +0,0 @@
name: Lighthouse CI
# GitHub mirror of .gitea/workflows/lighthouse.yml. Audits the deployed
# staging site (https://app.hivegrid.de) nightly + on manual dispatch.
# See the Gitea variant and docs/architecture/lighthouse.md for the rationale
# behind auditing a deployed environment rather than a CI-local server.
on:
workflow_dispatch:
schedule:
# 03:00 UTC nightly — after the day's deploys have settled.
- cron: "0 3 * * *"
jobs:
lighthouse:
name: Run Lighthouse audits
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Mint Lighthouse session cookie
run: node scripts/rotate-lighthouse-session-cookie.mjs
env:
LIGHTHOUSE_LOGIN_URL: https://app.hivegrid.de/login
LIGHTHOUSE_LOGIN_EMAIL: ${{ secrets.LIGHTHOUSE_LOGIN_EMAIL }}
LIGHTHOUSE_LOGIN_PASSWORD: ${{ secrets.LIGHTHOUSE_LOGIN_PASSWORD }}
LIGHTHOUSE_SESSION_COOKIE: ${{ secrets.LIGHTHOUSE_SESSION_COOKIE }}
LIGHTHOUSE_SESSION_COOKIE_NAME: hivegrid_session
LIGHTHOUSE_COOKIE_DOMAIN: app.hivegrid.de
- name: Run Lighthouse-CI against staging
# ubuntu-latest ships Chrome pre-installed; no browser setup needed.
run: npx --yes @lhci/cli@0.13.x autorun --config=./.lighthouserc.staging.json
- name: Upload Lighthouse artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: lighthouse-ci-results
path: .lighthouseci/
retention-days: 14
@@ -1,83 +0,0 @@
name: SDK Codegen Drift
# Re-runs the @hivegrid/api-client-ts generation pipeline on PRs that touch
# the upstream OpenAPI surface (apps/api/src/openapi.ts) or the SDK package
# itself, then verifies the committed src/generated/ tree is in sync with
# the captured openapi.json.
#
# Drift is a hard failure: regenerating + committing is part of the PR.
#
# Docs: docs/sdks/typescript.md
on:
pull_request:
paths:
- "apps/api/src/openapi.ts"
- "apps/api/src/openapi.test.ts"
- "packages/api-client-ts/**"
- "packages/api-types/**"
- ".github/workflows/sdk-codegen.yml"
permissions:
contents: read
pull-requests: write
jobs:
drift-check:
name: Verify SDK codegen is in sync with OpenAPI spec
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout PR head
uses: actions/checkout@v4
- name: Enable Corepack
run: corepack enable
- name: Prepare pnpm 10.33.0
run: corepack prepare pnpm@10.33.0 --activate
- name: Configure pnpm store
run: pnpm config set store-dir .pnpm-store
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: .pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-
- name: Install dependencies
run: pnpm install --frozen-lockfile --prefer-offline
- name: Regenerate OpenAPI capture
run: pnpm --filter @hivegrid/api-client-ts generate-spec
- name: Regenerate typed client (Hey-API)
run: pnpm --filter @hivegrid/api-client-ts generate
- name: Fail if generated code drifts from committed state
run: |
if ! git diff --exit-code --stat \
packages/api-client-ts/openapi.json \
packages/api-client-ts/src/generated; then
echo ""
echo "SDK codegen drift detected. Run:"
echo ""
echo " pnpm --filter @hivegrid/api-client-ts generate:all"
echo ""
echo "then commit packages/api-client-ts/openapi.json and packages/api-client-ts/src/generated/."
exit 1
fi
echo "SDK codegen is in sync with the upstream OpenAPI spec."
- name: Typecheck SDK packages
run: |
pnpm --filter @hivegrid/api-client-ts typecheck
pnpm --filter @hivegrid/api-types typecheck
- name: Run SDK tests
run: |
pnpm --filter @hivegrid/api-client-ts test
pnpm --filter @hivegrid/api-types test
@@ -40,7 +40,11 @@ tsconfig.tsbuildinfo
.react-router/
**/.react-router/
apps/web/app/generated/prisma/
.claude/
.claude/*
!.claude/skills/
.claude/skills/*
!.claude/skills/plan-ticket/
!.claude/skills/subframe-einbinden/
.cursor
__pycache__
@@ -59,6 +63,8 @@ node_modules/
.next/
dist/
build/
build-portal/
build-sourcemaps/
!apps/web/app/utils/build/
!apps/web/app/utils/build/**
__pycache__/
@@ -70,6 +76,10 @@ vendor/
*.log
coverage/
coverage-gate/
coverage-detail/
coverage-session-detail/
/playwright-report/
/test-results/
.cache/
tmp/
@@ -82,9 +92,9 @@ sbom-pnpm.json
# Plugin runtime external-audit packages (scripts/build-plugin-audit-package.sh output)
artifacts/plugin-audit/
# GSD baseline (auto-generated)
.gsd
.gsd-id
# Local LOC output; CI publishes the canonical artifacts to the loc-metrics branch.
/docs/metrics/
.mcp.json
nul
nul.*
@@ -1 +1 @@
v22.12.0
v24.18.0
@@ -133,25 +133,25 @@ Du baust sequenziell, aber der Designer liegt vor dir. Pro Block: was du baust +
### 6a. Pro Screen — die Designer→Backend-Übergabe (Checkliste)
```
[ ] 1. UI-SPEC existiert /gsd-ui-phase N → Element-Liste + Zustände + Interaktionen
[ ] 1. UI-SPEC existiert Element-Liste + Zustände + Interaktionen
[ ] 2. Screen designt Designer liefert Subframe-Screen (aus der Element-Liste!)
[ ] 3. RECONCILIATION ◄── kritischster Check:
[ ] jedes angezeigte Feld hat eine Datenquelle (Modell/Spec)? (keine „unmöglichen Daten")
[ ] jede Aktion/Button mappt auf eine Domänen-Operation?
[ ] Zustände designt: leer / laden / Fehler / keine-Berechtigung?
[ ] 4. VM ableiten VM-Typ + Action-Callbacks aus dem Screen lesen
[ ] 5. Backend bauen /gsd-plan-phase N (Planner baut Loader/Actions gegen das VM) → execute
[ ] 5. Backend bauen Loader/Actions gegen das VM bauen
[ ] 6. Integration Adapter bindet Screen an VM → Smoke-Test grün
[ ] 7. Visual-Reg-Baseline Playwright-Baseline für den Screen setzen
[ ] 8. Hot-Swap-Drill CI tauscht gegen ui-mock → läuft noch? (beweist saubere Trennung)
```
### 6b. Pro Phase — GSD-Gates (automatisch)
### 6b. Pro Ticket — Planungs- und Verifikationsgates
- **Source-Coverage-Audit** (Planner): jedes Phase-Requirement in einem Plan.
- **must_haves** (goal-backward): Truths/Artefakte/Key-Links erfüllt.
- **plan-checker**: Pläne erreichen das Ziel (vor dem Bauen, Loop ≤3×).
- **execute-phase Verifier**: Phasen-Ziel goal-backward erfüllt.
- Ticket-DoD vollständig und mit Proof belegt.
- Abhängigkeiten in beide Richtungen geprüft.
- Passende fokussierte Tests und Repo-Gates grün.
- Plane-Status entspricht dem nachgewiesenen DoD-Stand.
### 6c. Projektweit — Dauergates (CI, jeder Merge)
@@ -162,7 +162,7 @@ Du baust sequenziell, aber der Designer liegt vor dir. Pro Block: was du baust +
### 6d. Stakeholder — Noah/Geerkens (AD-19)
Nach jeder UI-Phase: **PROGRESS-TRACKER-Klick-Pfad** → Noah validiert den echten Screen. Designer-first ist hier im Vorteil: Noah sieht reale Screens früh, nicht erst beim Big-Bang.
Nach jeder UI-Phase: **UAT-Klick-Pfad der Ticket-Doc** → Noah validiert den echten Screen. Designer-first ist hier im Vorteil: Noah sieht reale Screens früh, nicht erst beim Big-Bang.
---
@@ -174,4 +174,4 @@ Nach jeder UI-Phase: **PROGRESS-TRACKER-Klick-Pfad** → Noah validiert den echt
---
*Erstellt 2026-06-08 als Ergänzung zu ROADMAP.md / PHASE-SOURCES.md für den designer-first-Modus.*
*Erstellt 2026-06-08; am 2026-08-02 auf den ticket-getriebenen Arbeitsmodus umgestellt.*
@@ -21,9 +21,12 @@ css: |-
# ENTITÄTENMODELL HiveGrid 2.0
**Stand:** 16.06.2026 · **Status: ✅ APPROVED & LOCKED** (Projekt-zentrisch, AD-20; **offene Modellierungs-Fragen entschieden 16.06.**, s.u.) · **Quelle:** Davids konsolidiertes CRM/Pipeline-Briefing (`HiveGrid_CRM_Datenlogik_UX_Entscheidungen.md`) für den Kern + Modul-Specs (`_bmad-output/specs/`, Block A) für die unveränderten Domänen.
**Stand:** 16.06.2026 · **Status: ✅ APPROVED & LOCKED** (Projekt-zentrisch, AD-20;
**offene Modellierungs-Fragen entschieden 16.06.**, s.u.) · **Quelle:** Davids konsolidiertes
CRM/Pipeline-Briefing (`HiveGrid_CRM_Datenlogik_UX_Entscheidungen.md`) plus die genehmigten
Requirements und Architekturentscheidungen. Dieses Dokument ist selbst die bindende Datenmodellquelle.
> ✅ **Projekt-zentrisches Modell (AD-20) — verbindlich.** Der CRM/Pipeline-Kern: EIN `Projekt`-Kern + konfigurierbare **Pipeline-Views** + **Pipeline-Feld-Config-Layer**; `Kontakt`-Oberbegriff (Kontakttyp/-status/-art); **Lead → Projekt**; **Rechnung** als Sub-Entity (v1); **Abnahme** als Checklisten/Protokoll-Sub-Area. „Deal" und „Auftrag" sind **Pipeline-Typen, keine eigenen Entitäten**. Maschinenlesbar: `entity-model.dbml` (ER-Diagramm: `entity-model.svg`). Laienfassung: `ENTITY-MODELL-ERKLAERUNG.pdf`. **Hinweis zu den Domänen 6–13 unten** (Auth, Files, Apps, Suche, Automation/KI, Kommunikation, Kalender/Forms, HR, Admin, Billing, Onboarding): vom Pivot unberührt — wo dort `Deal`/`Project` steht, ist der `Projekt`-Kern gemeint, wo `Contact`/`Company` steht, der `Kontakt`-Oberbegriff.
> ✅ **Projekt-zentrisches Modell (AD-20) — verbindlich.** Der CRM/Pipeline-Kern: EIN `Projekt`-Kern + konfigurierbare **Pipeline-Views** + **Pipeline-Feld-Config-Layer**; `Kontakt`-Oberbegriff (Kontakttyp/-status/-art); **Lead → Projekt**; **Rechnung** als Sub-Entity (v1); **Abnahme** als Checklisten/Protokoll-Sub-Area. „Deal" und „Auftrag" sind **Pipeline-Typen, keine eigenen Entitäten**. Maschinenlesbar: `entity-model.dbml` (ER-Diagramm: `entity-model.svg`). Laienfassung: `ENTITY-MODELL-ERKLAERUNG.md`. **Hinweis zu den Domänen 6–13 unten** (Auth, Files, Apps, Suche, Automation/KI, Kommunikation, Kalender/Forms, HR, Admin, Billing, Onboarding): vom Pivot unberührt — wo dort `Deal`/`Project` steht, ist der `Projekt`-Kern gemeint, wo `Contact`/`Company` steht, der `Kontakt`-Oberbegriff.
## Lies das zuerst (3 Architektur-Grundregeln)
@@ -65,9 +68,9 @@ Diese werden von vielen Modulen geschrieben/referenziert. Sie sind der Grund, wa
| **FileEntityLink** [v1] | Files | M:N Datei ↔ beliebige Entität | `file_id` + `entity_type` + `entity_id` + `link_role` [polymorph] |
| **CustomFieldDefinition / CustomFieldValue** [v1] | CRM | Tenant-eigene Felder auf Projekt/Kontakt/Lead/Rechnung | Definition (Typ, Entity-Ziel) ← Value (entity_id + Wert) · pro Pipeline via `PipelineFieldConfig` schaltbar |
| **Tag / TagAssignment** [v1] | CRM | Farbige Tags, entity-übergreifend | Tag (name, color) ↔ Assignment (entity_type + entity_id) [polymorph] |
| **SearchIndexEntry** [v1] | Suche | Zentraler Such-Index über alle Entitäten | `entity_type/id` · `tsvector_de` (FTS) · ~~`embedding` pgvector **[v2-Spalte]**~~ → ruht, RAG entfällt ([[AD-26]]) · `permission_subject` |
| **SearchIndexEntry** [v1] | Suche | Tenant-scoped Metadatenprojektion für den Meilisearch-Keyword-Index | `entity_type/id` · `title/subtitle/body_text` · `route_path/source_index` · `permission_subject` · `last_indexed_at` · Archive/Demo/Metadata |
| **HiveNumberSeq** [v1] | Sales | Fortlaufende Nummern (P-2026-0042, R-2026-0042) | pro `tenant_id` + `entity_type`, multi-tenant-sicher |
| **DataConnection** [v1] | Apps-Engine | Tenant ↔ externe App (AirCall, PandaDoc, Google, KWP) | `app_id` · `credentials` (verschlüsselt) · `connection_status` |
| **DataConnection** [v1] | Apps-Engine | Tenant ↔ externe App (AirCall, HalloPetra, PandaDoc, Google, KWP) | `app_id` · `credentials` (verschlüsselt) · `connection_status` |
**Die Tenant/User-Achse** (hängt an fast allem): `Tenant 1:N TenantUser N:1 User` · Rollen über `TenantRole` + `Permission` + `RoleAssignment` · `Group` orthogonal (N:M User).
@@ -78,7 +81,7 @@ Diese werden von vielen Modulen geschrieben/referenziert. Sie sind der Grund, wa
| Tenant | v1 | slug, status (trial/active/past_due/frozen/suspended/deletion_pending), default_language | 1:N TenantUser/Role · [RLS-Wurzel] |
| User | v1 | email, language, timezone, theme_preference, date_format | N:M Tenant (kein RLS, global) |
| TenantUser | v1 | tenant_id, user_id, status | M:N Role via RoleAssignment · [RLS] |
| TenantRole | v1 | name, is_template_origin | 1:N Permission · [RLS] · 6 SHK-Rollen geseedet |
| TenantRole | v1 | name, is_template_origin | 1:N Permission · [RLS] · fünf editierbare SHK-v2-Rollen für neue Workspaces (AD-29) |
| Permission | v1 | role_id, permission_key | [RLS] |
| Group | v1 | name | N:M User · [RLS][Soft-Delete] |
| TenantUserInvitation | v1 | email, token, expires_at, accepted_at | [RLS] · 48h-Token |
@@ -115,7 +118,7 @@ Diese werden von vielen Modulen geschrieben/referenziert. Sie sind der Grund, wa
| Entität | v | Kern-Felder | Relationen / Flags |
|---|---|---|---|
| App | v1 | key (kwp/gmail/aircall), category, connection_type (oauth2/api_key), connection_schema, phase | global, kein RLS |
| App | v1/v2 | key (kwp/gmail/aircall/hallopetra), category, connection_type (oauth2/api_key), connection_schema, phase | global, kein RLS |
| DataConnection | v1 | tenant_id, app_id, credentials (verschlüsselt), connection_status, last_health_check | [RLS] |
| AppSyncRun | v1 | data_connection_id, kind, status, items_total/succeeded/failed, summary_text | [RLS] |
| AppSyncRunLog | v1 | severity, message_text, tech_details | [RLS] |
@@ -164,9 +167,9 @@ Diese werden von vielen Modulen geschrieben/referenziert. Sie sind der Grund, wa
| Entität | v | Kern-Felder | Relationen / Flags |
|---|---|---|---|
| SearchIndexEntry | v1 | entity_type/id, title, body_text, tsvector_de, **~~embedding (pgvector → v2)~~ — ruht, RAG entfällt ([[AD-26]])**, permission_subject, is_archived | [RLS][polymorph] |
| RecentSearch | v1 | user_id, query_text, applied_filters, result_count | [RLS] |
| ~~EmbeddingProviderJob~~ | ~~v1~~ | ~~search_entry_id, provider, status~~ | **ruht — RAG/Embeddings entfallen ([[AD-26]]); Meilisearch-Keyword bleibt** |
| SearchIndexEntry | v1 | entity_type/id, title, subtitle, body_text, route_path, source_index, permission_subject (String), last_indexed_at, is_archived, is_demo_data, metadata | [RLS-Teil-A-Artefakt][polymorph] |
| RecentSearch | v1 | tenant_id, user_id, query_text, applied_filters, result_count | [RLS-Teil-A-Artefakt] |
| ~~EmbeddingProviderJob~~ | ~~v1~~ | ~~search_entry_id, provider, status~~ | **entfernt — RAG/Embeddings entfallen ([[AD-26]]); Meilisearch-Keyword bleibt** |
| Dashboard | v1 | name, is_default_for_role (gf/office/monteur/…), is_shared | [RLS][Soft-Delete] |
| DashboardLayout | v1 | dashboard_id, user_id (NULL=shared), widgets[], layout_data | 3 feste Rollen-Layouts v1 |
| WidgetInstance | v1 | widget_catalog_key, config, position, size | (Custom-Widgets + Drag&Drop → v2) |
@@ -206,11 +209,11 @@ Diese werden von vielen Modulen geschrieben/referenziert. Sie sind der Grund, wa
| EmailTemplate / EmailSender | v1 | body_html / from_name/email, sending_domain_id, is_default | [RLS] |
| RecipientSegment | v1 | entity_type, filter_definition (JSONB), is_static_snapshot | [RLS][Soft-Delete] |
| Unsubscribe / EmailSuppressionList | v1 | kontakt_id, scope, reason / email_address (unique), reason | [RLS] |
| TelephonyConnection | v1 | provider (aircall), oauth_token (verschl.), webhook_secret | max. 1 aktiv/Tenant · [RLS] |
| TelephonyUserBinding | v1 | tenant_user_id ↔ provider_user_id | AirCall-User-Mapping |
| TelephonyConnection | v1/v2 | provider (aircall/hallopetra), data_connection_id, provider_company_id, webhook_id, webhook_token_hash | max. 1 aktiver Telefonie-Provider/Tenant · Provider-Credentials verschlüsselt in `DataConnection.credentials`; Hash nur lokaler Webhook-Lookup-Digest · [RLS] |
| TelephonyUserBinding | v1 | tenant_user_id ↔ provider_user_id | AirCall-User-Mapping; HalloPetra stellt im erhobenen Vertrag keine Provider-User-Ressource bereit |
| TelephonyCallSession | v1 | direction, status, from/to_number (E.164), matched_kontakt/lead/projekt_id, note, recording_url | [RLS][Soft-Delete][polymorph match] |
| TelephonyWebhookEvent | v1 | event_type, signature_valid, processing_status | [append-only][30d] |
| *HalloPetra-Modelle* | **v2** | (M105) | zweiter Telefonie-Adapter |
| TelephonyWebhookEvent | v1/v2 | event_type, provider_auth_valid, processing_status | Aircall: Payload-Token; HalloPetra: separates Custom-Header-Bearer-Secret; nur normalisiertes/redigiertes Event · [append-only][30d] |
| *HalloPetra-Modelle* | **v2** | keine separaten Modelle | zweiter Adapter nutzt dieselbe typisierte Telefonie-Domäne; `post_call` ist ein terminales Inbound-Event |
| TeamChat | v1 | kind (project/group/dm), projekt_id, archived_reason, last_message_at | [RLS][Soft-Delete] |
| TeamChatMember | v1 | chat_id, user_id, role_in_chat, last_read_message_id, is_pinned | [RLS] |
| TeamChatMessage | v1 | chat_id, author, body (Markdown), parent_message_id (Thread), mentions[], attachments[] | [RLS][Soft-Delete] |
@@ -229,7 +232,7 @@ Diese werden von vielen Modulen geschrieben/referenziert. Sie sind der Grund, wa
| BookingPageProvider | v1 | booking_page_id, tenant_user_id | M:N User |
| AvailabilityRule / Exception | v1 | day_of_week, start/end_time / date, kind | Verfügbarkeit |
| Appointment | v1 | booking_page_id, provider_user_id, start/end, status (scheduled/held/cancelled/no_show/rescheduled), kontakt_id\|lead_id, form_submission_id | → Kontakt/Lead/Form · [RLS] |
| Form | v1 | slug, subtype (standard/acceptance_form/onboarding/survey), status, is_public | 1:N Field/Action · [RLS][Soft-Delete] |
| Form | v1 | slug, subtype (standard/acceptance_form/onboarding/survey/booking_intake/hr_request/lead/internal — lead+internal seit WF-P16-S01-Typauswahl, 2026-07-10), status, is_public | 1:N Field/Action · [RLS][Soft-Delete] |
| FormField | v1 | field_key, field_type (12 Typen), required, validation_rules | N:1 Form |
| FormSubmission | v1 | form_id, submission_data (JSON), linked_entity_type/id | [RLS][Soft-Delete][polymorph] |
| FormFile | v1 | submission_id, field_key, file_id | → File |
@@ -262,12 +265,20 @@ Diese werden von vielen Modulen geschrieben/referenziert. Sie sind der Grund, wa
| Entität | v | Kern-Felder | Flags |
|---|---|---|---|
| AdminUser | **v2** | email, password_hash, totp_secret (Pflicht), status | v1 = Boilerplate-Modell mit MFA-Step-up; getrennte Identität → v2 |
| AdminRole / AdminPermission / AdminSession | **v2** | name (super_admin/support/sales) / permission_id / expires_at (8h), ip | parallele RBAC → v2 |
| AdminUser | **v2** | email, name, authentik_subject, authentik_groups, status, last_login_at | Authentik ist der einzige produktive Login; keine produktiven lokalen Credentials |
| AdminRole / AdminPermission / AdminSession | **v2** | name (super_admin/support/sales/engineering/viewer), permission_id, expires_at (8h), ip_hash, mfa_assured_at | eigene RBAC-/Session-Welt; `UserSession` ist keine Admin-Session |
| AdminAuditLog | v1 | admin_user_id, action_type, target_kind/id, summary_text, metadata (Diff) | cross-tenant (tenant_id=null) |
| AdminTenantNote | v1 | tenant_id, note_text, category, pinned | Markdown-Notizen |
| AdminSupportTicket (+ Message) | v1 | source_kind (in_app_feedback_widget/inbound_email), tenant_id, status, priority | speist sich aus Feedback-Widget |
| AdminLead / AdminDeal / AdminLeadActivity | **v2** | (M040 Plattform-Lead-Pipeline) | unser eigenes Sales-Tool |
| AdminLead | **v2 · M040a (`R-LEADS`)** | source_id, external_id?, contact/content nullable, status, assigned_to_admin_user_id?, archived_at?, duplicate_hint_of_lead_id? | operatorweit, **kein tenant_id** · E-Mail nicht Pflicht/Unique · PII |
| AdminLeadActivity | **v2 · M040a (`R-LEADS`)** | lead_id, type (captured/imported/manually_created/status_changed/assigned/note_added/archived/restored), actor_admin_user_id?, payload, created_at | append-only fachlicher Verlauf · schema-validierter/PII-minimierter Payload |
| AdminLeadSource (+ Credential) | **v2 · M040a (`R-LEADS`)** | key, display_name, enabled, default_assignee_admin_user_id?, notify_admin_user_ids, rate_limit; Credential: key_hash/prefix/expires/revoked | Quelle aus Credential, nicht Body · rotierbare gehashte S2S-Keys |
| AdminDeal | **v2 · M040b (`VA-P28b`)** | admin_lead_id, stage, value/arr, probability, won/lost, promoted_tenant_id? | Deal-Kanban/Forecast/Promote-to-Tenant baut auf M040a auf |
**M040-Schnitt (AD-31):** `R-LEADS` baut M040a vorgezogen und ersetzt sowohl das
operatorweite Legacy-Modell `Lead`/`LeadEvent` als auch den separaten
`lead-inbox`-Dienst. `VA-P28b` ergänzt später ausschließlich M040b. Die
tenantgebundene `InboxLead`-Domäne aus P7 bleibt davon strikt getrennt.
## Domäne 12: Billing & Abo-Baukasten (M28) - wichtig: das Recut-Modell
@@ -316,4 +327,4 @@ CheckoutSessionStatus (legacyProvider_checkout_session, intent) ─N:1─▶ Ten
6. **Wertelisten final:** `kontakt_status` = **Kontakt / Kunde / Bestandskunde** ✅ · Label **„Organisation"** (NICHT „Unternehmen" — umfasst auch Vereine/Körperschaften) ✅ · **KWP-Felder komplett aus v1 raus → erst v2** (`ProjektExternesFeld` = [v2], in v1 nicht vorhanden) ✅.
---
*Begleitdateien: `entity-model.dbml` (DBML für dbdiagram.io / ER-Diagramm `entity-model.svg`) · `ENTITY-MODELL-ERKLAERUNG.pdf` (laienverständliche Fassung). Approved-Quelle: `HiveGrid_CRM_Datenlogik_UX_Entscheidungen.md`. Architektur-Entscheidungen: `docs/ARCHITECTURE-DECISIONS.md` (AD-1 RLS, AD-2 First-Class revidiert, AD-20 Projekt-zentrisch).*
*Begleitdateien: `entity-model.dbml` (DBML für dbdiagram.io / ER-Diagramm `entity-model.svg`) · `ENTITY-MODELL-ERKLAERUNG.md` (laienverständliche Fassung). Approved-Quelle: `HiveGrid_CRM_Datenlogik_UX_Entscheidungen.md`. Architektur-Entscheidungen: `docs/ARCHITECTURE-DECISIONS.md` (AD-1 RLS, AD-2 First-Class revidiert, AD-20 Projekt-zentrisch).*
@@ -1,84 +0,0 @@
---
pdf_options:
format: A4
margin: 14mm
landscape: true
css: |-
body { font-size: 10px; font-family: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif; }
h1 { font-size: 18px; } h2 { font-size: 14px; border-bottom: 2px solid #f5a623; padding-bottom: 3px; }
table { font-size: 9px; border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ccc; padding: 3px 5px; text-align: left; vertical-align: top; }
th { background: #fff7e8; }
code { background: #f4f4f4; padding: 1px 3px; font-size: 8.5px; }
---
# Externals-Checkliste — 4-Wochen-Sprint
**Stand:** 2026-06-12 (aktualisiert nach Scope-Schnitt 11.06. — siehe `SCOPE-V1-CUTS.md`) · Abgeglichen mit `.env.example` + allen v1-Phasen.
Spalte „Wer" im Team-Meeting ausfüllen. **Kategorie A heute anstoßen — das sind Wartezeiten, keine Arbeit.**
> **Durch den Scope-Schnitt entfallen/entschärft:** A2 nur noch Calendar-Scope (Gmail raus) · A3 Apple-Konto ruht (kein App-Store in v1/v2 — PWA-only, → v3) · A4 Google Play → v3 · A7 Microsoft Entra → v2 · B3 HalloPetra → v2 · B7 FCM/APNs **entfällt** (PWA → Web-Push/VAPID) · AlephAlpha (B6-Teil) → v2 · Memberspot/Boobora → v2. **AD-6 (Mailjet) + AD-7 (mCaptcha) sind GELOCKT** (Boilerplate-verdrahtet). **NEU: E6 AVV + Auskunfts-Vorlage (Anwalt).**
---
## A — Lange Vorlaufzeit (HEUTE anstoßen, sonst reißt Woche 3–4)
| # | Was | Wofür (Phase) | Vorlauf / Risiko | Wer |
|---|---|---|---|---|
| A1 | **KWP (✅ entschärft, 12.06.):** Hersteller richtet Zugang ein, verfügbar ~**19.07.** (nach Launch → P10 = erstes v2-Modul). **Jetzt erledigen:** (a) Callback-URLs zurückmelden: `https://app.hivegrid.de/integrations/kwp/oauth/callback` + `https://staging-app.hivegrid.de/integrations/kwp/oauth/callback` (PKCE), (b) **kwp-bnWin.net auf 8.1 N3** bei Geerkens-IT aktualisieren | v2-P10 | 🟢 kein Sprint-Risiko mehr; Antwort-Mail diese Woche | |
| A2 | **Google Cloud:** OAuth-App + **nur Calendar-API**-Scope-Verifizierung (Gmail-Scopes entfallen — Postfach-Sync → v2) | P16 Kalender (nur Google; Outlook → v2) | 🟠 Review Tage–Wochen; Testmodus mit Workspace-Konten als Brücke | |
| ~~A3~~ | ~~Apple Developer~~ | **v3** (kein App-Store in v1/v2 — PWA-only, AD-17) | Konto vorhanden, ruht — keine Aktion | — |
| ~~A4~~ | ~~Google Play Console~~ | **v3** (kein App-Store in v1/v2 — PWA-only) | ruht bis native App (v3) | — |
| A5 | **Mollie-Konto + Live-Verifizierung** (Geschäftsdaten, Bankkonto, Webseite-Anforderungen) + Lago-Production-Planung | P20 / BILL-08 | 🟠 Tage; Test-Mode reicht für Entwicklung, Live für Go-Live | |
| A6 | **Sende-Domain einrichten:** SPF/DKIM/DMARC für Mailjet + **Domain-Warm-up** beginnen | P1 (notify), P2 (Einladungen), P14 (Marketing!) | 🟠 DNS sofort; Reputation/Warm-up braucht Laufzeit — je früher, desto besser für Zustellbarkeit | |
| ~~A7~~ | ~~Microsoft Entra (Outlook/Graph)~~ | v2 (Outlook-Kalender + Postfach-Sync → v2) | → v2-Vorbereitung | — |
## B — Konten/Keys anlegen (Tag 1–3, kurzer Vorlauf)
| # | Was | Wofür | Hinweis | Wer |
|---|---|---|---|---|
| B1 | **Mailjet**-Konto + API-Keys | P1/P2/P3/P14 | ✅ Boilerplate bereits verdrahtet (`MAILJET_*`) → **AD-6 heute formal locken** | |
| B2 | **AirCall**-Konto + API/Sandbox + Webhooks | P15 | Sandbox reicht bis W3 | |
| ~~B3~~ | ~~HalloPetra~~ | v2 (M105 → v2) | → v2 | — |
| B4 | **PandaDoc** und/oder **DocuSign** Konto + API (Sandbox) | P16 Signatur | einen Provider für Launch wählen, zweiter später | |
| B5 | **Hetzner-Projekt `HiveGrid` anlegen** (Infra-ADR-009): S3-Object-Storage-Bucket + Token, Storage Box (Backups) · **DEK-Master-Key** in Coolify-Secrets (AD-8 revidiert: app-seitige Envelope-Encryption, kein Cloud-KMS) · ⚠ `SCALEWAY_*`-Env-Vars der Boilerplate auf Hetzner-Endpoint umziehen (S3-API identisch) | P4 (Storage), P5/P17 (DEK), Prod-Compute | 🟢 Stunden — Muster im Infra-Repo | |
| B6 | **Mistral** (La Plateforme) API-Key — **Primär-LLM** (Infra-Wechsel: Scaleway Generative APIs entfallen; zweiter EU-Provider + Whisper → v2) | P13 | ✅ in `.env.example` vorgesehen | |
| ~~B7~~ | ~~FCM/APNs~~ | **entfällt** (PWA → Web-Push/VAPID, kein FCM/APNs-Konto nötig) | v2: VAPID-Keys selbst generieren, notify()-Push-Kanal aktivieren | — |
| B8 | **Geo-IP-Dienst** (ipapi.is / ipstack) API-Key | P2 (Session-Standortanzeige) | ✅ in Boilerplate; EU-Konformität kurz prüfen oder Feature stubben | |
| B9 | **HaveIBeenPwned** k-Anonymity (frei) bzw. API-Key | P2 (Breach-Check) | k-Anonymity-Endpoint ist kostenlos/ohne Key | |
| B10 | **Subframe**-Workspace + Lizenzen für Designer + Devs | Designer-Track ab W1 | sofort, sonst steht D0 | |
## C — Eigene Infra provisionieren (Ops, Woche 1–2)
| # | Was | Wofür | Deadline | Wer |
|---|---|---|---|---|
| C1 | **Meilisearch: läuft bereits zentral auf `node1`** (Infra-ADR-008) — nur **scoped Key minten** (`indexes: ["hivegrid-*"]`, Muster: Boilerplate-Key vom 06.06.; `MEILI_API_KEY`, nicht Master-Key!) | P11 (AD-5) | 🟢 5 Minuten statt Setup | |
| C2 | **mCaptcha: läuft bereits zentral** auf `captcha.saas-ctrl.com` (Infra-ADR-013) — nur ENV anbinden + Sitekey anlegen (AD-7 ✓) | P2 Login, P16 Public-Forms/Booking | 🟢 anbinden statt aufsetzen | |
| C3 | **Hosting/Deploy (Infra-ADR-009/010, ersetzt Fly/Scaleway — `fly.toml` entfernt, `deployment-region-provider-pinning.md` stale!):** Staging auf **`staging-1`** via zentrale **Coolify**-Control-Plane (Muster: Boilerplate läuft dort mit 8 Apps) · Prod = Hetzner-Projekt `HiveGrid` (`hivegrid-db`/`-app`/`-worker`/`-lb`) · Registry = Gitea, build-once/promote (Infra-ADR-005). **Staging (User-Entscheidung 12.06., revidiert): ÖFFENTLICH** auf `staging-app.hivegrid.de` + `staging-api.hivegrid.de` (beide unter dem `*.hivegrid.de`-Wildcard-Zertifikat, kein VPN). **Pflicht-Härtung dafür:** (a) **NUR synthetische Daten** — niemals echte Kunden-/Geerkens-Daten auf Staging (DSGVO; Demo-Seeds reichen), (b) eigene Secrets/Keys je Umgebung (Mollie Test-Mode, Lago Staging, eigene OAuth-Apps, eigene Webhook-Secrets), (c) Webhooks auf staging-api mit HMAC-Signaturpflicht + Rate-Limit, (d) `X-Robots-Tag: noindex` + robots.txt deny, (e) Login wie Prod (TOTP), optional IP-Allowlist nachrüstbar. OAuth-Callbacks: Staging-Redirect-URIs (`staging-app.…`) bei KWP/Google mitregistrieren | ab W1 (CI/Gates brauchen Staging!) | Mitte W1 | |
| C4 | **Postgres + Redis: Coolify-managed** (Staging auf `staging-1`, Prod auf `hivegrid-db` — Muster: mITapp/Boilerplate; PgBouncer auf staging-1 vorhanden, siehe `docs/ops/pgbouncer.md`) | alles | Mitte W1 | |
| C5 | **Domains/DNS + TLS (Cloudflare — `hivegrid.de`-Zone existiert bereits!):** `app.hivegrid.de` + `admin.hivegrid.de` (Host-Routing + Cookie-Domain-Trennung!) + `staging-app.hivegrid.de` + `staging-api.hivegrid.de` (öffentlich, siehe C3) — ein `*.hivegrid.de`-Wildcard deckt alle. Portal/Forms/Booking/Help/API sind **Pfade** unter app.* gemäß `INTEGRATION-CONTRACTS.md` §6 (korrigiert 12.06.) | P1 URL-Schemata, P19 Admin, C3 Staging | W1 | |
| C6 | (Optional) **Authentik** für Admin-SSO (AD-3, optional) | P19 | kann Fast-Follow sein | |
## D — Entscheidungen, die heute fallen können (Boilerplate hat sie quasi getroffen)
| # | Entscheidung | Faktenlage | Aktion |
|---|---|---|---|
| D1 | **AD-6 EU-Email-Provider** | Boilerplate ist auf **Mailjet** verdrahtet (Keys, Webhooks, Worker-Delivery) — Tendenz im ADR war ohnehin Mailjet | Heute locken: ADR-Eintrag auf `Accepted`, Konto anlegen (B1), Domain-Setup (A6) |
| D2 | **AD-7 Captcha** | Boilerplate liefert **self-hosted mCaptcha** inkl. Infra-README — EU-perfekt (PoW, keine US-Firma) | Heute locken: ADR auf `Accepted`, Instanz aufsetzen (C2) |
| D3 | **EU-Sterilisations-Zusatzfunde** | `.env.example` enthält noch **GA-Tracking** (`ANALYTICS_GA_TRACKING_ID`) + **ConvertKit** (US) | In P1-Scope aufnehmen: entfernen/ersetzen (Analytics → EU-Alternative oder raus) |
| D4 | Signatur-Provider primär | PandaDoc **oder** DocuSign für Launch | im Team-Meeting wählen (B4) |
## E — Organisatorisch (Menschen & Termine)
| # | Was | Wann | Wer |
|---|---|---|---|
| E1 | **Noah: 4 Freitags-Slots** für Gate-Demos fest blocken (W1 CRM-Vorschau, W2 CRM, W3 Kette, W4 Voll-Walkthrough) | heute terminieren | |
| E2 | ~~KWP-Ansprechpartner identifizieren~~ ✅ läuft (KWP-Mail an Noah, 12.06.) · **NEU: Noah-Frage — gehört der Lagerist-Arbeitsplatz (M070) zum Validierungs-Versprechen?** (entscheidet, ob die M070-Dünnung hält) | bei Demo #1 (Fr W2) | |
| E3 | Echte SHK-Beispieldaten von Geerkens für Seeds-Validierung (Pipelines, Custom-Felder, Rollen) | bis W2 | |
| E4 | Dev-Zuordnung Tracks A/B/C + Scope-Leiter-Abnahme | Team-Meeting | |
| ~~E5~~ | ~~App-Store-Metadaten~~ → **v3** (kein App-Store in v1/v2 — PWA-only) | — | — |
| **E6** | **AVV-Vertragsvorlage (Auftragsverarbeitung, Art. 28) + DSGVO-Auskunfts-Vorlage** vom Anwalt — Launch-Pflicht für jeden Mandanten! | diese Woche beauftragen | |
---
**Merksatz fürs Meeting:** Kategorie A sind **Wartezeiten** — jede Stunde Verzögerung beim Anstoßen wandert 1:1 ans Ende des Sprints. B+C sind Arbeit, die parallel läuft. D sind Geschenke der Boilerplate — einfach locken.
@@ -1,92 +0,0 @@
# Handoff — D1: Login-2FA-Gate + Trust-Device (Backend)
> **Temporäres Handoff** (löschbar nach Erledigung). Für einen frischen Agenten, der **nur D1** fertigbaut.
> Lies zuerst `AGENTS.md` + `.planning/ticket-docs/R-P2a.md` + `R-P2b.md`. Stand: 2026-06-18.
## Mission
Erzwinge **2FA (TOTP) beim Tenant-Login** (Produktentscheidung 18.06.). Heute fragt der Login **keinen**
TOTP-Code ab (2FA nur als Step-up für sensible Aktionen). Baue das **Login-Gate** als Backend; die
Code-Eingabe-**Screen** liefert David (D-P2) — baue eine minimale funktionale Inline-UI als Swap-Ziel.
## Arbeitsbranch
`p2b-rls` (auf `origin`, enthält Upstream-Merge + komplettes R-P2a inkl. S4b + R-P2b RLS/Lifecycle/Rollen +
D2/D3). Bau D1 **auf `p2b-rls`** weiter (oder eigener Branch off p2b-rls). **Nicht** nach `main` mergen/pushen
(main auto-deployt auf Staging). Alles ist grün: `pnpm test` = 3758 passed | 6 skipped (RLS-Integration skippt ohne DB).
## Toolchain / Befehle (WICHTIG)
- Node **22.12.0** via fnm — vor JEDEM pnpm: `eval "$(fnm env)"; fnm use 22.12.0`
- `pnpm typecheck` · `pnpm lint` (--max-warnings=0) · `pnpm test` · `pnpm run verify:i18n`
- Pre-Push-Hook braucht DB-URLs: `set -a; . ./.env; set +a` vor `git push origin p2b-rls`
- Commits enden mit: `Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>`
## Das Design (so umsetzen)
**Zwei-Schritt-Login** (die bestehende Step-up-Infra reicht NICHT — die setzt schon eingeloggten `userId` voraus):
1. **`loginFromRequest`** (`apps/web/app/modules/users/services/AuthService.ts`, ~Z.156). Nach erfolgreichem
Passwort-Check + `clearFailedLogins(...)`, **vor** der Session-Erstellung:
```ts
const totpStatus = await getUserTotpStatus(user.id); // users.db.server.ts
if (totpStatus?.enabled) {
// KEINE Session. Pending-MFA-Zustand ins SIGNIERTE Cookie: pendingMfaUserId (NICHT userId!)
// + pendingMfaRedirectTo (rohes redirectTo). Antwort { requiresMfa: true } + Set-Cookie.
return beginPendingMfaLogin({ userId: user.id, redirectTo });
}
// sonst: bisheriger Pfad (startServerSession + createUserSession)
```
Da `pendingMfaUserId` ≠ `userId`, gewährt `requireUserId` (liest `userId`) **keinen** Zugriff — Gate hält.
2. **Verify-Route** (neu, tenant-fähig; Muster: `apps/web/app/routeModules/admin/mfa-challenge.impl.ts`).
Liest `pendingMfaUserId` aus dem Cookie → `verifyTotpCode(encryptedSecret, code)` **oder** Recovery-Code
(`apps/web/app/utils/auth/mfa/recovery-codes.server.ts`) → bei Erfolg: `setLoggedUser` + `getHome` +
`startServerSession` (`services/auth/sessionLifecycle.server.ts`) + `createUserSession` (setzt `userId`,
löscht `pendingMfaUserId`). Rate-Limit via `apps/web/app/utils/auth/mfa/challenge-rate-limit.server.ts`.
Routen sind folder-convention-autoregistriert (`createRoutesFromFolders`) — neue Datei = neue Route.
3. **`session.server.ts`**: `pendingMfaUserId?: string` (+ `pendingMfaRedirectTo?`) in den `UserSession`-Typ,
in `createUserSession`/`getUserInfo` durchreichen. `requireUserId` **nicht** ändern (liest `userId`).
4. **Trust-Device** (kann Folgeschritt sein): „diesem Gerät vertrauen → künftig Code überspringen" braucht
einen **PERSISTENTEN Geräte-Marker**, der den Logout überlebt — **NICHT** `UserSession.trustedAt` (das ist
per Session!). Vorschlag: signierter Long-Lived-Cookie `trusted-device` (HMAC über userId+random, serverseitig
gegen eine `TrustedDevice`-Tabelle geprüft) **oder** eine `TrustedDevice`-Tabelle (userId, tokenHash, expiresAt).
In Schritt 1 vor dem Gate prüfen → wenn vertrauenswürdig, MFA überspringen. In Schritt 2 bei „remember" setzen.
## Schlüssel-Dateien
- Login: `apps/web/app/modules/users/services/AuthService.ts` (`loginFromRequest`)
- TOTP: `apps/web/app/services/auth/totp.server.ts` (`verifyTotpCode`, `getTotpSafeStatus`)
- TOTP-Status/Secret: `apps/web/app/utils/db/users.db.server.ts` (`getUserTotpStatus`, `getUserTotpPendingEnrollment`)
- Recovery-Codes: `apps/web/app/utils/auth/mfa/recovery-codes.server.ts`
- MFA-Rate-Limit: `apps/web/app/utils/auth/mfa/challenge-rate-limit.server.ts`
- Admin-Muster (spiegeln): `apps/web/app/routeModules/admin/mfa-challenge.impl.ts`
- Cookie/Session: `apps/web/app/utils/session.server.ts` (+ Test `session.server.test.ts` mockt store/lifecycle)
- Server-Session: `apps/web/app/services/auth/sessionLifecycle.server.ts` (`startServerSession`)
- Enrollment (existiert, Tenant): `apps/web/app/routes/app.$tenant/settings/profile.tsx`
## DoD (D1) — ERLEDIGT 2026-06-18 (Details in `.planning/ticket-docs/R-P2a.md`, Abschnitt „D1")
- [x] TOTP-User bekommt mit Passwort allein **keine** Session (Gate); Antwort `requiresMfa`.
- [x] Verify-Route schließt Login ab (TOTP **und** Recovery-Code), inkl. Server-Session-Erzeugung.
- [x] `requireUserId` lehnt den Pending-Zustand ab (kein Zugriff vor Verify) — unverändert (liest nur `userId`).
- [x] Trust-Device-Skip via persistentem Marker (signiertes `RJ_trusted_device`-Cookie, 30 Tage; ohne DB-Tabelle).
- [x] Minimale Code-Eingabe-UI (data-ui-id) als Swap-Ziel für Davids D-P2 (`routeModules/auth/login-mfa.component.tsx`).
- [x] i18n-Keys (de+en) für alle UI-Texte (`account.loginMfa.*`). Tests: TOTP-User→requiresMfa, Verify-OK→Session,
Verify-Falsch→Reject, Nicht-TOTP-User→normaler Login (Regression). Bestehende Login-Tests bleiben grün.
- [x] `pnpm typecheck` + `pnpm lint` + `pnpm run verify:i18n` + `pnpm test` grün (**3777 passed | 6 skipped**).
> Restpunkt (Folge): tabellengestützte Einzel-Geräte-Widerrufbarkeit (`TrustedDevice`-Tabelle). Handoff
> kann nach Plane-Pflege gelöscht werden.
## Gotchas
- **i18n-Guard**: user-facing Strings MÜSSEN i18n-Keys sein (kein Klartext auf `description`/`title`/Label-Props).
Keys in `apps/web/public/locales/{de,en}/*.json` (Parität!). `auth.json` für Auth-Fehler, `settings.json` (flache Dot-Keys).
- Login-Tests haben Nicht-TOTP-User → der neue Zweig greift dort nicht (additiv, kein Bruch).
- `verifyTotpCode` nimmt das **verschlüsselte** Secret (siehe Admin-impl Z.135 wie es geholt wird).
- AD-21: Schema-Änderungen (falls `TrustedDevice`-Tabelle) via `prisma db push` auf dem Branch; lokale DB war down
→ Docker `pgvector/pgvector:pg16` (Setup-Muster im Header von `apps/web/app/utils/db/.server/rls-tenant-isolation.integration.test.ts`).
## Plane (Ticket-Pflege)
- R-P2a #18 = `4b52fe1d-eb78-42b2-a169-ad410553d86f`; R-P2b #19 = `1a0471a4-3a68-41b6-a21c-421200267230`.
- Token: `~/.cli-tokens/plane` (oder `PLANE_API_KEY`). Base `https://project.tool-ctrl.de`, Workspace `toolctrl`,
Projekt `35d0d968-8ab3-40cc-97b8-b81d917dc5df`. Identität prüfen via `GET /api/v1/users/me/` (muss `raffael` sein).
- Kommentar-Stil: Prefix „Claude: ", 1. Person (= raffael), schlicht, kein AI-Sprech, **keine Em-Dashes (—)**, korrekte Umlaute.
- Abschluss: Ticket-Doc (`.planning/ticket-docs/R-P2a.md`) Umsetzungsstand + Proof ergänzen, dann Plane-Kommentar.
@@ -0,0 +1,112 @@
# Interim-UI → David-Handover — Agent-Anleitung
**Zweck:** Wenn ein Ticket mit einer **Interim-UI** (Vorschau-Screen aus `~/ui`, AD-28) fertig wird, kann der
Interim-Screen an Designer David übergeben werden, damit er die finale Subframe-Optik bauen kann. Diese Doc ist
die Schritt-für-Schritt-Anleitung, wie ein Agent diese Übergabe erzeugt. Basis-Regeln: `INTERIM-UI-PLAYBOOK.md`
+ `INTERIM-UI-DESIGN-STANDARDS.md`.
> **Wann triggern:** Immer wenn im Zuge eines Tickets **mindestens ein** Interim-Screen
> (`apps/web/app/components/screens/<domain>/<Screen>Page.tsx`) neu entsteht. **Nicht ungefragt bauen** — das
> ist Arbeit außerhalb des Ticket-Scopes. Der Agent **fragt den User** (Rückfrage), ob zusätzlich die zwei
> Handover-Artefakte erzeugt werden sollen. Erst nach **explizitem OK** ausführen.
## Was erzeugt wird — zwei Artefakte
1. **One-Liner Brief-Pointer** — eine Zeile im passenden `.planning/designer-briefs/PXX-*.md` dieses Repos,
die David von seinem gewohnten Intake-Kanal auf die Handover-Seite verweist. (Lokale Doc-Änderung in
HiveGrid-Cloud; erreicht David beim nächsten `git pull` seines gebundelten `hivegrid-cloud/`-Checkouts.)
2. **Handover-Seite** — eine Domänen-Seite in Davids Vault
`../HiveGrid-Wireframes/Tickets/Interim-Handover/PXX-<Domain>.md` mit je Screen: D-*-Ziel, Archetyp, Route,
VM-Quelle, benötigte `~/ui`-Elemente, Actions, States, leerer „Davids Delta"-Block. **Plus** eine Zeile im
`INDEX.md` desselben Ordners.
Grundregel (Designer-First): Die Handover-Seite listet nur **Elemente / Daten / Aktionen / States** —
**NIE Layout**. Anordnung ist Davids freie Hand.
## Schritt 0 — Rückfrage an den User
Melde: „Für Ticket `<ID>` ist eine Interim-UI (`<N>` Screen(s) in `screens/<domain>/`) entstanden. Soll ich
zusätzlich (a) den One-Liner-Brief-Pointer in `designer-briefs/<PXX>.md` und (b) die David-Handover-Seite in
`../HiveGrid-Wireframes/Tickets/Interim-Handover/` erzeugen?" — Erst bei OK weiter.
Kläre bei OK zwei Dinge: **welcher Designer-Brief `PXX`** und **welches `D-*`-Ziel-Ticket** die Domäne hat
(steht im Header-Kommentar der `<Screen>Page.tsx` und in der Ticket-Doc). Bei Unklarheit nachfragen.
## Schritt 1 — Screens extrahieren (read-only)
Für jede `apps/web/app/components/screens/<domain>/<Screen>Page.tsx` (Test-/reine Helfer-Dateien wie
`DateField` überspringen) diese Felder rein aus dem Code ziehen — **nichts raten**:
| Feld | Quelle im Code |
|---|---|
| D-*-Ziel + Archetyp (A1–A7) | Header-Kommentar oben in der `<Screen>Page.tsx` (nennt „D-… , archetype A…") |
| Route(n) | passende Datei unter `apps/web/app/routes/app.$tenant/<domain>.*.tsx` (bzw. `routes/admin/*` für Admin-Host) |
| Daten (VM) | der aus `@hivegrid/view-models` importierte VM-Typ + Quelle `packages/view-models/src/<domain>/*.vm.ts` |
| Benötigte UI-Elemente | die `~/ui/components/*`-Imports + `@subframe/core`-Icon-Imports (= das, was David nachbauen muss) |
| Interaktionen (Actions) | die exportierte `…Actions`-Typ-Shape (Callback-Namen + Argumente); bei server-`<form>`-Screens die `intent`-Werte |
| States | Empty / Loading / Permission-Denied(404) — im JSX belegt (EmptyState, `status!=="ready"`, Guard/404) |
Bei vielen Screens: pro Domäne **einen read-only Subagenten** parallel laufen lassen, der die Datensätze im
unten stehenden Format zurückgibt. Keine Datei editieren, nur lesen + Markdown zurückliefern.
## Schritt 2 — Handover-Seite schreiben (in Davids Vault)
Lege bei Bedarf `../HiveGrid-Wireframes/Tickets/Interim-Handover/` an. Schreibe `PXX-<Domain>.md` mit Kopf-Notiz
+ je Screen einem `###`-Record nach dieser Vorlage:
```md
# PXX · <Domäne> (<Bau-Ticket> → <D-*-Ziel>)
> Interim-UI-Referenz (AD-28). Lauffähige `~/ui`-Vorschau-Screens (VM als Prop) im gebundelten
> `03 Quellen und Referenzen/hivegrid-cloud/`-Checkout. **Layout = Davids freie Hand.**
### <ScreenName> · <D-*-Screen-Titel + Archetyp>
- **Interim-Screen:** `apps/web/app/components/screens/<domain>/<Screen>Page.tsx`
- **Route(n):** `<url>` (`routes/app.$tenant/<file>.tsx`)
- **Daten (VM):** `<VMTypeName>` — `packages/view-models/src/<domain>/<file>.vm.ts`
- **Benötigte UI-Elemente (KEIN Layout):** <~/ui-Komponenten> · Icons: <Icons>
- **Interaktionen (Actions):** <callbackName(args), …>
- **States:** <Empty / Loading / Permission-Denied(404) — was zutrifft>
- **Davids Delta (offen):**
- [ ] Überschriebene/geänderte Spec-Punkte:
- [ ] Neue UI/UX-Entscheidungen:
- [ ] Subframe-Screen-Link(s):
- [ ] Offene Fragen an Dev:
```
Danach im `INDEX.md` desselben Ordners je Screen eine Zeile ergänzen (anlegen, falls INDEX noch fehlt — mit
Intro „Was ist das?" + Domänen-Übersichtstabelle + Screen-Index):
```md
| <ScreenName> | <D-*> | <Ax> | <Route> | offen |
```
Ist die Domäne bei David bereits fertig (`D-*` liegt als `Tickets/Fertige Tickets/D-*.md` vor), Status-Spalte
= `David fertig` und Kopf-Notiz „dient dem Konsistenz-Abgleich, kein neuer Design-Request".
## Schritt 3 — One-Liner Brief-Pointer setzen (in diesem Repo)
Im passenden `.planning/designer-briefs/PXX-*.md` **direkt unter die `**Subframe:**`-Zeile** des Kopfblocks
diese eine Zeile splicen (chirurgisch, keine JSON-/Struktur-Umbauten):
```md
🖥️ **Interim-UI gebaut (AD-28):** lauffähige Screen-Referenz + genutzte Elemente/VM/Actions in `../HiveGrid-Wireframes/Tickets/Interim-Handover/PXX-<Domain>.md`. Layout bleibt frei.
```
## Schritt 4 — Ausliefern
- **Handover-Seite(n) + INDEX** liegen in **Davids Vault** (eigenes Repo). Auf einem **eigenen Branch**
committen (z.B. `interim-ui-handover`), **nicht auf `main`**. Der Push/PR gehört dem User — Push nur mit
expliziter Freigabe; im Zweifel Branch + Commit lokal lassen und dem User den Push-Befehl geben:
`git -C ../HiveGrid-Wireframes push -u origin <branch>`.
- **Brief-Pointer** ist eine Doc-Änderung in **diesem** Repo (HiveGrid-Cloud) — läuft über den normalen
Ticket-/Commit-Flow dieses Repos, **nicht** in den gebundelten `hivegrid-cloud/`-Checkout des Vaults schreiben
(der ist read-only / nur-zum-Pullen).
## Verifikation
- Jede `<Screen>Page.tsx` der Domäne taucht genau einmal in Handover-Seite **und** INDEX auf
(Gegencheck: `ls apps/web/app/components/screens/<domain>/*Page.tsx`).
- Jedes `D-*`-Ziel + Archetyp stammt aus dem Header-Kommentar (nicht geraten).
- Kein Layout in der Handover-Seite (nur Elemente/Daten/Actions/States).
- Brief-Pointer greppbar: `grep -rl "Interim-Handover" .planning/designer-briefs/`.
@@ -49,7 +49,7 @@ Screen-Bau lesen**.
```
apps/web/app/components/screens/<domain>/<Screen>Page.tsx
└─ export function <Screen>Page({ vm, actions }: { vm: <Screen>VM; actions: <Screen>Actions }) { … }
komponiert ~/ui-Components + DefaultPageLayout, rendert vm.data, ruft actions.onX
komponiert ~/ui-Components als app-chrome-freien Content, rendert vm.data, ruft actions.onX
```
Die Route bleibt beim etablierten Muster und rendert nur:
@@ -65,6 +65,55 @@ export default function XRoute() {
Das ist genau das AGENTS.md-Zielmuster `<XPage vm={} actions={} />` — die Interim-UI füllt die heute
fehlende „mittlere Komposition" zwischen VM und `~/ui`-Primitives.
### App-Shell-Grenze: keine rekursive Subframe-Sidebar
Die HiveGrid-App-Routes laufen bereits innerhalb der echten App-Shell mit Sidebar, Tenant-Layout und
Navigation. Deshalb dürfen Screen-Komponenten unter `apps/web/app/components/screens/**` **keine**
generierten Subframe-Page-Layouts rendern, die selbst App-Chrome enthalten, insbesondere nicht
`~/ui/layouts/DefaultPageLayout`. Dieses Layout bringt eine eigene Beispiel-Sidebar inklusive Logo/Nav mit
und erzeugt sonst eine doppelte Sidebar in der App. Erlaubt sind app-chrome-freie Content-Shells aus `div`/
`section` plus `~/ui`-Komponenten. `DialogLayout` und `DrawerLayout` bleiben für echte Modale/Drawer erlaubt,
wenn sie nicht zusätzlich App-Navigation rendern.
### Scroll-Verhalten: Dokumentfluss statt Subframe-Inner-Scroll
Subframe-Page-Exporte kommen mit einem eigenen Scroll-Gerüst: Screen-Root
`h-full min-h-[0px] … overflow-hidden` plus Inhaltsbereich `grow shrink-0 basis-0 … overflow-y-auto`.
Das funktioniert nur, wenn der Screen eine definite Höhe vom Parent erbt. Die `SubframeAppShell` rendert
Screens aber in ein block-level `<main class="flex-1 overflow-auto">` — dort kollabiert der
`basis-0`-Bereich auf **0px** und der komplette Inhalt ist unsichtbar (im DOM vorhanden, Höhe 0; so
geschehen bei WF-P16 S00/S02 und den Automations-Übersichten, 2026-07-10). Beim Integrieren deshalb
**beide Klassen-Sets entfernen** und den Screen im normalen Dokumentfluss rendern — das Scrollen
übernimmt die `<main>` der Shell (wie bei allen anderen App-Screens). Der Guard-Test
`apps/web/app/components/screens/subframe-layout-boundary.test.ts` schlägt bei dem Muster statisch fehl.
### Lokales UI-Kit ≠ Cloud-Export: bekannte Prop-Abweichungen
Der Subframe-Cloud-Export nutzt teils andere Prop-APIs als das lokale Kit unter `apps/web/app/ui`.
Bei Unsicherheit die Komponente lesen. Real getroffen (Stand 2026-07-13):
- `SearchInput`: flache Props (`value`/`onChange`/`placeholder` direkt), KEIN `<SearchInput.Input>`-Child.
- `Table.Cell`: kennt nur `align-left`/`align-center`; rechtsbündig = Default + `justify-end`-Div.
- `BadgeFeedback`: Farb-Prop heißt `farbe`.
- `BadgeShortcut`: Props heißen `icon`/`iconRight` (Default-Icon ⌘), NICHT `iconLeft1`/`iconLeft2` aus dem Export; ⇧-Kombos als Text-Children (z. B. `⇧Z`).
- `HelpCircle`: hat KEIN `tooltipText` — Tooltip via `SubframeCore.Tooltip.Root/Trigger/Portal/Content asChild` + `~/ui`-`Tooltip` als Content (Muster: `select-tenant.component.tsx`).
- Radix `SubframeCore.ContextMenu.Content`: akzeptiert KEIN `side`/`align` (Kontextmenüs positionieren am Pointer) — die Props aus dem Export entfernen, nur `asChild` behalten.
### Component-Sync: nie blind `sync --all` übernehmen (real getroffen 2026-07-18)
`pnpm subframe:sync` (`@subframe/cli sync --all`) schreibt den **kompletten** Cloud-Stand nach
`apps/web/app/ui` — inklusive **Löschungen**: lokale Komponenten ohne Cloud-Pendant
(`ConfirmDialog`, `ResultDialog`, `layers.ts`, …) und sogar colocated **Testdateien**
(`Dialog.layering.test.tsx`) flogen raus; parallel kamen umbenannte Duplikate (`DialogFullscreen`
neben `FullscreenDialog`) rein. Vorgehen:
1. Sync laufen lassen, dann `git status` sichten und **nur die für das Ticket nötigen Komponenten
behalten** (Rest per `git stash`/`checkout` zurück — der volle Stand bleibt im Stash als Referenz).
2. Synchronisierte Komponenten auf **Breaking-API** prüfen (2026-07-18: `KanbanCard` wechselte von
`name`/`price`/`topRow` auf Slot-Props `tagsSlot`/`titleSlot`/`valueSlot`/`footer*Slot`) und ALLE
Konsumenten im selben PR migrieren — auch fremde Module (LeadBoard), Abhängige müssen grün bleiben.
3. Wrapper wie `SortableKanbanBoard` forwarden neue Props **nicht** automatisch — Interface + Forwarding
nachziehen, sonst greifen neue Defaults still (2026-07-18: `showSum=false` zeigte überall
„Summe gesperrt" statt der Spaltensumme).
### Layer-Regeln bleiben unangetastet
Die drei Anti-Patterns (AGENTS.md) gelten weiter:
- kein `@prisma/client`/`~/db` in `packages/ui-app/**`;
@@ -137,6 +186,8 @@ Done setzen weiterhin nur **mit expliziter Freigabe** und nach dem Abschluss-Aud
- [ ] Interim-`<XPage>` in `apps/web/app/components/screens/<domain>/` aus `~/ui` + Layout, VM als Prop.
- [ ] Route rendert `<XPage vm={} actions={} />`; kein handgeschriebenes Tailwind.
- [ ] Keine rekursive App-Shell: Screen-Komponenten importieren nicht `~/ui/layouts/DefaultPageLayout` und rendern keine zusätzliche Sidebar/Header-Navigation.
- [ ] Kein Subframe-Inner-Scroll: `h-full`/`overflow-hidden`-Root und `basis-0`/`overflow-y-auto`-Inhaltsbereich aus dem Page-Export entfernt — Screen läuft im Dokumentfluss, die Shell-`<main>` scrollt (siehe §„Scroll-Verhalten").
- [ ] **Davids Design-Standards befolgt** (`.planning/INTERIM-UI-DESIGN-STANDARDS.md`): Spacing/Padding/
Dialog-Struktur/Control-Höhen/States aus `~/ui`-Defaults; Screen-IDs/Naming an Davids Tracker angelehnt.
- [ ] Reachability B 6–10 verdrahtet (Sidebar/Permission/Route/Breadcrumb/i18n).
@@ -164,3 +215,102 @@ Refactor-Nachzug offen: finale Subframe-Optik aus `D-<XXX>` (Plane-Label `design
umgekehrt. Divergiert Plane vom Doc, gewinnt das Doc.
- Es gibt **kein** Skript, das Plane-Kommentare postet. Kommentar/Status weiter manuell via API
(`POST /issues/{iid}/comments/`, Identität vorab `GET users/me`); Done nur mit Freigabe.
## Footgun: FK-Constraints auf Tabellen unter `FORCE ROW LEVEL SECURITY`
**Symptom.** Eine Migration, die eine Foreign Key Constraint anlegt, bricht ab mit
`ERROR: query would be affected by row-level security policy for table "<X>"` —
obwohl der Migrator der Tabellen-Owner ist.
**Ursache.** Seit dem App-weiten RLS-Cutover tragen die Tabellen `FORCE ROW LEVEL
SECURITY`, und `FORCE` gilt **auch für den Owner**. Postgres validiert eine neue
FK-Constraint mit einem internen `SELECT` über die betroffenen Tabellen, und
genau dieses `SELECT` wird von der Policy abgelehnt. Es trifft **beide** Seiten:
die Tabelle, die die Constraint bekommt, **und** die referenzierte Tabelle.
**Fix.** `FORCE` für die Dauer der Constraint-Erzeugung abschalten und sofort
wieder setzen. Die Policy selbst bleibt die ganze Zeit **aktiviert**, und im
Fenster steht kein DML — es ist also kein Sicherheitsloch:
```sql
ALTER TABLE "Pipeline" NO FORCE ROW LEVEL SECURITY;
ALTER TABLE "Pipeline" ADD CONSTRAINT "…_fkey" FOREIGN KEY (…) REFERENCES "Pipeline"("id") …;
ALTER TABLE "PipelineFieldGroup" ADD CONSTRAINT "…_fkey" FOREIGN KEY (…) REFERENCES "Pipeline"("id") …;
ALTER TABLE "Pipeline" FORCE ROW LEVEL SECURITY;
```
**Merke.** Mehrere FKs auf dieselbe Zieltabelle in **ein** Fenster packen, statt
`FORCE` mehrfach zu togglen. Neu angelegte Tabellen sind nicht betroffen,
solange ihre Policies erst am Ende der Migration gesetzt werden — das ist ein
weiterer Grund, den RLS-Block ans Ende des Migrationsfiles zu stellen.
**Gefunden:** 2026-07-28, WF-P8-Baseline (`20260728120000_wf_p8_subframe_baseline`).
Der Fehler erscheint erst bei `verify:migrations-parity` bzw. beim Replay gegen
eine leere DB, **nicht** beim lokalen `prisma db push` — der Feature-Branch-Pfad
verschleiert ihn also.
## Footgun: eine neue Relation kann die Policy-Form einer bestehenden Tabelle kippen
**Symptom.** `verify:rls-live` meldet gegen die frische Migrationskette
`rls_expected_policy_mismatch` **und** `rls_unexpected_policy`, obwohl
`verify:tenant-policy-contract --check` grün ist und die Migration für jede neue
Tabelle brav eine Policy anlegt.
**Ursache.** Der Generator entscheidet die **Form** der Policies aus dem Modell:
eine Tabelle mit direktem `tenantId` bekommt **eine** `FOR ALL`-Policy
(`hg_<T>_all`), eine Tabelle mit abgeleiteter Ownership bekommt **vier**
Per-Command-Policies (`_select`/`_insert`/`_update`/`_delete`). Fügt man einer
**bestehenden** Tabelle eine Relation hinzu, kann sie dadurch zum
Derived-Ownership-Modell werden und ihre Policy-Form wechseln. Bei WF-P8 hat
genau das die Selbstrelation `Pipeline.nachfolgePipelineId` ausgelöst:
`hg_Pipeline_all` → vier Policies.
**Fix.** Die Policy-DDL **nie von Hand schreiben**, sondern wörtlich aus
`prisma/rls/tenant-policy-contract-isolation.sql` in die Migration kopieren —
inklusive der Tabellen, die man gar nicht angefasst zu haben glaubt. Die alte
Policy muss dabei explizit gedroppt werden:
```sql
DROP POLICY IF EXISTS "hg_Pipeline_all" ON "Pipeline";
-- danach die vier generierten Per-Command-Policies
```
**Merke.** Postgres verknüpft permissive Policies mit **ODER**. Eine
stehengebliebene alte Policy hebt die neue also nicht auf, sondern hält den
schwächeren Ausdruck daneben am Leben — ein stiller Sicherheitsverlust, den
kein Test bemerkt, der nur „Zeile sichtbar?" prüft. Ein `git diff` gegen
`packages/db/src/rls-runtime-contract.generated.ts` zeigt nach jeder
Schema-Änderung sofort, welche Tabellen ihre Policy-Form gewechselt haben.
**Gefunden:** 2026-07-28, WF-P8-Baseline. Sichtbar nur in `verify:rls-live`,
`Database Checks` und `Docker Smoke` — lokal auf `RLS_RUNTIME_MODE=off` nicht.
## Footgun: `~/ui`-Felder in einer umbrechenden Flex-Zeile
**Symptom.** Mehrere Eingabefelder nebeneinander rendern kaputt: jedes Feld
steht auf einer eigenen, sehr hohen Zeile, das Label klebt weit über dem Input
und kollidiert mit dem nächsten Feld. Im DOM ist die Reihenfolge korrekt — es
ist rein Layout.
**Ursache.** Die Roots von `~/ui`-`TextInput`/`Select` tragen selbst
`h-full w-full … justify-center`. Als Flex-Kind beansprucht ein solches Feld
damit die **ganze** Zeile (eine `flex-wrap`-Zeile bricht also nach jedem Feld
um) und dehnt sich zusätzlich auf die Zeilenhöhe, wobei `justify-center` den
Input in der Mitte dieser Höhe parkt.
**Fix.** Die Zeile als **Grid** auslegen, dann füllt jedes Feld seine Spur:
```tsx
<div className="grid w-full items-end gap-3 sm:grid-cols-2">
<TextInput className="w-full" … />
<TextInput className="w-full" … />
</div>
```
**Merke.** `className="grow"` hilft **nicht** — es überschreibt das `w-full` des
Feldes nicht. Eine nicht umbrechende `flex`-Zeile ist dagegen unkritisch, weil
die Felder dort schlicht schrumpfen. Guard:
`apps/web/app/components/screens/subframe-layout-boundary.test.ts`.
**Gefunden:** 2026-07-29, WF-P8 „Termin erstellen" (S02-T) und S05
„Neue Feldgruppe". Nur im Browser sichtbar, nicht im Unit-Test.
@@ -0,0 +1,187 @@
# KWP-API-Vertrag (Stand 2026-07-12 · Read-only-Entscheidung 2026-07-22)
> **Auslöser:** KWP bekommt eine offizielle **API-Anbindung**. Die historische Planung
> (M089–M095) war für **KWP OHNE API** gebaut: lokaler Windows-Client `kwpsync.exe` (NSSM-Dienst)
> + MSSQL-Direktzugriff + lokale SQLite-Queue + MSSQL-Schema-Drift-Sentinel.
> **Aktuelle Grundlage:** verifizierte Tenant-OpenAPI-/Staging-Proofs, AD-32, CR-003/CR-005 und die
> Ticket-Docs `VR-P32*`/`VEXT-6`.
> 🟢 **Initialer Produkt-Scope nach CR-003/AD-32 (2026-07-22):** HiveGrid nutzt KWP bis auf Weiteres
> ausschließlich read-only. Der ausgelieferte Scope umfasst OAuth2/PKCE, die bestätigte 1:1-Mandantenbindung,
> Connection-Health und spätere KWP→HiveGrid-Pulls. Keine KWP-Mutation wird registriert oder ausgeliefert.
> M091, `kwp.push_auftrag`, M094-Outbound und M074-Outbound sind geparkt. `VEXT-6` hält den fehlenden
> Write-/Project-Create-Vertrag nach; es blockiert den read-only Ausbau nicht. Read-only ist eine
> HiveGrid-Produktgrenze und keine Behauptung über technisch mögliche BNWIN-Rechte.
## Maßgeblicher Vertrag für Geerkens
KWP-Hosts sind **dynamisch**: Der Connector ermittelt den Relay-Host über
`https://loadbalancer.kwp-online.de/Relay/GetAppUrl?linkId=<KUNDENKUERZEL>` und hängt
`/relay/<KUNDENKUERZEL>/pwa` an. Ein Host wie `app04` darf deshalb nicht dauerhaft in Code oder Tenant-Config
festgeschrieben werden. Für `geerkens2` lieferte der Loadbalancer am 2026-07-12:
| Vertragsmerkmal | Verifizierter Stand |
|---|---|
| Relay-Host | `https://geerkens2.app04.kwp-online.de` |
| Tenant-OpenAPI | `/relay/geerkens2/pwa/swagger/v1/swagger.json` |
| Vertrag | OAS 3.0.1 · 301 Pfade · 303 Operationen · 396 Schemas |
| Snapshot-Proof | SHA-256 `5c504ffa955bc492fcc16ae01a92ad0491db29a904ad59058123fc3b24f26762` |
| API-Metadaten | Title `KWP Api` · Version `v1` · Server `/relay/geerkens2/pwa` |
Ergänzende Primärquelle ist die
[offizielle KWP-API-Dokumentation](https://www.kwpsoftware.de/kwp-api-dokumentation/): Die API handelt im Namen
eines bnWin-Benutzers; seine Rechte bestimmen Lese- und Schreibzugriff. Nutzt der Endkunde bnWin-Mandanten,
muss jeder Request den Queryparameter `mandant=<Mandantenkürzel>` erhalten.
**Mandanten-Verbindungsflow, freigegeben 2026-07-21:** Die Tenant-OpenAPI enthält
`GET /api/Mandant/Load`; der Endpoint beschreibt die für den angemeldeten Benutzer zulässigen Mandanten als
`DtoMandant{id, kuerzel, bezeichnung}`. HiveGrid versucht diese Discovery direkt nach dem OAuth-Login. Ein
Treffer wird vorausgewählt, muss aber vom Benutzer bestätigt werden; bei mehreren Treffern wird genau einer
gewählt und bestätigt. Die OpenAPI-Security
des Endpoints nennt allerdings andere KWP-interne Produkt-Scopes als die fünf für HiveGrid gelieferten
`*-extern`-Scopes. Falls der externe Client die Liste nicht lesen darf, muss der Benutzer deshalb fail-closed
entweder „kein bnWin-Mandant eingerichtet“ ausdrücklich bestätigen oder das exakte Kürzel manuell eingeben.
Ein Fehler oder eine leere Liste ist keine implizite `none`-Bestätigung.
Die Produktgrenze bleibt **1:1**: Ein HiveGrid-Tenant bindet genau ein KWP-Kundenkürzel plus genau eine
bestätigte bnWin-Auswahl (`selected`) oder die bestätigte Abwesenheit eines bnWin-Mandanten (`none`). Ein
fehlender Altwert ist `unconfirmed` und blockiert fachliche Calls. Der vorprovisionierte Geerkens-Pilot bleibt
processweit auf `KWP_HIVEGRID_TENANT_ID` begrenzt. Die sichere Provisionierung mehrerer HiveGrid-Tenants oder
weiterer KWP-Kundenclients ist Folge-Scope und wird nicht durch Entfernen dieses Gates vorgezogen.
**OAuth-Runtime live geklärt (2026-07-22):** Die Freischaltungs-Mail nennt Keycloak unter
`id.kwp-online.de/realms/kwp-federated`, die Tenant-OpenAPI dagegen Relay-lokale Endpunkte
`/relay/geerkens2/pwa/connect/authorize` und `/connect/token`. Ein Authorization-Probe mit dem gelieferten
externen Client, PKCE/S256 und allen fünf externen Scopes erreichte am Keycloak-Pfad für Produktions- und
Staging-Redirect jeweils die Login-Seite (HTTP 200; weder `invalid_client` noch `invalid_redirect`). Damit sind
Client und beide Redirects am Authorization-Endpunkt plausibilisiert. `client_credentials` ist wegen
deaktiviertem Service-Account nicht erlaubt; der Device Authorization Grant ist ebenfalls für den Client
deaktiviert. Gültig ist `openid` + fünf `*-extern`-Scopes + `offline_access`; `email` erzeugt für diesen Client
`invalid_scope`. Somit bleibt ausschließlich Authorization Code + PKCE mit einem echten bnWin-Benutzer.
Token-Austausch, geschützter read-only Resource-Call, bestätigte Mandantenbindung und neun automatische
Refresh-Rotationen sind auf Staging belegt. `VN-1` bleibt nur für kontrollierte fachliche Testdaten offen.
## Architektur: von 3 auf 2 Komponenten
**Vorher:** `HiveGrid Cloud ↔ kwpsync.exe (Windows, beim Kunden) ↔ KWP-MSSQL`
**Nachher:** `HiveGrid Cloud ↔ HTTPS ↔ dynamisch aufgelöster KWP-Relay`
Der „Kunde-vor-Ort"-Mittelteil entfällt. KWP wird damit ein **regulärer `oauth2`-Adapter**
(statt `windows_client`-Sonderweg) und passt direkt ins generische Apps-Engine-Muster
(`prisma/schema/appsEngine.prisma`: `App` / `DataConnection` / `AppSyncRun` / `AppSyncItem`).
Egress (Cloud ruft KWP aktiv auf) statt Ingress (Client pollt Cloud).
## Überführung der historischen Milestones M089–M095
| Milestone | Vorher | Nachher (Re-Cut) | Verdict |
|---|---|---|---|
| **M089** Sync-Programm | externes `kwpsync.exe` (.NET/Go, NSSM, MSSQL, DPAPI, Auto-Update) | **KWP-API-Connector** (Host-Resolver + OAuth + userbezogener Kontext + bestätigte 1:1-`mandant`-Bindung über M33a) | **REPURPOSED** (Windows-Client entfällt) |
| **M090** Heartbeat+Recovery | Client-Heartbeat 5min + 15-min-Watchdog + Auto-Restart | **KWP-API Connection-Health** (generischer M33a-Health-Probe) | **STARK VEREINFACHT** |
| **M091** Warteschlange+Replay | zwei Queues (Cloud + lokale SQLite) | Zukünftige Cloud-Outbox nach belastbarem Write-Vertrag | **PARKED** hinter `VEXT-6` |
| **M092** Schema-Drift-Sentinel | täglicher MSSQL-Schema-Snapshot+Hash-Diff | **API-Contract-Sentinel** (zod-Response-Validierung + OpenAPI-Fingerprint + `x-kwp-client-version`) | **VEREINFACHT** (ggf. in M089 integrierbar) |
| **M093** Konflikt „KWP gewinnt" | Domain-Regel | Domain-Regel + HiveGrid-Snapshot/Audit; KWP-Änderungsfelder nur partiell | **UNVERÄNDERT**, technische Erkennung angepasst |
| **M094** Plantafel-Sync | bidirektional via Client | initial nur KWP→HiveGrid per Cron-Pull; Outbound geparkt | **READ-ONLY RECUT** |
| **M095** Dokumenten-Archiv-Sync | Client-Dateizugriff | Archiv-Metadaten via API, Dateiinhalt via Azure-Blob-Austausch → `@hivegrid/storage` | **VEREINFACHT** |
**Netto:** M089 ändert sich grundlegend (Client → Connector), M090/M092/M094/M095 werden teils erheblich
leichter, M093 bleibt als Schutz für eingehende KWP-Daten. M091 ist kein Vorläufer des read-only Ausbaus mehr.
## Datenmodell
- **Aus Apps-Engine (`appsEngine.prisma`) nutzen:** `App{key:"kwp", connectionType:"oauth2"}`,
`DataConnection{credentialsCiphertext:<verschlüsselt>}`, `AppSyncRun`, `AppSyncRunLog`, `AppSyncItem`
(inkl. `rolledBackData` für M093-Restore). Plus `IdempotencyKey`/`FileObject` 1:1. Kundenkürzel und
OAuth-Material liegen verschlüsselt in `DataConnection.credentialsCiphertext`; der dynamische Relay-Host wird nur gecacht. Die
`mandantBinding` liegt ebenfalls ausschließlich im verschlüsselten Credential-Bundle und ist explizit
`unconfirmed`, `none` oder `selected(<Kürzel>)`. Ein fehlendes Feld aus Alt-Credentials bedeutet
`unconfirmed`, nicht `none`; dafür ist kein Prisma-Schema-Delta nötig.
- **Neu im aktuellen Read-only-Scope in `prisma/schema/kwp.prisma`:** `KwpApiContractSnapshot` (API-Version + Schema-Fingerprint, ersetzt `KwpSchemaSnapshot`) und `KwpErrorReport`.
- **PARKED, nicht im aktuellen Datenmodell:** `KwpProjectNumberSequence` und `KwpProjectNumberReservation` gehören ausschließlich zum Project-/Auftrag-Create. Sie dürfen erst nach belastbarem Providervertrag aus `VEXT-6` **und** erneuter ausdrücklicher Produktfreigabe angelegt werden.
- **Credentials:** verschlüsselt in `DataConnection.credentialsCiphertext` via **Per-Tenant-DEK** (AD-8). Achtung: Spec 19.1.2 („KWP-Zugangsdaten verlassen das Kunden-Netz nie") gilt bei API-Anbindung nicht mehr 1:1 — API-Creds liegen jetzt (verschlüsselt) in der Cloud. DSGVO-konform, aber bewusst neu bewertet → in AVV/Subprozessoren (M166) vermerken.
- **Pilot-Provisionierung:** Der bestehende Geerkens-OAuth-Client bleibt fail-closed an
`KWP_HIVEGRID_TENANT_ID` gebunden. `KWP_MANDANT` wird für neue Connections nicht als processweite
Mapping-Quelle verwendet. Ein späterer Mehr-Tenant-/Mehr-Kunden-Betrieb braucht einen eigenen sicheren
Provisionierungsvertrag statt einer ersatzlosen Gate-Entfernung.
## Harte Vorbedingung
**M008–M010 (M33a Apps-Engine-Adapter-Interface)** — das echte `connect/disconnect/validateConnection/syncPull/syncPush/handleWebhook`-Interface. `defineAdapter()` aus der Boilerplate ist nur eine 18-Zeilen-Status-Registry, **nicht** das Connector-Framework. KWP-API ist dann der **erste konkrete Adapter** dahinter.
## Vertragsstand der sieben Re-Cut-Fragen
1. **Auth:** OAuth2/Authorization Code + PKCE und Refresh/`offline_access` sind gesetzt;
`App.connectionType='oauth2'`. Service-Account- und Device-Flow sind deaktiviert; der Request darf
`openid` + fünf `*-extern`-Scopes + `offline_access`, aber nicht `email` enthalten. Userrechte sind bindend.
Keycloak- versus Relay-`/connect/*`-Endpoint wird mit Token-Austausch und Resource-Call final entschieden.
2. **Endpoints/Capabilities:** Die externen Scopes erscheinen in der Tenant-Spec an folgenden Operationen:
| Scope | Operationen | Fachliche Tags |
|---|---:|---|
| `adresse-extern` | 23 | `Adresse` |
| `archiv-extern` | 15 | `ArchivExternal`, `VorgangInfo` |
| `termin-extern` | 14 | `Termin`, `Monteursteuerung` |
| `vorgang-extern` | 31 | `Projekt`, `Projektampel`, `VorgangAnzeige` |
| `aktivitaet-extern` | 31 | `Aktivitaet`, `Aktivitaetenverwaltung`, Termin-Verknüpfungen |
Die `*-extern`-Scopes fehlen allerdings in der Scope-Liste des OAuth-Flows und stehen in den
Operation-Security-Arrays zusammen mit internen Scopes. Nach strikter OpenAPI-Semantik wäre das eine
UND-Anforderung; praktisch sieht es nach alternativen KWP-Berechtigungen aus. Lese- und Schreibrechte sind
deshalb pro Scope im Runtime-Probe zu beweisen. Der aktuelle HiveGrid-Scope führt unabhängig davon keine
Schreiboperation aus. **Fachliche Lücke für einen späteren Writeback:** Es gibt keinen dokumentierten Endpoint
zum Anlegen eines kaufmännischen Auftrags/Projekts. `/api/Projekt/Save` speichert laut Vertrag nur eine neue
Bezeichnung für ein bereits bestehendes Projekt. Der Won→Auftrag-Use-Case benötigt eine KWP-Erweiterung oder
ein bestätigtes Alternativ-Mapping.
**Reale Vollinventur 2026-07-24 (CR-005):** Die 2.062.387-Byte-Tenant-OpenAPI enthält 554 Operationen.
Wegen überlappender Security-Arrays ergeben die Scope-Zahlen zusammen nicht die eindeutige Anzahl:
113 Operationen liegen in mindestens einem der fünf HiveGrid-Scopes. Davon sind 77 semantisch lesend und
36 mutierend. Alle 113 erhalten einen expliziten Contract; nur die 77 Reads sind runtime-ausführbar. Die
übrigen 441 Operationen gehören nicht zum lizenzierten HiveGrid-Umfang und werden nicht allowlisted.
3. **Webhooks:** In der vollständigen Tenant-OpenAPI gibt es weder Top-Level-`webhooks` noch
Operation-`callbacks`. Das ist **Abwesenheit im Vertrag**, keine Bestätigung, dass KWP außerhalb davon keine
Webhooks anbietet. M094 plant bis zur Herstellerantwort Cron-Pull.
4. **Rate-Limits:** KWP bestätigt ein Hard-Cap von 60 Requests/Minute pro Client. Read-only-Pulls müssen dieses
Limit aggregiert einhalten. M091 bleibt bis zum Write-Vertrag geparkt und muss bei einer späteren Freigabe
zusätzlich Backoff, Jitter und `429` konservativ behandeln.
5. **Versionierung:** OpenAPI/Info-Version `v1`; alle 303 Operationen führen optional
`x-kwp-client-version`. Changelog- und Breaking-Change-Policy bleiben offen. M092 speichert deshalb
OpenAPI-Hash plus beobachtete Serverversion und pausiert bei nicht validierbarer Drift.
6. **Dokumenten-API:** Listing, Suche, Details, Revisionen, Export und Import sind unter
`/api/archiv-extern/*` vorhanden. Der Dateitransfer läuft gemäß offizieller KWP-Doku separat über Azure Blob:
- `GetSetup.azureConnectionUri` höchstens **6 Stunden cachen**.
- Upload in den Blob, danach `ImportDatei(containerId, dateiname)`.
- Dateien im Austausch-Storage werden nach **24 Stunden automatisch gelöscht**.
- Download: `ExportDatei(revisionId, guid)` → `exchangeFileUri` → JSON-Datei → eigentlicher Downloadlink.
7. **Konflikt-Felder:** Aktivitäten liefern `datumAenderung`/`userAenderung`; Archiv-Daten liefern
`letzteAenderungAm`/`letzteAenderungVon` sowie `revisionId`/`revision`. Adresse, Termin und
Projekt/Vorgang haben keine einheitlichen Versions-/Änderungsfelder. Es sind keine `ETag`-/`Last-Modified`-
Response-Header oder `If-Match`-Preconditions dokumentiert. M093 verwendet daher KWP-Felder nur, wo
vorhanden, und sonst HiveGrid-Snapshot + „KWP gewinnt" + Audit-Restore.
## Mandantenbindung als M089-Connector-Vertrag
- OAuth-`tenant=<Kundenkürzel>` wählt die KWP-Installation; der Resource-Query
`mandant=<Mandantenkürzel>` wählt optional die Firma innerhalb dieser Installation. Die Werte dürfen nicht
gleichgesetzt werden.
- Nach dem Token-Austausch bleiben die Credentials bis zur ausdrücklichen Auswahl per-Tenant-DEK
verschlüsselt in der reservierten `pending`-Connection. Erst eine bestätigte Bindung und ein geschützter
Health-Probe dürfen die Connection aktivieren.
- `selected` setzt den Queryparameter an jedem KWP-Resource-Request, `none` lässt ihn bewusst weg und
`unconfirmed` blockiert fachliche Calls fail-closed.
- Discovery über `Mandant/Load` ist bevorzugt, aber wegen des abweichenden Scope-Vertrags nicht garantiert;
der manuelle Fallback ist deshalb Bestandteil des Connectors, kein Sync-Feature.
- Der Slice enthält weiterhin keinen Pull, Push, manuellen Sync und keine automatische Anlage weiterer
HiveGrid-Tenants.
## Noch extern zu bestätigen
- für `VEXT-6`: belastbare Write-/Project-Create-Operationen, Scopes/BNWIN-Rechte, Payloads,
Idempotenz-/Fehlervertrag und ein kontrollierbarer Testpfad;
- kontrollierte fachliche Testdaten beziehungsweise ein sicherer Testpfad, obwohl KWP keine Sandbox und keinen
Testkunden anbietet;
- konkrete Pull-Intervalle innerhalb des bestätigten Hard-Caps von 60 Requests/Minute pro Client.
## Phase 2 (unverändert)
Andere ERPs (Taifun/TopKontor/Streit) über dasselbe Adapter-Pattern. Streit hat ohnehin eine Cloud-API (analog zur KWP-API-Variante).
@@ -1,283 +0,0 @@
# Phase → Source-Dokumente (HiveGrid 2.0)
Mapping der 21 ROADMAP-Phasen auf ihre Quell-Dokumente für **Stufe-3-Enrichment** (`/gsd-plan-phase N`).
- **Modul-Specs** (`_bmad-output/specs/`) — das WHAT je Modul (requirements-pur, `detail-spec-draft`)
- **Milestone-PLANs** (`docs/milestones/`) — die detaillierte Ausführungsebene (176 Milestones mit Ziel, Abhängigkeiten, Definition-of-Done)
**Generiert:** 2026-06-07. Alle **176 Milestone-PLANs + 36 Modul-Specs + 2 Fundament-Docs** sind genau einer Phase zugeordnet (verifizierte Summe: 176 Milestones).
Beim Planen einer Phase liest der Planner/Researcher diese Specs + Milestone-PLANs als Enrich-Input.
> 🔴 **MODELL-PIVOT 2026-06-13 (AD-20):** Die Milestone-Maps von **Phase 6–9** (M01-CRM, M02-Lead, M03-Sales, M04-Auftrag) werden durch das Projekt-zentrische Modell neu geschnitten: Sales- und Auftrags-Milestones konsolidieren zu „Projekt & Pipelines" (Projekt-Kern + Pipeline-Engine + Feld-Config + konfigurierbarer Kanban); Lead→Projekt statt Promotion; Rechnung-Sub-Entity (NEU v1); Abnahme als Checklisten-Sub-Area. Der Re-Map erfolgt **mit dem gemeinsamen ER-Modell**. Single Source: `.planning/ENTITY-MODEL.md`.
---
## Phase 1: Fundament & Walking-Skeleton
**Specs:** `docs/ARCHITECTURE-DECISIONS.md`, `docs/INTEGRATION-CONTRACTS.md`; Service-Kern-Teile aus `_bmad-output/specs/M21-audit-log.md`, `M22-notifications.md`, `M30-i18n.md`, `M32-feature-flags.md`
**Milestone-PLANs (15):** M001-audit-log-default, M002-klartext-diagnostik, M003-i18n-pflicht-wiring, M004-tenant-scope-owner-check, M005-url-tampering-mass-action-schutz, M006-feature-flag-engine, M007-idempotenz-wrapper, M011-notification-service-layer, M012-workspace-topologie, M013-view-model-konvention, M014-action-callback-contract, M015-subframe-adapter-layer, M016-visual-regression-gate, M017-hot-swap-drill, M176-anti-liste-change-request-doku
> ⚠ **Restrukturiert 2026-06-10 (Dependency-Audit):** M001/M003/M006/M011 (Service-Kerne Audit, i18n, Feature-Flags, Notifications) von Phase 3 hierher verschoben — Phase 1 enthält die Wiring-Pflichten (REQ-integration-audit/notification-wiring), und der gesamte Auth-Block (P2, M018–M027) setzt diese Services voraus. Entspricht der ursprünglichen BMAD-Block-1-Ordnung.
> 🔌 **Neuer Integration-Contract „Entitlement-Gate-Pflicht" (2026-06-11):** Jedes Modul registriert einen **Feature-Konnektor** — `tenantHasModule('<modul>')` gated Sidebar-Eintrag, Routes und Actions. Pflicht-Checkpunkt JEDER Modul-Phase (wie Sidebar-/Audit-Wiring). Mechanik: Flag-Engine (M006, hat `plan-tier`-Targeting) × `packages/entitlements`. Modul-Liste als Vorlage: `archive/hivegrid-cloud/app/config/pricing-plans.ts` (14 Gates). Grundlage des Abo-Baukastens (P20-Recut).
## Phase 2: Identität & Mandantentrennung
**Specs:** `_bmad-output/specs/M27-auth-multi-tenancy.md`
**Milestone-PLANs (9):** M018-mandanten-anlage, M019-mandanten-trennung-hardening, M020-email-passwort-auth, M021-magic-link-sessions, M022-totp-2fa, M023-rollen-engine-shk-rollen-gruppen, M024-mitarbeiter-einladung-deaktivierung, M025-konto-loeschung, M026-mandanten-lebenszyklus
> Scope-Schnitt 2026-06-12 (Boilerplate-Recheck): M027 (API-Keys & Tarif-Gates) → v2 — wandert als Paket mit der Public-API (M161–163). Boilerplate-`ApiKey`-Modell + Settings-Routen bleiben ungenutzt im Code (Vorbereitung gratis, nicht in Sidebar verlinken). Auth-Block hat HIGH-Boilerplate-Coverage (`apps/web/app/services/auth/`) — RLS bleibt der Eigenbau-Kern (Boilerplate hat nur App-Level-Scoping).
## Phase 3: Querschnitts-Oberflächen
**Specs:** `_bmad-output/specs/M21-audit-log.md`, `M22-notifications.md`, `M30-i18n.md` (Oberflächen-Teile; Service-Kerne → Phase 1)
**Milestone-PLANs (5):** M028-sprach-settings-aufloesung, M115-notifications-center, M116-notifications-user-settings, M151-audit-log-anzeige, M152-audit-log-export-aufbewahrung
> ⚠ **Restrukturiert 2026-06-10:** Service-Kerne (M001/M003/M006/M011) → Phase 1; Flag-Admin-UI (M031–M033) → Phase 19 (braucht laut eigener Vorbedingung die Admin-Welt M034). Phase 3 = die Bedien-Oberflächen: Audit-Viewer/Export, Notification-Center/Settings, Sprach-UX.
> Scope-Schnitt 2026-06-12 (Boilerplate-Recheck): **M029 (Sprach-Wechsler/Fallback) → v2** — v1 ist **DE-only**; M028 gedünnt auf DE-Defaults (Auflösungskette/Timezone → v2). HART: i18n-Pflicht-Wiring (M003, P1) + `verify:i18n`-CI-Gate bleiben unantastbar — alles i18n-ready. **M117 (Bündelung/Quiet-Hours/Push-Limits) → v2** — v1: Sofort-Zustellung, Center (M115), Kategorie-An/Aus (M116). **M152 gedünnt:** fixe Default-Retention + direkter CSV/PDF-Export (Boilerplate: Retention-Cron + PDF vorhanden); konfigurierbare Policy/Legal-Hold/Saved-Views → v2.
## Phase 4: Files & Tasks
**Specs:** `_bmad-output/specs/M23-files.md`, `M26-tasks.md`
**Milestone-PLANs (7):** M052-datei-upload, M053-speicher-backend-hetzner, M054-datei-permissions-sharing-versionierung, M055-datei-suche-tagging-archivierung, M071-aufgaben-crud-zuweisung, M072-aufgaben-listen-pro-modul, M073-aufgaben-erinnerungen-push-email
> M074-aufgaben-sync-erp → Phase 10 verschoben (2026-06-10): braucht Apps-Engine (P5) UND KWP-Sync-Foundation (P10) — ist inhaltlich eine KWP-Integration. Task-Entity-Verknüpfung zu CRM-Entitäten (M071 ↔ M042): Task-Kern hier, Entity-Links werden in Phase 6 nachverdrahtet.
> Scope-Schnitt 2026-06-12 (Boilerplate-Recheck): **M054 gedünnt** — Versionierung, Office-/Video-Previews, Resume-Upload → v2; v1 = Ersetzen + Bild-/PDF-Preview + **HEIC→JPG-Konvertierung (Pflicht — iPhone-Fotos der Monteure!)**; Permissions/Sharing bleiben. **M055 gedünnt** — OCR/Inhalts-Volltext → v2; Dateiname+Tags via Meilisearch + Archiv-Flag bleiben. Boilerplate liefert S3-Adapter/Signed-URLs/ClamAV (`packages/storage/`; ClamAV läuft zentral, Infra-ADR-014).
> ⚠ **Infra-Wechsel 12.06. (M053):** Speicher-Backend ist **Hetzner S3-kompatibles Object Storage** (per-Product-Bucket im Hetzner-Projekt `HiveGrid`, Infra-ADR-009) — NICHT mehr Scaleway (M053-PLAN-Name ist historisch). S3-API identisch, nur Endpoint/Credentials.
## Phase 5: Apps-Engine & Integrations-Framework
**Specs:** `_bmad-output/specs/M33a-apps-engine.md`
**Milestone-PLANs (3):** M008-apps-engine-adapter-state-machine, M009-apps-engine-setup-wizard-sync-log, M010-apps-engine-probe-scheduler-webhook-schutz
## Phase 6: CRM-Kern
**Specs:** `_bmad-output/specs/M01-crm-kern.md`
**Milestone-PLANs (5):** M042-kontakt-stammdaten, M043-firma-stammdaten, M044-schlagwoerter-custom-felder, M045-aktivitaets-stream, M046-listen-segmente-dsgvo
## Phase 7: Lead-Inbox
**Specs:** `_bmad-output/specs/M02-lead-inbox.md`
**Milestone-PLANs (4):** M047-lead-inbox-quellen-adapter, M048-lead-routing-pro-quelle, M050-spam-duplikat-erkennung, M051-lead-status-pipeline-verlust-gruende
> M049-auto-projekt-anlage → Phase 8 verschoben (2026-06-10, Dependency-Inversion): braucht den `Projekt`-Kern (M060). P7 liefert den Extension-Point (Lead-Status `qualified` + Event), P8 verdrahtet die automatische Projekt-Anlage in der Sales-Pipeline.
## Phase 8: Projekt & Pipelines (Kern)
**Specs:** `_bmad-output/specs/M03-sales-pipeline.md` *(Bezeichner historisch; Inhalt projekt-zentrisch re-gemappt — Single Source: `.planning/ENTITY-MODEL.md`, AD-20)*
**Milestone-PLANs (7):** M049-auto-projekt-anlage, M059-sales-pipeline-konfiguration, M060-projekt-crud, M061-sales-kanban-ui, M062-verlust-gewinn-gruende, M063-auto-auftragsprojekt-setter-closer, M064-pipeline-reporting-kwp-sync
> 🔴 **Pivot-Re-Map (AD-20, R-REFIT 16.06.):** Die Milestone-Inhalte sind projekt-zentrisch re-gemappt — „Verkaufsfall"/„Deal" = ein `Projekt`-Kern in der Sales-Pipeline-Sicht (kein eigenes Deal-Objekt), `M060-projekt-crud` = Projekt-CRUD; Pipeline-Engine baut zusätzlich PipelineAccess/-FieldConfig/-FieldVisibility (Field-Level-Rechte v1). Maßgeblich ist ENTITY-MODEL.md, nicht der historische Bezeichner in älteren Specs.
> M049 (aus Phase 7, 2026-06-10): Auto-Projekt-Anlage bei Lead-Qualifizierung — hier, weil der `Projekt`-Kern (M060) hier entsteht.
## Phase 9: Projekt & Pipelines (Auftrag)
**Specs:** `_bmad-output/specs/M04-auftragspipeline.md` *(Bezeichner historisch; Inhalt projekt-zentrisch re-gemappt — Single Source: `.planning/ENTITY-MODEL.md`, AD-20)*
**Milestone-PLANs (6):** M065-auftragspipeline-konfiguration, M066-auftrag-crud-kwp-archiv, M067-plantafel-tage-granularitaet, M068-auftrag-mitglieder-mgmt, M069-abnahme-workflow, M070-material-listen-lager
> 🔴 **Pivot-Re-Map (AD-20, R-REFIT 16.06.):** Die Milestone-NAMEN bleiben als Datei-Referenz, ihr **Inhalt ist projekt-zentrisch re-gemappt** — Auftrags-Welt = Pipeline-View auf denselben `Projekt`-Kern (kein separates Project-Objekt, kein Won-Handoff); `M066-auftrag-crud` = Auftrags-Sicht/Sub-Areas am Projekt inkl. **Rechnung-Sub-Entity v1 (E3, NEU)**, `M069-abnahme-workflow` = AbnahmeProtokoll-Sub-Area (Mängel = Checkliste). Maßgeblich ist ENTITY-MODEL.md, nicht der historische Bezeichner.
> Scope-Schnitt 2026-06-12: **M070 gedünnt** — Lagerist-Sicht + Material-Ausgangs-Dokumentation → v2; Material-Listen am Auftrag bleiben (KWP-Daten folgen mit v2-P5/Phase 32). Noah-Frage zum Lager-Arbeitsplatz auf der E-Liste.
> 🟦 **KWP-Anteil (D-1, Entsch. 16.06.):** Die KWP-Tokens in `M064-…-kwp-sync` und `M066-auftrag-crud-kwp-archiv` sind **Extension-Point-only** — **KWP komplett v2** (Phase 32 / ROADMAP-V2 v2-P5). KWP-Archiv-Anteile von M064/M066/M069 ruhen bis v2; beim Plan-Lauf **KEINEN KWP-Bau triggern** (nur VM-Slot/Stub/Event liefern).
## Phase 10: KWP-Integration — **→ v2 (KOMPLETT DEFERRED, 2026-06-12 — ERSTES v2-Modul)**
**Specs:** `_bmad-output/specs/M19-kwp-integration.md` ⚠ Recut (siehe Note)
**Milestone-PLANs (0 in v1):** alle acht KWP-Milestones (Task-ERP-Sync + die komplette Sync-Familie) vollständig → v2 (siehe v2-Sektion).
> **Grund (Kalender, nicht Scope):** KWP-API-Zugang lt. Hersteller-Mail erst ~**19.07.2026** — nach dem v1-Launch (~10.07.). KWP bleibt USP und wird **erstes v2-Modul** (Sync ~2–3 Wochen nach Launch). **Sofort erledigt in v1:** Callback-URL an KWP gemeldet (`https://app.hivegrid.de/integrations/kwp/oauth/callback` — eine feste URL, Tenant im `state`; OAuth Authorization Code Flow mit PKCE), bnWin.net-Update auf 8.1 N3 bei Geerkens angestoßen. **Andockpunkte bleiben v1:** Apps-Engine (P5; KWP wird `DataConnection type='rest-api'`), Extension-Points an Auftrag/Abnahme/Material. Recut-Note bleibt bindend für die v2-Planung (kwpsync.exe NICHT bauen, M089 obsolet). Phasen-Nummer reserviert, Ausführungsreihenfolge überspringt P10.
## Phase 11: Globale Suche & Dashboard
**Specs:** `_bmad-output/specs/M24-globale-suche.md`, `M20-dashboard.md`
**Milestone-PLANs (5):** M056-such-index, M057-permission-aware-search, M058-such-ui-saved-searches, M147-dashboard-layout-widget-engine, M148-dashboard-standard-widgets
> Scope-Schnitt 2026-06-11/AD-26: M149-custom-widgets + M150-export-report → v2. Suche = **Keyword-only** (Meilisearch); pgvector/Hybrid-RRF/HiveMind entfällt bzw. ruht als v3-Kandidat.
> Scope-Schnitt 2026-06-12 (Boilerplate-Recheck): **M147 gedünnt** — 3 feste Rollen-Layouts (GF/Büro/Monteur) statt Drag&Drop-Grid (react-grid-layout wäre Neueinkauf); Layout-Persistenz pro User → v2. Widget-Registry bleibt voll (Inversion `M064→M147` registriert Sales-Widgets darüber).
## Phase 12: Automation-Engine
**Specs:** `_bmad-output/specs/M17-automation-engine.md`
**Milestone-PLANs (8):** M075-automation-schema-ausloeser, M076-automation-aktion-registry-steuerung, M077-automation-bedingungen, M078-automation-visueller-editor, M079-automation-test-lauf-vorschau, M080-automation-undo-fenster, M081-automation-schleifen-webhook-anomalie, M082-automation-klartext-logs-metering
## Phase 13: ~~KI-Layer~~ → entfällt ([[AD-26]])
> ⛔ **KI→MCP-Pivot ([[AD-26]]): Phase 13 entfällt in v1.** Die Milestones **M083/M084/M085/M086/M088 sind gelöscht** — HiveGrid hostet kein eigenes LLM/RAG. Die Tickets R-P13/D-P13/EXT-11 sind ebenfalls gelöscht.
~~**Specs:** `_bmad-output/specs/M18-ki-layer.md`~~ (entfällt)
~~**Milestone-PLANs (5):** M083-ki-eu-provider-layer, M084-ki-multi-provider-fallback, M085-ki-promptfoo-eval-suite, M086-ki-sprach-zu-automation, M088-ki-token-limits-pay-as-you-go~~ → **alle gestrichen ([[AD-26]])**
> ~~Scope-Schnitt 2026-06-11: M087 (HiveMind/RAG) + Whisper → v2. Sprach-zu-Automation (M086) EXKLUSIV im Automation-Kontext (direkte DB-Prüfungen, kein RAG). v1 baut Andock-Adapter: RetrievalProvider-Interface, Outbox-Index-Events (via P11), Bestätigungs-Grenze. M084: Mistral primär … → v2. M088: lokales Credits-Konto + Drossel; Abrechnung → v2.~~ → überholt durch [[AD-26]] (kein KI-Unterbau).
## Phase 14: Email & Marketing
**Specs:** `_bmad-output/specs/M09-email-inbox.md`, `M10-email-marketing.md`
**Milestone-PLANs (6):** M099-email-tracking-bounces, M100-marketing-email-editor, M101-marketing-segmente-empfaenger, M102-marketing-versand-engine, M103-marketing-ab-tests-reporting, M104-marketing-unsubscribe-bounces
> Scope-Schnitt 2026-06-11: M096/M097/M098 (Postfach-OAuth-Sync, Inbox-UI, Provider-Versand) → v2. **Aus M096 herausgelöst und v1-Pflicht:** Sende-Domain-Verifikation (DKIM/SPF/DMARC, Auto-Probe) — Marketing setzt sie voraus. **Neu (klein):** BCC-Logging-Brücke (`crm@tenant…` → Mail am Kontakt protokolliert, via Inbound-Infrastruktur). Marketing bleibt VOLL (inkl. A/B).
## Phase 15: Telefonie & Team-Chat
**Specs:** `_bmad-output/specs/M12-telefonie.md`, `M13-team-chat.md`
**Milestone-PLANs (9):** M106-telefonie-aircall, M107-telefonie-anruf-eingang, M108-telefonie-anruf-ausgang, M109-telefonie-voicemail-notizen, M110-chat-channel-permissions, M111-chat-direkt-nachrichten, M112-chat-anhaenge, M113-chat-modul-verknuepfungen, M114-chat-mentions-push
> Scope-Schnitt 2026-06-11: M105 (HalloPetra) → v2 — AirCall ist v1-Provider; TelephonyProviderInterface ist für den zweiten Adapter gebaut. Chat bleibt VOLL (inkl. Threads/Reactions/Pins).
## Phase 16: Kalender, Booking, Forms & Signatur
**Specs:** `_bmad-output/specs/M25-calendar-sync.md`, `M06-booking.md`, `M05-form-builder.md`, `M07-angebot-signatur.md`
**Milestone-PLANs (15):** M118-calendar-google-adapter, M119-calendar-termin-sync, M120-calendar-display-modul-verknuepfung, M121-form-editor, M122-form-veroeffentlichung, M123-form-submission-eingang, M124-form-conditional-display, M125-form-rate-limit-captcha-dsgvo, M126-booking-time-slot, M127-booking-verfuegbarkeit, M128-booking-bestaetigung, M129-booking-stornierung, M130-angebot-erstellung, M131-angebot-self-hosted-e-signatur, M132-angebot-status-tracking
> Scope-Schnitt 2026-06-12: **M122 gedünnt** — personalisierte Links (Tracking/Ablauf/Nutzungs-Limit) + JS-Snippet → v2; öffentliche URL + QR-Code + iFrame-Embed bleiben (SHK-Kernfall). **M129 bleibt explizit VOLL** (User-Entscheidung: Verschiebung/Re-Assignment/No-Show in v1).
## Phase 17: HR-Hub
**Specs:** `_bmad-output/specs/M14-hr-hub.md`
**Milestone-PLANs (7):** M133-hr-mitarbeiter-stammdaten, M134-hr-dokumente, M135-hr-urlaub, M136-hr-krankmeldungen, M137-hr-mitarbeiter-kommunikation, M139-hr-berichte-lohn-export, M140-hr-mitarbeiter-selbstbedienung
> Scope-Schnitt 2026-06-11: M138 (Drittanbieter-Onboarding Memberspot/Boobora) → v2. Mitarbeiter-Surveys (M139-Teil) bleiben auf User-Wunsch. M140 ohne Push in v1 (Web/PWA; Web-Push (VAPID) als Kanal → v2, AD-17).
## Phase 18: Customer-Portal — **→ v2 (KOMPLETT DEFERRED, 2026-06-11)**
**Specs:** `_bmad-output/specs/M15-customer-portal.md`
**Milestone-PLANs (0 in v1):** alle sechs Portal-Milestones vollständig → v2 (siehe v2-Sektion). AD-18 revidiert.
> v1 behält die Andockpunkte: P4-Portal-Upload-Vorbereitung (FileEntityLink), Portal-Pfad `app.hivegrid.de/portal/<tenant>/…` im P1-URL-Schema (gemäß `INTEGRATION-CONTRACTS.md` §6 — Pfad, keine Subdomain; korrigiert 2026-06-12). Phasen-Nummer bleibt reserviert (kein Renumbering), Ausführungsreihenfolge überspringt P18.
## Phase 19: Plattform-Admin
**Specs:** `_bmad-output/specs/M37-plattform-admin.md`
**Milestone-PLANs (7):** M031-feature-flag-schalter-lifecycle, M032-feature-flag-filter-editor, M034-plattform-admin-auth, M035-plattform-admin-dashboard, M036-plattform-admin-mandanten-verwaltung, M037-plattform-admin-stellvertreter-anmeldung, M041-plattform-admin-system-health-audit-support
> Scope-Schnitt 2026-06-11: M033 (Flag-Massen-Statistik) + M040 (Plattform-Lead-Pipeline) → v2. **Neu in P19-Scope:** Tenant-Abo-Zusammenstellung durch Admin (Abo-Baukasten-Mechanik: Feature-Konnektoren pro Tenant schalten + Legacy-Provider-Positionen; Self-Service-UI → v2).
> Scope-Schnitt 2026-06-12 (Boilerplate-Recheck): **M038 + M039 (getrennte AdminUser-Identität + AdminRBAC-Parallelwelt) → v2** — v1 nutzt das Boilerplate-Modell (AdminUser als User-Extension + MFA-Step-up-Gate, `admin-mfa-gate.server.ts`). **Bindende Auflagen für M034:** (a) TOTP-Pflicht hart erzwingen, (b) Admin-User bekommen **keinen Tenant-Workspace** und erscheinen in keiner Mandanten-Mitgliederliste (Boilerplate-Default-Provisionierung abschalten!), (c) Host-Routing `admin.hivegrid.de` → Admin-Routen (Boilerplate-Code routet `/admin`-Pfad), (d) **Cookie-Domain-Trennung** App↔Admin. **M035 gedünnt:** Boilerplate-KPIs (Tenants/User/MRR); Churn/ARPU/Health-Kacheln → v2 (bei 1 Launch-Kunden sinnfrei).
> M031–M033 (Flag-Admin-UI, 2026-06-10 aus Phase 3 hierher verschoben): Vorbedingung M034 (Admin-Auth) liegt hier; die Flag-**Engine** (M006, `tenantHasFlag()`) liegt in Phase 1 und ist ab dort von allen Phasen nutzbar.
## Phase 20: Billing, Onboarding & Branding
**Specs:** `_bmad-output/specs/M28-subscriptions-billing.md`, `M29-onboarding.md`, `M31-branding.md`
**Milestone-PLANs (8):** M030-pwa-theme-color, M153-subscriptions-billing-provider, M154-subscriptions-plan-seat-modell, M155-subscriptions-trial-readonly, M156-subscriptions-metering-pay-as-you-go, M158-onboarding-shk-provisionierung, M159-onboarding-branchen-templates, M160-onboarding-demo-daten
> ⚠ **M154-Recut bindend (2026-06-11):** Seat-Typ-Modell (Büro/Monteur) ist NICHT zu bauen — ersetzt durch **Abo-Baukasten**: Basis-Preis pro Nutzer + Feature-Module als zubuchbare Legacy-Provider-Positionen via Entitlement-Schicht (Flag-Engine `plan-tier`-Targeting × `packages/entitlements`). **Source-Spec:** `~/Documents/GitHub/archive/hivegrid-cloud/app/config/pricing-plans.ts` (Legacy D006: Core/Swarm/Colony, 14 Modul-Gates, 6 Quota-Dimensionen) — Struktur portieren, Preise/Tier-Zuschnitt = Kostenmatrix (Partner, AD-15). M156: Zähler+Drossel v1, Aufschlags-Abrechnung → v2. M157 (Wizard-UI) → v2 — Signup provisioniert SHK-Seed automatisch. M159: v1 nur SHK.
> Scope-Schnitt 2026-06-12: **M030 gedünnt** — nur Hell/Dunkel-Toggle, **kein System-Modus** (User-Entscheidung); nativer Status-Bar-Teil entfällt durch Mobile-Cut (Expo/Capacitor verworfen — PWA-only, AD-17; `next-themes` in Boilerplate-Deps). **M160 gedünnt** — KI-Walkthrough → v2 (gehört zum Wizard M157 = v2); Demo-Daten-Seed bleibt als Settings-Knopf, einfaches Löschen statt Multi-Step-Bulk; Mitarbeiter-Einladung läuft über M024.
## Phase 21: DSGVO & Launch-Reife
**Specs:** `_bmad-output/specs/M35-dsgvo-export.md` (M34/M36/M38/M39 → v2)
**Milestone-PLANs (2):** M164-dsgvo-daten-export, M165-dsgvo-loesch-workflow
> Scope-Schnitt 2026-06-11: Public-API (M161–163), DSGVO-Auskunft (M166 → manuelles Playbook: Suche + Kontakt-Export + Anwalts-Vorlage + Frist-Task), Mobile (M167–171, v2 als **Mobile-PWA-Ausbau** — Recut auf PWA, kein EAS-Build, keine Native-Module, keine Store-Compliance; Expo/Capacitor verworfen, AD-17), Help-Center/Desk (M172–175 → Minimal-FAQ) — alles → v2. **Bleibt zusätzlich klein in v1:** Feedback-Widget → speist P19-Support-Inbox (generische Quelle).
---
## v2-Phasen 22–34 — Source-Mapping
> Ergänzt 2026-06-15. Voll ausgearbeitete Phasen (Goal/Success-Criteria/Screens/Recut) in `.planning/ROADMAP.md` (Phase 22–34) + `.planning/ROADMAP-V2.md`. „phase:1"-Module (26/28/29/30): nur das **v2-Delta**, nicht das v1-Fundament. Block 2 (32/33/34) = Partner-API-Vertrag offen, agil vorziehbar.
### Phase 22: Public-API & Webhooks
**Specs:** `_bmad-output/specs/M34-public-api.md`
**Milestone-PLANs (4):** M161, M162, M163, M027 (api-keys)
**v1-Andockpunkte:** ApiKey-Modell (P2), Automation `external_event` + ausgehende Webhook-Action (P12), Frozen-Middleware (P20), Redis (Rate-Limit).
### Phase 23: Postfach-Sync (Email-Inbox)
**Specs:** `_bmad-output/specs/M09-email-inbox.md` (OAuth-Sync/Inbox/Threading; Sende-Domain ist v1)
**Milestone-PLANs (3):** M096, M097, M098
**v1-Andockpunkte:** Apps-Engine/`EmailProviderInterface` (P5), CRM-Matching (P6), Sende-Domain (P14), Files-Anhänge (P4). Risiko: Gmail restricted scopes (Antrag v1 EXT-13), Graph-Subscription-Renewal.
### Phase 24: Self-Service-Billing & Onboarding-Wizard
**Specs:** `_bmad-output/specs/M28-subscriptions-billing.md` (Block P), `M29-onboarding.md`
**Milestone-PLANs (1+):** M157 + M28-Self-Service-Delta
**v1-Andockpunkte:** Legacy-Provider/Checkout/Webhook + SubscriptionFeature (P20), TenantUserInvitation (P2), deklaratives Branchen-Template (geteilt P26/P30). Retro: KI-Coach aus P25.
### Phase 25: ~~KI-Tiefe — HiveMind/RAG~~ → MCP-Server ([[AD-26]])
> ⛔ **KI→MCP-Pivot ([[AD-26]]): Phase 25 zurückgestellt → ersetzt durch MCP-Server.** Kein M0xx-Milestone (v2-Neuschnitt); verbindliche Bau-Spec = **[[VR-MCP]]** (Backend) / **[[VD-MCP]]** (Screens). HiveMind/RAG/Whisper sind v3-Kandidat.
~~**Specs:** `_bmad-output/specs/M18-ki-layer.md` (RAG/HiveMind/Whisper-Teile)~~ (entfällt)
~~**Milestone-PLANs (1+):** M087 + Whisper-EU + pgvector-Hybrid + zweiter EU-Provider~~ → **M087 gelöscht ([[AD-26]]); kein Milestone, neues Ticket [[VR-MCP]]**
**v1-Andockpunkte (MCP):** ApiKey-Auth + Scopes + Rate-Limit (Public-API, [[VR-P22]]), withTenantScope/RLS, withPermission (M004), M001-Audit. ~~Retro: Help-Korpus von P29.~~ → Help optional als MCP-Resource.
### Phase 26: Customer-Portal ⭐ *(ex-P18)*
**Specs:** `_bmad-output/specs/M15-customer-portal.md`
**Milestone-PLANs (6):** M141, M142, M143, M144, M145, M146
**v1-Andockpunkte:** FileEntityLink (P4), CRM/Project (P6), Project-Stages/Acceptance (P9), Sende-Domain (P14), Form-Builder `portal_form` (P16), URL-Pfad `app.hivegrid.de/portal/<tenant>` (P1).
### Phase 27: Mobile-PWA-Ausbau
**Specs:** `_bmad-output/specs/M36-mobile-app.md` ⚠ Recut auf PWA (kein EAS-Build, keine Native-Module, keine Store-Compliance; Expo/Capacitor verworfen, AD-17)
**Milestone-PLANs (5):** M167, M168, M169, M170, M171 — Recut auf PWA (kein EAS-Build, keine Native-Module, keine Store-Compliance)
**v1-Andockpunkte:** OfflineSyncQueue (P9, PWA-ready), notify()-Web-Push-Kanal (P21), Auth/Magic-Link/Biometrie via WebAuthn (P2), `IS_MOBILE_APP`-Flag (P20). Kein App-Store (PWA-only); nativer Client → frühestens v3.
### Phase 28: Plattform-Admin-Tiefe
**Specs:** `_bmad-output/specs/M37-plattform-admin.md` (Block A–D), `M32-feature-flags.md` (Massen-Statistik)
**Milestone-PLANs (4):** M038, M039, M033, M040
**v1-Andockpunkte:** Admin-Welt-Fundament M034 (P19), Auth-Bausteine (P2), FeatureFlag-Modell (P1). Hardgrenze: kein BYPASSRLS.
### Phase 29: Help-Center & Help-Desk
**Specs:** `_bmad-output/specs/M38-help-center.md`, `M39-help-desk.md`
**Milestone-PLANs (4):** M172, M173, M174, M175
**v1-Andockpunkte:** Feedback-Widget→Support-Inbox (P21), Admin (P19), Files (P4). Retro: liefert HelpArticle-Embeddings an P25.
### Phase 30: Dashboard-Deluxe & Querschnitt
**Specs:** `_bmad-output/specs/M20-dashboard.md`, `M22-notifications.md`, `M30-i18n.md`
**Milestone-PLANs (4):** M149, M150, M117, M029
**v1-Andockpunkte:** Dashboard/Widget-Registry (P11), Notification-Center (P3), i18n-Library (P1), WebSocket (P15). DeepL DE→EN.
### Phase 31: DSGVO-Vollausbau
**Specs:** `_bmad-output/specs/M35-dsgvo-export.md`
**Milestone-PLANs (1):** M166
**v1-Andockpunkte:** DSGVO-Export/Lösch-Fundament (P21), AdminAuditLog/Legal-Verwaltung (P28). AVV-PDF anwaltlich (v1 EXT-03).
### Phase 32: KWP-Integration *(Recut, Block 2)*
**Specs:** `_bmad-output/specs/M19-kwp-integration.md` + **`docs/milestones/M19-KWP-API-RECUT.md` (bindend)**
**Milestone-PLANs (8):** M089, M090, M091, M092, M093, M094, M095, M074
**v1-Andockpunkte:** M33a Apps-Engine-Adapter-Interface M008–M010 (P5, HART), Auftrag/Abnahme/Material-Extension-Points (P9), Automation `kwp.push` (P12), Cloud-Outbox/Idempotenz (P1/M007). ⚠ kwpsync.exe NICHT bauen. **Trigger:** KWP-API-Zugang ~20.07.
### Phase 33: Telefonie-Erweiterung (HalloPetra) *(Block 2)*
**Specs:** `_bmad-output/specs/M12-telefonie.md` (Provider-Pattern) — ⚠ HalloPetra in keiner Spec → **Vorlauf-Spec nötig**
**Milestone-PLANs (1):** M105
**v1-Andockpunkte:** TelephonyProviderInterface + AirCall-Adapter (P15), Automation `call.*` (P12), notify() (P3). **Trigger:** HalloPetra-API-Vertrag.
### Phase 34: HR-Drittanbieter-Onboarding *(Block 2)*
**Specs:** `_bmad-output/specs/M14-hr-hub.md` — ⚠ Memberspot/Boobora in keiner Spec → **Vorlauf-Spec nötig**
**Milestone-PLANs (1):** M138
**v1-Andockpunkte:** Apps-Engine (P5), HR-Hub (P17). **Trigger:** Memberspot/Boobora-API-Vertrag.
---
## v2 — Committed Deferred (Stand 2026-06-11, Scope-Schnitt)
**Definition (User, verbindlich):** v2 = alles, was gemacht werden MUSS — nur sequenziert nach dem v1-Launch. Kein Vielleicht-Backlog. Vollständige Entscheidungs-Historie: `.planning/SCOPE-V1-CUTS.md`.
**43 Milestones → v2:**
- **KWP-Integration (8):** M074, M089–M095 — **ERSTES v2-Modul** (API-Zugang ~19.07. > Launch ~10.07.; Recut-Note bindend: kwpsync.exe NICHT bauen); Callback-URL gemeldet, bnWin.net-8.1-N3-Update angestoßen, Andockpunkte in v1
- **Mobile-PWA (5):** M167–M171 — ⚠ Recut auf PWA (kein EAS-Build, keine Native-Module, keine Store-Compliance; Expo/Capacitor verworfen, AD-17); v1 = mobile-first responsive Web / PWA; nativer Client + App-Store → v3
- **Customer-Portal (6):** M141–M146 — AD-18 revidiert; Andockpunkte bleiben v1
- **Postfach-Sync (3):** M096, M097, M098 — Sende-Domain-Verifikation herausgelöst in v1
- **Public-API (4):** M161–M163, M027 (API-Keys & Tarif-Gates — Boilerplate-`ApiKey`-Modell bleibt ungenutzt im Code; Scope-Schnitt 12.06.)
- **Help-Center/Desk (4):** M172–M175 — v1: Minimal-FAQ + Feedback-Widget→P19-Inbox
- **Dashboard-Deluxe (2):** M149 (Custom-Widgets), M150 (Export/Report)
- **Admin-Teile (4):** M033 (Flag-Massen-Statistik), M040 (Plattform-Lead-Pipeline), M038 + M039 (getrennte AdminUser-Identität/AdminRBAC — bindende Auflagen beim Admin-Auth-Milestone in P19 dokumentiert; Scope-Schnitt 12.06.)
- ~~**KI-Kür (1):** M087 (HiveMind/RAG; + Whisper, pgvector/Hybrid-Suche, AlephAlpha — REQ-Ebene)~~ → **KI→MCP-Pivot ([[AD-26]]): M087 gestrichen; v2 liefert stattdessen den MCP-Server ([[VR-MCP]]/[[VD-MCP]], kein M0xx). HiveMind/RAG/Whisper = v3-Kandidat.**
- **Querschnitt (2):** M117 (Notification-Bündelung/Quiet-Hours — bewusst v2), M029 (Sprach-Wechsler — v1 DE-only, i18n-Wiring bleibt Pflicht; beide Scope-Schnitt 12.06.)
- **Sonstige (4):** M105 (HalloPetra), M138 (Memberspot/Boobora), M157 (Wizard-UI), M166 (DSGVO-Auskunft → manuelles Playbook)
**Dünnungen in v1 (Modul bleibt):** Kalender nur Google (Outlook v2) · Sales-Analytik = Basis-KPIs · Booking eine Zuteilungs-Strategie · M154→Abo-Baukasten-Recut · M156 ohne Aufschlags-Abrechnung · M159 nur SHK · *(12.06.)* M028 DE-only · M054 ohne Versionierung/Office-Video-Preview (HEIC→JPG bleibt!) · M055 ohne OCR · M147 feste Rollen-Layouts · M152 fixe Retention · M035 Boilerplate-KPIs · *(12.06., #12)* M030 nur Hell/Dunkel (kein System-Modus) · M070 ohne Lagerist-Sicht · M122 ohne personalisierte Links/JS-Snippet · M160 ohne KI-Walkthrough
**Bilanz: v1 = 133 Milestones · v2 = 43 Milestones · Summe 176 ✓**
---
## Hinweise
- **Querschnitt-Milestones (M00, kein Modul):** Auf die Phasen verteilt, wo sie inhaltlich greifen — Fundament-Infra UND Service-Kerne (audit-default, i18n-wiring, flag-engine, notification-service) → Phase 1; aufgaben-listen → Phase 4; chat-/calendar-modul-verknuepfung → Phase 15/16.
- **Nicht im Ingest-Set (Phase 2-Produkt):** `M11-whatsapp` (von M13 referenziert; M18-Ref entfällt mit [[AD-26]]) ist nicht spec'd. Siehe REQUIREMENTS.md v2. ~~Beim Planen von P13/P15 als Stub markieren.~~ → P13 entfällt ([[AD-26]]); nur noch P15 betroffen.
- **Coverage:** 133 v1 + 43 v2 = 176/176 Milestone-PLANs zugeordnet, keine verwaisten Milestones. Dependency-Audit 2026-06-10: alle GSD-verursachten Reihenfolge-Verletzungen behoben (Service-Kerne → P1, M074 → P10, M031–M033 → P19). Scope-Schnitte 2026-06-11 + 2026-06-12 (#1–#12): siehe v2-Sektion.
---
## Dependency-Inversion — Retro-Integrations-Ownership (0 offene Vorwärts-Deps)
**Prinzip (verbindlich für jeden plan-phase-Lauf):** Das spätere Modul integriert sich rückwirkend in frühere Oberflächen. Jede `Vorbedingung:`-Zeile in einem Milestone-PLAN, die auf eine spätere Phase zeigt, ist hiermit **invertiert**: Die Integrations-Aufgabe GEHÖRT der späteren Phase (Owner), die frühe Phase liefert nur den Extension-Point (VM-Slot, Domain-Event, Stub-Tabelle). Die BMAD-PLAN.md-Quelldateien bleiben unverändert — dieses Register ist die verbindliche Neuinterpretation. Damit existieren auf Phasen-Ebene **keine unaufgelösten Vorwärts-Abhängigkeiten**.
### Ownership-Register (wer integriert was rückwirkend)
| Owner | Retro-Integrations-Aufgaben (beim Planen dieser Phase MIT einplanen) |
|---|---|
| **P6 CRM** | Task↔CRM-Entity-Verknüpfung verdrahten (`M071→M042`; P4 liefert polymorphe EntityLink) |
| **P8 Sales** | Auto-Projekt aus qualifiziertem Lead (M049, hierher verschoben); SHK-Pipelines + Gründe selbst seeden (`M059→M158`, `M062→M158`); Lead→Projekt-Verdrahtung konsumiert das P7-Event |
| **P9 Projekte** | Sales-Won-Handoff konsumieren (`M063→M065`; P8 liefert deal.won-Event); Abnahme-Defaults selbst seeden (`M069→M158`) |
| **P10 KWP** *(→ v2, erstes v2-Modul = Phase 32 / ROADMAP-V2 v2-P5)* | Retro-Integrationen wandern mit: KWP-Sync in Auftrag-Archiv, Abnahme-Drift-Schutz, Material-Listen, Task-ERP-Sync (M074) — Phase 32 (= ROADMAP-V2 v2-P5, ex-P10) integriert sich rückwirkend; v1 liefert die Extension-Points (Auftrag/Abnahme/Material) |
| **P11 Suche/Dashboard** | Hybrid-Suche-Upgrade für Audit-Viewer (`M151→M057`), Datei-Suche (`M055→M056`), CRM-Segmente (`M046→M056`), Kanban-Filter (`M061→M057`); Sales-Reporting-Widgets (`M064→M147`; P8 liefert Aggregat-APIs); Dashboard-Default-Layout selbst seeden (`M148→M158`) |
| **P12 Automation** | Task-Liste im Automation-Modul (`M072→M075`; Pattern aus P4) |
| ~~**P13 KI**~~ → entfällt ([[AD-26]]) | ~~KI-Actions in der Automation-Registry registrieren (`M076→M083`; Registry ist type-safe erweiterbar gebaut)~~ → **entfällt: kein KI-Layer, keine KI-Actions (M083 gelöscht). Die Automation-Registry bleibt erweiterbar; künftige MCP/Provider docken via Apps-Engine an.** |
| **P14 Email/Marketing** | Task-Liste im Marketing-Modul (`M072→M104`); Channel-Bedarf von M068 prüfen (`M068→M104` — voraussichtlich durch P1-notify()-Kern gedeckt); Email-Templates selbst seeden (`M100→M158`) |
| **P16 Kalender/Booking/Forms** | Kalender in Plantafel (`M067→M119`, `M067→M129`); Kalender-Termin aus Won-Deal (`M063→M119`); Form-Templates für Abnahme (`M069→M121`); Task-Liste im Forms-Modul (`M072→M121`); Form-Templates selbst seeden (`M125→M158`) |
| **P17 HR** | Abwesenheiten in Plantafel anzeigen (`M067→M135`) |
| **P20 Billing/Branding** | Legacy-Provider ersetzt Subscription-Stub (`M026→M153`, `M036→M153`, `M041→M153`); ~~AI-Credits-Kauf (`M088→M153`, `M088→M156`)~~ → **entfällt ([[AD-26]]: kein LLM-Gateway → keine AI-Credits; M088 gelöscht)** |
| **v2 (deferred Owner)** | Diese Retro-Integrationen wandern mit ihren Owner-Modulen nach v2: Push-Kanal-Aktivierung + Settings-Erweiterung (Mobile), Theme→Portal, Portal-DSGVO-Löschung, Help-Desk→Admin-Inbox, Abwesenheiten→Plantafel bleibt v1 (HR bleibt!) |
### Extension-Point-Pflichten (frühe Phase MUSS liefern, damit die Inversion trägt)
| Phase | Extension-Point |
|---|---|
| P1 | `notify()` mit Kanal-Abstraktion inkl. ruhendem Push-Kanal; Search-Registry; Flag-Engine (bereits Success Criteria) |
| P2 | TenantSubscription-Status-Stub (manuell setzbar) — Frozen-Modus (M026) liest nur den Status, Legacy-Provider füllt ihn ab P20 |
| P3 | Notification-Settings-UI kanal-erweiterbar (Push-Sektion erscheint in P21) |
| P4 | Polymorphe EntityLink-Tabelle (`entity_type` + `entity_id`, kein harter FK); Task-Listen-Pattern als wiederverwendbare Komponente |
| P7 | Lead-Status-Event `lead.qualified` (Extension-Point für M049 in P8) |
| P8 | `deal.won`-Domain-Event; Aggregat-APIs für Reporting |
| P9 | Plantafel-VM-Slots für Termine/Abwesenheiten/Storno; Abnahme v1 mit festem Formular |
| ~~P13~~ → entfällt ([[AD-26]]) | ~~Lokales AiCredits-Konto mit manuellem Top-up (Kauf/Abrechnung folgt P20)~~ → **entfällt: kein KI-Layer/LLM-Gateway in v1; AiCredits gestrichen.** |
| P18 | *(→ v2)* Portal startet mit Default-Theme |
| P19 | Support-Inbox mit generischer Message-Quelle |
### Seed-Regel (ersetzt alle M158-Vorwärts-Refs)
Jede Modul-Phase seedet ihre eigenen SHK-Defaults deklarativ (AD-12). M158 (P20) orchestriert nur den Onboarding-Wizard über bereits vorhandene Seeds. Alle Refs auf M158 aus P8/P9/P11/P14/P16 sind durch Self-Seeding obsolet.
### Audit-Register (maschinenlesbar — jede invertierte Ref einzeln)
`M026→M153` `M151→M057` `M055→M056` `M071→M042` `M072→M075` `M072→M104` `M072→M121` `M046→M056` `M059→M158` `M061→M057` `M062→M158` `M063→M065` `M063→M119` `M064→M147` `M067→M119` `M067→M129` `M067→M135` `M068→M104` `M069→M121` `M069→M158` `M148→M158` ~~`M076→M083`~~ ~~`M088→M153`~~ ~~`M088→M156`~~ `M100→M158` `M125→M158` `M036→M153` `M041→M153`
> ⛔ **KI→MCP-Pivot ([[AD-26]]): 3 Einträge entfernt** — `M076→M083`, `M088→M153`, `M088→M156` (Ziele M083/M088 gelöscht, kein KI-Layer). Verbleibend: **25 Einträge**.
(~~28~~ → 25 Einträge, Stand 2026-06-12 nach Scope-Schnitten + [[AD-26]]. Entfernt am 11.06.: 9 Refs, deren Quelle oder Ziel → v2 ging (Quellen/Ziele: 116, 030, 140 gegen 167/168/171; 141 gegen 030; 146 gegen 165; 041 gegen 174) — sie leben als v2-Inversionen in der v2-Planung weiter. Entfernt am 12.06. (#12, P10 → v2): die drei KWP-Inversionen (Quellen 066, 069, 070 gegen 095/092) — wandern mit dem v2-P10-Owner; die v1-Quell-Milestonen liefern weiterhin nur die Extension-Points. Ebenfalls per Inversion aufgelöst: die KWP-Anteile in den Vorbedingungen von 123 (Post-Submit-Action „KWP-Push" — Action-Registry ist erweiterbar, v2-P10 registriert nach, identisch zur Automation-Registry-Note) und 158 (KWP-Plantafel-Seed-Anteil entfällt in v1; v2-P10 seedet selbst, AD-12). Ergänzung 12.06.: Die M158-Vorbedingung „M115–M117" verliert ihren M117-Anteil an v2 — der Seed-Umfang von M158 umfasst nur noch Notification-Defaults aus M115/M116 (Bündelungs-Defaults entfallen); kein Register-Eintrag nötig, da M115/M116 in P3 vor P20 liegen. Ferner dokumentiertes Bereichs-Artefakt: Die M051-Vorbedingung „M047-M050" enthält M049 nur als Range-Nebeneffekt (M049 → P8 am 10.06.); M051 braucht real nur M047/M048/M050 — kein Register-Eintrag, beim P7-Planen die Range als M047/M048/M050 lesen. Konstruktionsbedingt zulässig: Die M164-Vorbedingung „M042-M170 (alle Daten-Module)" meint „alles, was zum Export-Zeitpunkt existiert" — v1-Export deckt die v1-Datenmodelle; jedes v2-Modul registriert seinen DSGVO-Export-Adapter bei v2-Bau selbst nach (Inversion, Owner = v2-Modul). Audit-Kontrakt: Vorwärts-Refs aus den Milestone-Vorbedingungen der **v1-gemappten** Milestones MINUS dieses Register MUSS leer sein.)
*Generiert: 2026-06-07 als Brücke zwischen GSD-ROADMAP und bestehender BMAD-Milestone/Spec-Basis.*
@@ -2,34 +2,35 @@
## What This Is
HiveGrid 2.0 ist eine Multi-Tenant-SaaS-Plattform für SHK-Handwerksbetriebe (Sanitär, Heizung, Klima). Sie bündelt CRM, Vertriebs- und Auftragspipeline, Team-Chat, visuelle KI-Automation und die Anbindung an das KWP-ERP in einem EU-gehosteten System.
HiveGrid 2.0 ist eine Multi-Tenant-SaaS-Plattform für SHK-Handwerksbetriebe (Sanitär, Heizung, Klima). Sie bündelt CRM, Projekt-/Pipeline-Arbeit, Team-Chat, visuelle Automation und die Anbindung an das KWP-ERP in einem EU-gehosteten System. Externe KI-Clients können später über die Remote-MCP-Surfaces andocken; HiveGrid hostet nach AD-26 keine eigene Inferenz.
HiveGrid ist ein Multi-Kunden-SaaS für den gesamten SHK-Markt. Die **Geerkens GmbH** (Kontakt: Noah) ist erster Kunde und Investor — Validierungspartner, nicht alleiniger Zweck. Das Produkt ersetzt dort HubSpot (CRM + Sales-Pipeline), Quiply (Team-Chat), Zapier/n8n (Automation) sowie mehrere Excel-Prozesse. Die Codebase wird als bespoke HiveGrid-Anwendung weitergeführt: historisches Fundament wird genutzt, produktfremde Altlasten werden entfernt.
> 🔴 **MODELL-PIVOT (2026-06-13):** CRM/Pipeline-Modell ist **Projekt-zentrisch** — ein `Projekt`-Kern, Pipelines = frei konfigurierbare Views; „Deal"/„Auftrag" sind Pipeline-Typen, keine eigenen Entitäten. Single Source: `.planning/ENTITY-MODEL.md`. ENTITY-MODEL/REQUIREMENTS/SCREEN-MAP/PHASE-SOURCES werden gegen den Anker neu gefasst (ER-Modell wird gemeinsam gebaut).
> 🔴 **MODELL-PIVOT (2026-06-13):** CRM/Pipeline-Modell ist **Projekt-zentrisch** — ein `Projekt`-Kern, Pipelines = frei konfigurierbare Views; „Deal"/„Auftrag" sind Pipeline-Typen, keine eigenen Entitäten. Single Source: `.planning/ENTITY-MODEL.md`. Entity Model, Requirements, Screen-Map und Ticket-Docs wurden gegen diesen Anker neu gefasst.
## Core Value
Jeder SHK-Betrieb (Mandant) wickelt die komplette Wertschöpfungskette — **Lead → Projekt (frei konfigurierbare Pipelines: Sales/Auftrag/…) → KWP-Sync (ab v2)** — inklusive visueller KI-Automation in einem einzigen, DSGVO-konformen EU-System ab. Wenn diese Kette nicht durchgängig funktioniert, scheitert das Produkt.
Jeder SHK-Betrieb (Mandant) wickelt die komplette Wertschöpfungskette — **Lead → Projekt (frei konfigurierbare Pipelines: Sales/Auftrag/…) → KWP-Sync (ab v2)** — inklusive visueller Automation in einem einzigen, DSGVO-konformen EU-System ab. Der initiale KWP-Scope liest KWP-Daten nach HiveGrid; Writeback folgt erst nach belastbarem Providervertrag und erneuter Freigabe gemäß AD-32/CR-003. Wenn diese Kette nicht durchgängig funktioniert, scheitert das Produkt.
## Requirements
Vollständige Liste mit 79 v1-Requirements über 36 Module: siehe `.planning/REQUIREMENTS.md`. Detaillierte Acceptance-Kriterien je Requirement: `.planning/intel/requirements.md` + Modul-Specs unter `_bmad-output/specs/`.
Vollständige Requirements stehen in `.planning/REQUIREMENTS.md`. Ausführbare Acceptance-Kriterien und
DoD stehen ausschließlich in den self-contained Ticket-Docs unter `.planning/ticket-docs/`.
### Validated
<!-- Geliefert und bestätigt wertvoll. -->
(Noch keine — Big-Bang-Launch ohne phasiertes Produktiv-Go-Live, AD-19. Validierung erfolgt pro Modul über Noah/Geerkens via PROGRESS-TRACKER-Klick-Pfad.)
(Noch keine — Big-Bang-Launch ohne phasiertes Produktiv-Go-Live, AD-19. Validierung erfolgt pro Modul über Noah/Geerkens via UAT-Klick-Pfad der Ticket-Doc.)
### Active
<!-- Aktueller Scope. Scope-Schnitt 2026-06-11: v1 = 146 Milestones / 94 Reqs; 30 MS committed → v2 (Mobile-PWA-Ausbau, Portal, Postfach-Sync, Public-API, Help, HiveMind/Whisper u.a.) — Details: SCOPE-V1-CUTS.md + ROADMAP. NEU: Konnektor-Pflicht (jedes Modul plan-gebunden schaltbar) + Abo-Baukasten-Billing (M154-Recut, Legacy: archive/hivegrid-cloud pricing-plans.ts, Core/Swarm/Colony). -->
<!-- Aktueller Scope. AD-26 ersetzt den früheren KI-/RAG-Plan: kein eigener KI-Layer in v1/v2; v2 liefert stattdessen VR-MCP/VD-MCP. Details: REQUIREMENTS.md + ROADMAP-V2.md. -->
**USP-Säulen (Differenzierung, volle Tiefe day-1 — AD-16):**
**USP-Säulen (aktuell nach AD-26):**
- [ ] Automation-Engine (M17) — visueller Editor, alle Trigger/Aktionen, 24h-Undo, Guards
- [ ] KI-Layer (M18) — EU-Provider, RAG, Sprach-zu-Automation, Pay-as-you-go
- [ ] KWP-Integration (M19) — bidirektionaler Sync mit dem SHK-ERP KWP (Kernsystem des Erstkunden)
- [ ] Remote-MCP-Surfaces (`VR-MCP`/`VD-MCP`, v2) — permission-aware Produktzugriff für externe KI-Clients; keine eigene Inferenz
- [ ] KWP-Integration (M19) — initial read-only KWP → HiveGrid; Writeback provider-gegatet und nach `VEXT-6` geparkt (AD-32/CR-003)
**SHK-Kernpfad (AD-11, Projekt-zentrisch nach AD-20):**
- [ ] CRM/Kontakt-Kern (M01), Lead-Inbox/LeadInput (M02), **Projekt & Pipelines** (vormals Sales M03 + Auftrag M04 → ein `Projekt`-Kern + konfigurierbare Pipeline-Views; Abnahme bleibt v1 als Checklisten-Sub-Area, Rechnung = Sub-Entity v1)
@@ -44,25 +45,29 @@ Vollständige Liste mit 79 v1-Requirements über 36 Module: siehe `.planning/REQ
<!-- Explizite Grenzen mit Begründung — verhindert Scope-Creep. -->
- **Phase-2-Module (z.B. M11 WhatsApp)** — nicht spec'd, späterer Release; von M13/M18 referenziert, aber nicht im Ingest-Set
- **Konkrete Pricing-Stufen** — Billing-Engine wird gebaut, Preise geparkt; Geerkens auf Sonderkondition/Trial (AD-15)
- **Phase-2-Module (z.B. M11 WhatsApp)** — nicht spec'd, späterer Release; von M13 referenziert, aber nicht im Ingest-Set
- **Konkrete Pricing-Stufen** — grundsätzlich weiter geparkt (AD-15). **Ausnahme AD-30/CR-001:** Starter/Team zahlen 19,99 EUR netto/Monat für das Customer-Portal; Business und Enterprise enthalten es. Die Custom-Portal-Domain kostet Starter/Team/Business 299,99 EUR netto je Einrichtung; Enterprise enthält eine Domain. Ein Domainwechsel ist eine neue Einrichtung, sofern keine individuelle Enterprise-Regel greift.
- **Volle Migrations-Pipelines pro Altsystem** — sauberer Start, KWP-Sync füllt nach; HubSpot/Quiply als Read-only-Archiv, nur punktuelle CSV-Importe (AD-14)
- **KWP-Writeback im initialen Phase-32-Scope** — keine fachlichen KWP-Mutationen; M091, M094-outbound,
M074-outbound und Project-/Auftrag-Create bleiben bis `VEXT-6` + erneuter Produktfreigabe geparkt
(AD-32/CR-003)
- ~~EU-Email-Provider (AD-6) / Captcha (AD-7)~~ — **entschieden 11.06.: Mailjet + mCaptcha** (Boilerplate-verdrahtet)
- **KWP Windows-Sync-Programm (M089, alte M19-Variante)** — entfällt durch offizielle KWP-API; M089–M095 vor Umsetzung neu schneiden
## Context
- **SHK-Domäne:** Geerkens = Heizungsanlagen/Wartung/Reparatur. Entitäten: B2C/B2B-Kunden mit Anlagen-Zustand (Custom-Felder), mehrstufige Anlagen-Verkäufe, Wartungsverträge, Reparatur-Aufträge. Monteure arbeiten offline auf Baustellen (AD-17).
- **SHK-Seeds beim Tenant-Anlegen:** 6 Standard-Rollen + Permission-Bundles, SHK-Sales-Pipelines, Custom-Felder für Heizungsanlagen, Projekt-Pipelines, Automation-Templates, Onboarding-Branchen-Zweig — deklarativ, von Noah iterativ validiert (AD-12).
- **SHK-Defaults beim Tenant-Anlegen:** fünf editierbare Tenant-Rollen + Permission-Bundles und ausschließlich die globale Rolle `Admin` für den Owner, SHK-Sales-Pipelines, Custom-Felder für Heizungsanlagen, Projekt-Pipelines, Automation-Templates, Onboarding-Branchen-Zweig — deklarativ, von Noah iterativ validiert (AD-12/AD-29).
- **Workspace-Naming:** Alle Runtime-, UI-, Config-, DB-, Mail-, Queue- und View-Model-Pakete laufen unter `@hivegrid/*`; CLI = `hivegrid-cli`; technische Produkt-Contracts nutzen `HIVEGRID_*`, `hivegrid_*`, `x-hivegrid-*` und `hivegrid.*`.
- **Phase-0-Pflichten (vor jedem Fachmodul):** (1) Codebase lauffähig halten, (2) Naming-Drift beheben (AD-10), (3) EU-Sterilisation (GitHub/Google-OAuth-Reste raus), (4) M00 + 4 Querschnitts-Neubauten (logActivity, Search-Registry, Subframe-Adapter, Mass-Action-Schutz), (5) fehlende Dependencies ergänzen.
- **Spec-Stil:** Alle 36 Specs sind „requirements-pur" (benötigte UI-Elemente als Liste, keine Layouts — Designer hat freie Hand) und im Status `detail-spec-draft`. Vor Modulbau: Noah-Verifizierung, Index-/Migrations-SQL, SHK-Defaults finalisieren, Subframe-UI-Designs.
- **Bau-Spec-Stil:** Ticket-Docs sind self-contained und enthalten Was, Screens, DoD, technische
Bausteine, Abhängigkeiten und aktuelle Quellen.
## Constraints
- **Mandanten-Trennung**: Echtes Postgres-RLS als bauliche Vorgabe (USING/WITH CHECK, `SET LOCAL app.tenant_id`, App-Rolle ohne BYPASSRLS) — AD-1
- **Datenmodell**: Typisierte First-Class-Prisma-Tabellen; Boilerplate-Entity-Builder (Entity/Row/RowValue) wird entfernt; Custom-Felder über `CustomFieldDefinition`+`CustomFieldValue` — AD-2
- **EU-Stack (keine US-Kern-Abhängigkeit)**: Meilisearch (zentral auf `node1`, scoped Key — Infra-ADR-008/013) + pgvector v2 + RRF (AD-5 sequenziert), Per-Tenant-DEK/Envelope-Encryption **app-seitig** (AD-8 revidiert 12.06.: Hetzner-Stack hat kein Cloud-KMS — Master-Key im Coolify-Secret-Store, Rotations-Runbook; bei P1-Ist-Stand-Check bestätigen), Mailjet (AD-6 ✓), mCaptcha zentral `captcha.saas-ctrl.com` (AD-7 ✓)
- **EU-Stack (keine US-Kern-Abhängigkeit)**: Meilisearch Keyword-only (zentral auf `node1`, scoped Key — Infra-ADR-008/013) mit SQL-Fallback; kein pgvector/RRF/Embedding in v1/v2 nach AD-26. Per-Tenant-DEK/Envelope-Encryption **app-seitig** (AD-8 revidiert 12.06.: Hetzner-Stack hat kein Cloud-KMS — Master-Key im Coolify-Secret-Store, Rotations-Runbook; bei P1-Ist-Stand-Check bestätigen), Mailjet (AD-6 ✓), mCaptcha zentral `captcha.saas-ctrl.com` (AD-7 ✓)
- **Infra-Stack (Infra-Repo `~/Documents/GitHub/infra`, ADR-009/010, ersetzt Scaleway seit 30.05.)**: Hetzner Cloud, ein Projekt pro SaaS (`HiveGrid`: hivegrid-db/app/worker/lb + S3-kompatibles Object Storage + Storage Box); Staging konsolidiert auf `staging-1`; Deploys via zentrale Coolify-Control-Plane; Registry = Gitea (build-once/promote); DNS = Cloudflare (`hivegrid.de`-Zone existiert); zentrale Dienste: Meilisearch/Sentry/Loki (node1), ClamAV, mCaptcha. `fly.toml` entfernt (Infra = Hetzner/Coolify); `docs/deployment-region-provider-pinning.md` stale → P1-Ist-Stand-Check
- **Sessions**: Postgres als Source-of-Truth + Redis-Cache; Cookie hält nur Session-ID (AD-4)
- **Realtime**: WebSocket für Chat (M13), SSE für Read-Updates (M03/M22) — AD-9
@@ -72,7 +77,8 @@ Vollständige Liste mit 79 v1-Requirements über 36 Module: siehe `.planning/REQ
## Key Decisions
Vollständige Extraktion mit Scope/Begründung: `.planning/intel/decisions.md`. Quelle: `docs/ARCHITECTURE-DECISIONS.md`.
Operative Architekturregeln stehen in `AGENTS.md`; IDs, Gründe und Status im kompakten Register
`docs/ARCHITECTURE-DECISIONS.md`.
| Decision | Kern | Status |
|----------|------|--------|
@@ -80,7 +86,7 @@ Vollständige Extraktion mit Scope/Begründung: `.planning/intel/decisions.md`.
| AD-2 | Typisierte Tabellen, Entity-Builder raus — **revidiert 13.06.:** `Projekt` = EINE typisierte Tabelle + CustomFields + Pipeline-Feld-Config-Layer; generischer Entity-Builder bleibt entfernt | ✓ revidiert (13.06.) |
| AD-3 | Plattform-Admin getrennt (Email+PW+TOTP, opt. Authentik-SSO) | ✓ locked |
| AD-4 | Sessions: Postgres Source-of-Truth + Redis-Cache | ✓ locked |
| AD-5 | Such-Engine: Meilisearch (v1 Keyword); pgvector-Hybrid → v2 | ✓ sequenziert (11.06.) |
| AD-5 | Such-Engine: Meilisearch Keyword-only + SQL-Fallback; pgvector/RRF durch AD-26 aufgehoben | ✓ revidiert (AD-26) |
| AD-6 | EU-Email-Provider: **Mailjet** (Boilerplate-verdrahtet) | ✓ locked (11.06.) |
| AD-7 | Captcha: **mCaptcha self-hosted** (infra/ vorhanden) | ✓ locked (11.06.) |
| AD-8 | Verschlüsselung: Per-Tenant-DEK + Envelope, Crypto-Shredding | ✓ locked |
@@ -91,12 +97,16 @@ Vollständige Extraktion mit Scope/Begründung: `.planning/intel/decisions.md`.
| AD-13 | Go-Live-Scope: breiter Launch (Großteil der 36 Module) | ✓ locked |
| AD-14 | Migration: sauberer Start + KWP-Sync füllt nach | ✓ locked |
| AD-15 | Billing-Engine bauen, Preise geparkt | ✓ locked |
| AD-16 | USP-Säulen (Automation + KI) in voller Tiefe day-1 | ✓ locked |
| AD-16 | Historischer KI-USP-Plan | überholt durch AD-26 |
| AD-17 | Mobile: **PWA-only (v1 + v2)** — Offline via PWA/Web (P9), Web-Push in v2; **kein Expo/native/App-Store** (native → frühestens v3) | ✓ revidiert (16.06.) |
| AD-18 | Customer-Portal → komplett v2 | ✓ revidiert (11.06.) |
| AD-19 | Go-Live-Modus: Big-Bang | ✓ locked |
| AD-20 | **Projekt-zentrisches Modell (NEU 13.06.):** ein `Projekt`-Kern; Pipelines = konfigurierbare Views; „Deal"/„Auftrag" = Pipeline-Typen, keine eigenen Entitäten; Lead → Projekt (Weiterverarbeitungsfreigabe); Abnahme v1 als Checklisten-Sub-Area, Rechnung v1-Sub-Entity, KWP-Felder v1-Halter/v2-Sync | ✓ locked (13.06.) |
| KWP-Recut | Offizielle KWP-API → M089 entfällt, M090–M095 vereinfacht; M093 bleibt; KWP als `DataConnection type='rest-api'` (M33a). M089–M095 vor Umsetzung neu schneiden. | ⚠ Recut nötig |
| AD-26 | Kein eigener KI-Layer/LLM/RAG/Whisper in v1/v2; stattdessen Remote-MCP (`VR-MCP`/`VD-MCP`) | ✓ locked |
| AD-30 | Customer-Portal auf `portal.hivegrid.de/<tenant>`; separater `hivegrid-portal`-Container aus dem Web-Image mit eigenem DB-Login; Starter/Team als Add-on, Business/Enterprise inklusive; Self-Service-Custom-Domain über DNS-Proof + CNAME + automatisches TLS | ✓ locked (15.07.; Paket-/Rollout-Nachtrag 16.07.) |
| AD-31 | Plattform-Leads nativ in der operatorweiten Admin-Welt; `lead-inbox` nach Backfill, Cutover und Drain stilllegen; M040a als `R-LEADS` vorziehen | ✓ locked (16.07.) |
| AD-32 | Initialer KWP-Scope in v2-P5/Phase 32 ist read-only; keine fachlichen KWP-Mutationen. Writeback inklusive M091, M094-outbound, M074-outbound und Project-Create bleibt hinter `VEXT-6` + erneuter Freigabe geparkt. | ✓ locked (22.07., CR-003) |
| KWP-Recut (historischer Stand 12.07.) | Offizielle KWP-API → M089 entfällt, M090–M095 vereinfacht; M093 bleibt; KWP als `App(key='kwp', connectionType='oauth2')` mit tenant-spezifischer `DataConnection` und dynamischem Tenant-Relay (M33a). Tenant-OpenAPI/Redirects verifiziert; Runtime-Scopes + Auftrag-Create waren zu diesem Stand extern offen. | durch AD-32 superseded; Runtime-Dauerbetrieb bewiesen |
---
*Erzeugt: 2026-06-07 via `/gsd:ingest-docs` (Stufe 1 — WHAT) aus 38 Docs (37 SPEC + 1 ADR). ROADMAP folgt in Stufe 2.*
*Erstellt: 2026-06-07 · aktive Quellen zuletzt bereinigt: 2026-08-02.*
@@ -1,24 +1,22 @@
# .planning/ — START HIER (Live-Planung HiveGrid 2.0)
# .planning/ — Planungsunterlagen HiveGrid 2.0
Dies ist das **aktive Planungs-Zuhause**. Wenn du planst, steuerst oder verstehen willst „wo stehen wir" — hier, nicht in `docs/` (das ist Boilerplate-/Technik-Referenz).
Operativer Status, Ownership und Dependencies liegen in Plane. Gebaut wird ausschließlich nach
`.planning/ticket-docs/<ID>.md`; die übrigen Dateien liefern fachliche und architektonische Referenz.
**Stand:** 2026-06-15
**Stand:** 2026-08-02
## Zuerst lesen (in dieser Reihenfolge)
1. **PROJECT.md** — Was ist HiveGrid, Core Value, Key Decisions (AD-1…AD-20), Constraints.
2. **ROADMAP.md** — die 21 Phasen mit Zielen & Success-Criteria.
3. **STATE.md** — aktueller Stand, was als Nächstes dran ist.
1. **ticket-docs/<ID>.md** — ausführbare Bau-Spec und DoD des Tickets.
2. **ENTITY-MODEL.md** — verbindliches Datenmodell.
3. **PROJECT.md / ROADMAP*.md / REQUIREMENTS.md** — Produkt- und Scope-Referenz.
## Kern-Planung (gepflegt)
| Datei | Inhalt |
|---|---|
| PROJECT.md | Charter + Architektur-Entscheidungen (Kurzfassung; voll in `docs/ARCHITECTURE-DECISIONS.md`) |
| PROJECT.md | Produkt-Charter und Architekturkontext |
| ROADMAP.md | 21 Phasen, Reihenfolge, Success-Criteria |
| REQUIREMENTS.md | v1-Requirements (90) je Modul |
| PHASE-SOURCES.md | Phase → Milestone-PLANs (`docs/milestones/`) Mapping für /gsd-plan-phase |
| SCOPE-V1-CUTS.md | Entscheidungs-Historie v1↔v2 (Schnitte #1–#13) |
| TIMELINE.md / SPRINT-4W.md | Master-Timeline + 4-Wochen-Sprint |
| STATE.md | Live-Status |
| KWP-API-CONTRACT.md | bindender read-only KWP-Connector- und Providervertrag |
## Datenmodell — ✅ APPROVED & LOCKED (Projekt-zentrisch, AD-20)
| Datei | Rolle |
@@ -26,20 +24,22 @@ Dies ist das **aktive Planungs-Zuhause**. Wenn du planst, steuerst oder verstehe
| **ENTITY-MODEL.md** | autoritatives Datenmodell (voll) |
| **entity-model.dbml** | maschinenlesbar → in dbdiagram.io importieren |
| **entity-model.svg** | gerendertes ER-Diagramm |
| **ENTITY-MODELL-ERKLAERUNG.md/.pdf** | laienverständliche Fassung (für Design/Stakeholder) |
| **ENTITY-MODELL-ERKLAERUNG.md** | laienverständliche Fassung (für Design/Stakeholder) |
| HiveGrid_CRM_Datenlogik_UX_Entscheidungen.md | Davids approved UX-Quelle (Grundlage des Pivots) |
## UX / Design
- **SCREEN-MAP.md** — Bau-Liste aller v1-Screens (Davids Arbeitsliste)
- **designer-briefs/** — phasenbezogene Screen-Briefs für David
- **DESIGNER-FIRST-PLAYBOOK.md** — Designer-first-Methodik + Archetypen
## Externe Abhängigkeiten
- **EXTERNALS-CHECKLISTE.md** — Konten/APIs (KWP, Mistral, Mailjet, AirCall, Legacy-Provider, …)
Externe Abhängigkeiten werden als `EXT-*`-/`VEXT-*`-Tickets in Plane und in den zugehörigen
`.planning/ticket-docs/` gepflegt. Es gibt keine zweite globale Statusliste im Repository.
## Unterordner
- **handouts/** — personalisierte Briefings (David, Akeshan, Dejan, Haris, Noah, Raffael)
- **intel/** — Bootstrap-Intel (Decisions/Constraints/Requirements-Extrakte; Referenz, nicht aktiv gepflegt)
## Konventionen
- `*.pdf` neben einer `*.md` = nur die gerenderte Fassung derselben Datei (zum Teilen).
- Infra-Realität: **Hetzner + Coolify + Cloudflare** (nicht Scaleway/Fly).
- Ersetzte Produktplanungen liegen nur noch in der Git-Historie. Aktive Regeln stehen in `AGENTS.md`,
Scope/DoD in der Ticket-Doc und das Datenmodell im Entity Model.
@@ -1,7 +1,7 @@
# Requirements: HiveGrid 2.0
**Defined:** 2026-06-07
**Core Value:** Jeder SHK-Betrieb (Mandant) wickelt die komplette Wertschöpfungskette — Lead → Projekt (frei konfigurierbare Pipelines) (→ KWP-Sync ab v2) — inklusive visueller Automation in einem einzigen, DSGVO-konformen EU-System ab. Wenn diese Kette nicht durchgängig funktioniert, scheitert das Produkt. *(Scope-Schnitt #12, 12.06.: KWP = erstes v2-Modul — API-Zugang des Herstellers erst ~19.07., nach v1-Launch. AD-26: kein eigenes LLM/RAG/Whisper; MCP-Server statt KI-Layer.)*
**Core Value:** Jeder SHK-Betrieb (Mandant) wickelt die komplette Wertschöpfungskette — Lead → Projekt (frei konfigurierbare Pipelines) (→ KWP-Sync ab v2) — inklusive visueller Automation in einem einzigen, DSGVO-konformen EU-System ab. Wenn diese Kette nicht durchgängig funktioniert, scheitert das Produkt. *(Scope-Schnitt #12, 12.06.: KWP = erstes v2-Modul. Stand 12.07.: Discovery, Relay-Auflösung, tenant-spezifischer OpenAPI-Vertrag und beide Redirects sind verifiziert; Runtime-Login/Testdaten und der Auftrag-Create-Vertrag fehlen noch. **Superseding 22.07., AD-32/CR-003:** Der Auth-/Resource-/Refresh-Dauerbetrieb ist bewiesen; der initiale Phase-32-Scope ist read-only KWP → HiveGrid. Writeback bleibt hinter `VEXT-6` + erneuter Freigabe geparkt. AD-26: kein eigenes LLM/RAG/Whisper; MCP-Server statt KI-Layer.)*
> ✅ **MODELL-PIVOT 2026-06-13 (AD-20) — Module 1–4 nachgezogen (R-REFIT, 16.06.):** Projekt-zentrisch (ein `Projekt`-Kern, Pipelines = Views). Umgesetzt: **REQ-crm-lead-promotion entfällt → REQ-lead-projekt-konvertierung** (Lead → Projekt bei Weiterverarbeitungsfreigabe, kein Modal, E4); **Sales (Modul 3) + Projekt (Modul 4) konsolidiert** zu „Projekt & Pipelines" mit Pipeline-Feld-Config-/Rechte-Layer (PipelineAccess/-FieldConfig/-FieldVisibility); **REQ-rechnung-sub-entity (NEU, E3)** angelegt; Kontaktmodell (Kontakttyp Privatperson/Organisation, -status, -art als Relation); Abnahme bleibt v1 als Checklisten/Protokoll-Sub-Area (E2). Single Source: `.planning/ENTITY-MODEL.md`.
@@ -22,7 +22,7 @@
### Modul 2 — Lead-Inbox
- [ ] **REQ-lead-inbox-liste**: Lead-Inbox als Arbeitsplatz mit Status-Filter, Triage-Quick-Actions, Bulk-Operationen und Real-time-Refresh.
- [ ] **REQ-lead-quellen-auto-anlage**: Automatische Lead-Anlage aus Form-Submission, eingehender E-Mail und AirCall-Inbound-Anruf mit Automation-Trigger.
- [ ] **REQ-lead-quellen-auto-anlage**: Automatische Lead-Anlage aus Form-Submission, eingehender E-Mail und Inbound-Anrufen verbundener Telefonie-Provider mit Automation-Trigger.
- [ ] **REQ-lead-status-workflow**: Status-Enum (new|qualified|converted|lost|spam) mit definierten Übergängen und DSGVO-Auto-Lösch-Cron.
- [ ] **REQ-lead-anti-spam**: Rate-Limiting und Anomalie-Detection für Lead-Quellen mit Quarantäne-Modus und Tenant-Admin-Notification.
- [ ] **REQ-lead-statistiken**: Statistiken-Page mit KPI-Kacheln, Quellen-Aufschlüsselung und Trend-Charts, Permission-aware.
@@ -75,10 +75,10 @@
- [ ] **REQ-marketing-double-optin**: Double-Opt-In-Workflow mit DSGVO-Compliance, One-Click-Unsubscribe und Suppression-List-Check vor jedem Versand.
- [ ] **REQ-marketing-versand**: BullMQ-basierter Versand mit Rate-Limiting, Bounce-Handling und SMTP-Provider-Abstraktion (Mailjet, AD-6 gelockt).
### Modul 12 — Telefonie (AirCall)
### Modul 12 — Telefonie (AirCall + HalloPetra)
- [ ] **REQ-telefonie-datenmodell**: TelephonyConnection, TelephonyUserBinding und TelephonyCallSession als Datenmodell für AirCall-Integration mit verschlüsselten OAuth-Tokens.
- [ ] **REQ-telefonie-provider-adapter**: TelephonyProviderInterface mit AirCallAdapter für Click-to-Call, Inbound-Webhook-Verarbeitung und automatische Lead-Anlage bei unbekannter Nummer.
- [ ] **REQ-telefonie-datenmodell**: TelephonyConnection, TelephonyUserBinding und TelephonyCallSession als providerneutrales Datenmodell; AirCall-OAuth-/Webhook-Token und HalloPetra-API-Key-/Webhook-Secret liegen verschlüsselt in der Apps Engine.
- [ ] **REQ-telefonie-provider-adapter**: TelephonyProviderInterface mit AirCallAdapter für Cold Calling und HalloPetra-Adapter für `post_call`-Inbound-Verarbeitung; beide nutzen E.164-Match, Logging und automatische Lead-Anlage bei unbekannter Nummer.
### Modul 13 — Team-Chat
@@ -97,12 +97,15 @@
- *(→ v2, Scope-Schnitt 2026-06-11)* **REQ-portal-datenmodell**: PortalUser, CustomerPortalSession, CustomerPortalProjectAccess und PortalConfiguration als vollständig getrennte Portal-Datenwelt.
- *(→ v2, Scope-Schnitt 2026-06-11)* **REQ-portal-auth-magic-link**: Magic-Link-Authentication für Endkunden (getrennte Auth-Welt, AD-3) mit One-Time-Token, IP-Bindung und DSGVO-Lösch-Workflow.
- *(→ v2, Scope-Schnitt 2026-06-11)* **REQ-portal-projekt-sicht**: Projekt-Sicht für Endkunden (nur explizit freigegebene Projekte), Dokument-Upload und Portal-Forms, Default-Sichtbarkeit NICHT sichtbar.
- *(→ v2-P6 / `VA-P26a`, AD-30)* **REQ-portal-runtime-isolation**: Öffentliche Portalrequests laufen über den separaten Coolify-Service/Container `hivegrid-portal`, zunächst aus demselben unveränderlichen Web-Image. Fail-closed Surface-Routing vor Static-Asset-Serving und React Router, getrennte Secrets/Sessions/Healthchecks und der dedizierte minimal berechtigte DB-Login `hivegrid_portal` verhindern App-/Admin-Routen und den breiten `hivegrid_app`-Datenzugriff aus der Portal-Runtime.
- *(→ v2-P6 / `VA-P26c`, AD-30/CR-001)* **REQ-portal-commercial-access**: Eigenständiges Portal-Entitlement mit Standardhost `portal.hivegrid.de/<tenant>`; Starter/Team 19,99 EUR netto/Monat je Workspace, Business/Enterprise inklusive, PortalUser/Projekte unbegrenzt unter den Ressourcenlimits des Basispakets. Öffentliche Buchung/Freischaltung erst nach dem vollständigen `VA-P26b`-Admin-/Interaktions-Slice.
- *(→ v2-P6 / `VA-P26c`, AD-30/CR-001)* **REQ-portal-custom-domain**: Eine optionale, global eindeutige Portal-Subdomain pro Workspace mit TXT-Ownership-Proof, CNAME auf `domains.portal.hivegrid.de`, automatischem TLS/Ingress, Host-zu-Tenant-Auflösung, 30-tägigem Reclaim-Cooldown, sicherem Lifecycle und Standardhost-Fallback; Starter/Team/Business 299,99 EUR netto je Einrichtung, Enterprise eine Domain inklusive. Ein Domainwechsel ist eine neue kostenpflichtige Einrichtung, sofern keine individuelle Enterprise-Regel greift.
### Modul 17 — Automation Engine
- [ ] **REQ-automation-datenmodell**: AutomationRule (JSON-Graph), AutomationExecution, AutomationStepExecution und AutomationTemplate als Datenmodell für den Flow-Editor.
- [ ] **REQ-automation-trigger-library**: Phase-1-Trigger-Library über alle Module (CRM, Sales, Projekte, Email, Forms, Kalender, Zeit-Trigger, Webhooks).
- [ ] **REQ-automation-action-library**: Phase-1-Action-Library über alle Module (CRM-Aktionen, Notifications, KWP-Push, HTTP-Request, Tasks, If/Else, Delay, Loop).
- [ ] **REQ-automation-action-library**: Phase-1-Action-Library über alle Module (CRM-Aktionen, Notifications, HTTP-Request, Tasks, If/Else, Delay, Loop); der bestehende KWP-Registry-Platzhalter bleibt ohne KWP-Adapter/Executor-Handler nicht ausführbar und scheitert fail-closed. Er ist keine freigegebene Writeback-Capability. `kwp.push_auftrag` oder eine andere ausführbare KWP-Action folgt erst nach `VEXT-6`, belastbarem Providervertrag und erneuter Produktfreigabe (AD-32/CR-003).
- [ ] **REQ-automation-flow-editor**: Graph-basierter visueller Flow-Editor mit manueller Flow-Erstellung, Dry-Run und 24h-Undo. KI-/Sprach-Erstellung entfällt nach AD-26.
- [ ] **REQ-automation-schutz**: Loop-Guard, Rate-Limit, Idempotenz-Key, Resume-Mode und Trigger-Volumen-Metering pro Tenant.
@@ -118,9 +121,9 @@
### Modul 19 — KWP-Integration
- *(→ v2, Scope-Schnitt 2026-06-12 — erstes v2-Modul)* **REQ-kwp-datenmodell**: KwpSettings, KwpRegistry, KwpProjectQueue, KwpApiKey und KwpSchemaSnapshot als Cloud-seitiges Datenmodell (keine KWP-DB-Credentials in Cloud).
- *(→ v2, Scope-Schnitt 2026-06-12 — erstes v2-Modul; ⚠ Recut: offizielle REST-API statt kwpsync.exe)* **REQ-kwp-architektur**: ~~Drei-Komponenten-Architektur (HiveGrid Cloud, kwpsync.exe Windows-Client, KWP MSSQL-DB)~~ → KWP als `DataConnection type='rest-api'` mit bidirektionalem Sync und Adapter-Pattern.
- *(→ v2, Scope-Schnitt 2026-06-12 — erstes v2-Modul)* **REQ-kwp-schema-drift**: Schema-Drift-Sentinel für Schema-/API-Versions-Änderungen mit regelmäßigem Snapshot, Drift-Detection und Tenant-Admin-Notification.
- *(→ v2, Scope-Schnitt 2026-06-12 — erstes v2-Modul)* **REQ-kwp-datenmodell**: Apps-Engine-Modelle `App(key='kwp', connectionType='oauth2')`, `DataConnection(credentialsCiphertext)`, `AppSyncRun`, `AppSyncRunLog` und `AppSyncItem` wiederverwenden; KWP-spezifisch im aktuellen Read-only-Scope nur `KwpApiContractSnapshot` und `KwpErrorReport`. Kundenkürzel, OAuth-Metadaten, Refresh-Token und Mandantenbindung liegen per Tenant-DEK verschlüsselt in `DataConnection.credentialsCiphertext`; der dynamische Relay-Host wird nur gecacht. `KwpProjectNumberSequence` und `KwpProjectNumberReservation` werden im aktuellen Datenmodell nicht angelegt; sie gehören zum geparkten Project-/Auftrag-Create und dürfen erst nach `VEXT-6` **und** erneuter ausdrücklicher Produktfreigabe aufgenommen werden.
- *(→ v2, Scope-Schnitt 2026-06-12 — erstes v2-Modul; ⚠ Recut: offizielle REST-API statt kwpsync.exe; AD-32/CR-003/CR-005)* **REQ-kwp-architektur**: ~~Drei-Komponenten-Architektur (HiveGrid Cloud, kwpsync.exe Windows-Client, KWP MSSQL-DB)~~ → KWP als `App(key='kwp', connectionType='oauth2')` mit tenant-spezifischer `DataConnection`, dynamisch aufgelöstem Tenant-Relay und Adapter-Pattern. Der initiale/current Scope ist fachlich read-only KWP → HiveGrid. Der Adapter inventarisiert alle 554 Tenant-OpenAPI-Operationen und erfasst die 113 Operationen der fünf HiveGrid-`*-extern`-Scopes explizit; nur die 77 semantischen Reads sind runtime-ausführbar, die 36 Mutation-Contracts bleiben vor HTTP gesperrt. M091, Project-/Auftrag-Create, `kwp.push_auftrag` sowie M094-outbound und M074-outbound bleiben verpflichtend nachgehalten, aber bis zu einem belastbaren Providervertrag aus `VEXT-6` und erneuter ausdrücklicher Produktfreigabe geparkt.
- *(→ v2, Scope-Schnitt 2026-06-12 — erstes v2-Modul)* **REQ-kwp-schema-drift**: API-Contract-Sentinel über tenant-spezifische, capability-spezifische semantische OpenAPI-Fingerprints und endpoint-spezifische Response-Schemas mit Drift-Detection und Tenant-Admin-Notification; eine Drift pausiert nur den betroffenen Bereich, freie KWP-Pfade sind verboten und es werden keine einheitlichen Versions-/Hash-Felder vorausgesetzt.
### Modul 20 — Dashboard
@@ -130,13 +133,13 @@
### Modul 21 — Audit-Log
- [ ] **REQ-audit-datenmodell**: Append-only AuditEntry mit SHA-256-Hash-Kette (Tamper-Nachweisbarkeit) und automatischer Generierung über Prisma-Middleware.
- [ ] **REQ-audit-retention-export**: Fixe Default-Retention (10 Jahre), BullMQ-Export-Jobs als NDJSON/CSV in S3-kompatibles Object Storage (Hetzner) und Cron-Auto-Löschung. *(Scope-Schnitt 12.06.: tenant-konfigurierbare Retention-Policy, Legal-Hold, Saved-Views → v2; Boilerplate liefert Retention-Cron + PDF-Export.)*
- [ ] **REQ-audit-permissions**: Audit-Zugriff permission-gegated (audit.read, audit.export) mit Plattform-Admin-View für mandantenübergreifende Einträge.
- [x] **REQ-audit-retention-export**: Fixe Default-Retention (10 Jahre), BullMQ-Export-Jobs als NDJSON/CSV in S3-kompatibles Object Storage (Hetzner) und Cron-Auto-Löschung. *(Scope-Schnitt 12.06.: tenant-konfigurierbare Retention-Policy, Legal-Hold, Saved-Views → v2; Boilerplate liefert Retention-Cron + PDF-Export.)* — AK-P3 (auf main; v1-Schnitt lt. Owner-Entscheid 24.06.: Export **synchron** mit Zweck-Pflichtfeld + signed-URL statt BullMQ-Job-Liste, `AuditExportJob` = v2; Retention-Cron nightly mit regulatorischen Mindestfristen (SOC2/HIPAA 7 J, GDPR 6 J, sonst 365 T) statt fixer 10 Jahre; Export-File-Löschung = Bucket-Lifecycle-Regel auf `audit-exports/`, Infra).
- [x] **REQ-audit-permissions**: Audit-Zugriff permission-gegated (audit.read, audit.export) mit Plattform-Admin-View für mandantenübergreifende Einträge. — AK-P3 (auf main; Owner-Entscheid 24.06.: bestehende Keys `admin.auditTrails.view`/`app.settings.auditTrails.view` als Alias für audit.read/export, kein Key-Duplikat; Admin-View `/admin/audit` mandantenübergreifend).
### Modul 22 — Notifications
- [ ] **REQ-notification-datenmodell**: Notification, NotificationPreference und NotificationDevice als Datenmodell. *(Scope-Schnitt 12.06.: NotificationBundle + NotificationQuietHours → v2 mit M117.)*
- [ ] **REQ-notification-versand-pipeline**: Drei-Kanal-Versand (In-App via SSE, Email, Web-Push via VAPID) über BullMQ mit notify()-Pflicht-Interface aus @hivegrid/notifications. *(Scope-Schnitt 12.06.: Sofort-Zustellung ohne Bündelung/Quiet-Hours; Push-Kanal Stub bis v2.)*
- [x] **REQ-notification-versand-pipeline**: Drei-Kanal-Versand (In-App via SSE, Email, Web-Push via VAPID) über BullMQ mit notify()-Pflicht-Interface aus @hivegrid/notifications. *(Scope-Schnitt 12.06.: Sofort-Zustellung ohne Bündelung/Quiet-Hours; Push-Kanal Stub bis v2.)* — Phase-3-Anteil AK-P3 (auf main; Bedien-Oberflächen: Notification-Center mit SSE/Tabs/Bulk-Clear/Deeplink/Bounce-Klartext + Settings mit Modul-Registry und Email-Master-Toggle; notify()-Kern = R-P1b/Phase 1, Push-Stub bleibt v2).
### Modul 23 — Files
@@ -145,9 +148,9 @@
### Modul 24 — Globale Suche
- [ ] **REQ-suche-datenmodell**: SearchIndexEntry, RecentSearch und Outbox-Pattern für Index-Jobs nach Entity-Mutationen. AD-26: keine Embedding-/RAG-Spalte in v1/v2; Outbox-Events bleiben für Meilisearch-Indexierung und spätere MCP-Resource-Aktualität.
- [ ] **REQ-suche-hybrid**: Keyword-Suche via Meilisearch mit permission-awarem SearchAdapter-Interface (INTEGRATION-CONTRACTS §8). AD-26: pgvector/Hybrid-RRF entfällt; v1+v2 = reine Meilisearch-Keyword-Suche.
- [ ] **REQ-suche-ui**: Cmd+K-Modal (global Hotkey, debounced) und Vollbild-Such-View mit persistierter Suche und RecentSearch-Anzeige.
- [x] **REQ-suche-datenmodell**: SearchIndexEntry, RecentSearch und Outbox-Pattern für Index-Jobs nach Entity-Mutationen. AD-26: keine Embedding-/RAG-Spalte in v1/v2; Outbox-Events bleiben für Meilisearch-Indexierung und spätere MCP-Resource-Aktualität. — **R-P11a-Kern complete** (6/6 Ticket-DoD, 2026-07-12); breiter M056-/M24-Scope bleibt separat getrackt.
- [x] **REQ-suche-hybrid**: Keyword-Suche via Meilisearch mit permission-awarem SearchAdapter-Interface (INTEGRATION-CONTRACTS §8). AD-26: pgvector/Hybrid-RRF entfällt; v1+v2 = reine Meilisearch-Keyword-Suche. — **R-P11a-Kern complete** (6/6 Ticket-DoD, 2026-07-12); vollständiger M057-Milestone-Proof bleibt separat offen.
- [x] **REQ-suche-ui**: Globale Spotlight-Suche mit RecentSearch-Anzeige: Desktop per Cmd+K/Ctrl+K oder Header-Suchsymbol als debounced Modal, Mobile per Header-Suchsymbol als viewportfüllendes Overlay. Keine nutzerseitige `/search`-Seite; `/search/api` bleibt geschützter interner Resource-Endpunkt. *(Scope-Schnitt 2026-07-12.)* — R-P11a-Kern complete (AD-28-Interim-UI, 6/6 Ticket-DoD); finales `D-DASH`-Delta bleibt Design-Nachzug.
### Modul 25 — Calendar-Sync
@@ -163,28 +166,30 @@
- [ ] **REQ-auth-multi-tenancy**: Self-Service-Signup mit auto-generiertem Tenant-Slug, Reserved-Words-Validierung und URL-Struktur (app.hivegrid.de, admin.hivegrid.de).
- [ ] **REQ-auth-methoden**: Email+Passwort (NIST-konform, Breach-Check), TOTP-2FA (RFC 6238) und Magic-Link exklusiv für Customer-Portal (AD-3).
- [ ] **REQ-auth-rbac**: Rollen-basiertes Permission-System (Role ↔ User M:N) mit Permission-Keys in packages/entitlements und 6 SHK-Standard-Rollen geseedet *(Seed nur Staging/Dev — Produktion startet admin-only, AD-29)*.
- [ ] **REQ-auth-rbac**: Rollen-basiertes Permission-System (Role ↔ User M:N) mit Permission-Keys in packages/entitlements. Jeder neue Workspace erhält fünf editierbare SHK-Tenant-Rollen; der Owner erhält ausschließlich die globale Rolle `Admin` (AD-29). Bestehende Tenants werden nicht automatisch verändert.
- [ ] **REQ-auth-user-lifecycle**: User-Einladung (48h-Token), Soft-Deactivation und DSGVO-Löschung via PII-Anonymisierung ohne Audit-Trail-Verlust.
- *(→ v2, Scope-Schnitt 2026-06-12)* **REQ-auth-api-keys**: API-Key-System mit SHA-256-Hash-Speicherung, fein-granularen Scopes und Rate-Limit (1000 Req/Min Default). *(Wandert mit der Public-API; Boilerplate-`ApiKey`-Modell bleibt ungenutzt im Code.)*
### Modul 28 — Subscriptions/Billing
- [ ] **REQ-billing-datenmodell**: TenantSubscription mit Lago/Mollie-Recut nach AD-27: Lago als Billing-/Invoice-Engine, Mollie nur als Payment-Processor, lokaler HiveGrid-Billing-State fuer Entitlements und Frozen-Modus (Read-Only-Middleware). Kein v1-Usage-Billing, keine Credits; AI-Credits/AiTokenUsage entfallen nach AD-26.
- [ ] **REQ-billing-trial-dunning**: 14-Tage-Trial ohne Kreditkarte, Dunning-Email-Sequenz (Tag 1/3/7) bei fehlgeschlagener Zahlung und anschließender Frozen-Modus.
- [x] **REQ-billing-datenmodell**: TenantSubscription mit Lago/Mollie-Recut nach AD-27: Lago als Billing-/Invoice-Engine, Mollie nur als Payment-Processor, lokaler HiveGrid-Billing-State fuer Entitlements und Frozen-Modus (Read-Only-Middleware). Kein v1-Usage-Billing, keine Credits; AI-Credits/AiTokenUsage entfallen nach AD-26. *Proof: `BILL-02` bis `BILL-05`, AK-P20 Interim-UI/VMs; Ready-to-Verify 2026-07-12.*
- [x] **REQ-billing-trial-dunning**: 14-Tage-Trial ohne Kreditkarte, Dunning-Email-Sequenz (Tag 1/3/7) bei fehlgeschlagener Zahlung und anschließender Frozen-Modus. *Proof: AK-P20 Billing-Status-/Read-only-Gates und Shell-Banner; Ready-to-Verify 2026-07-12.*
### Modul 29 — Onboarding
- *(→ v2, Scope-Schnitt 2026-06-11)* **REQ-onboarding-wizard**: Branchen-getriebener Onboarding-Wizard nach Self-Service-Signup mit SHK-Template-Vorauswahl und OnboardingSession.
- [ ] **REQ-onboarding-demo-daten**: Demo-Daten-Provisioning auf Wunsch (Kontakte, Projekte in Sales-/Auftragssichten, Tasks) mit Lösch-Funktion via is_demo_data-Flag. *(Scope-Schnitt 12.06. + AD-26: KI-Walkthrough entfällt; Settings-Knopf statt Wizard-Schritt, einfaches Löschen.)*
- [x] **REQ-onboarding-demo-daten**: Demo-Daten-Provisioning auf Wunsch (Kontakte, Projekte in Sales-/Auftragssichten, Tasks) mit Lösch-Funktion via is_demo_data-Flag. *(Scope-Schnitt 12.06. + AD-26: KI-Walkthrough entfällt; Settings-Knopf statt Wizard-Schritt, einfaches Löschen. Proof: AK-P20 Demo-Settings-Interim-Screen und Environment-Gate; Ready-to-Verify 2026-07-12.)*
### Modul 30 — i18n
- [ ] **REQ-i18n-architektur**: Locale-File-Struktur in packages/i18n, Language-Resolution (User → Tenant → DE), Build-Lint für Hard-Strings und ICU-Pluralisierung.
- [ ] **REQ-i18n-outbound**: Contact.language steuert Sprache der automatischen Outbound-Kommunikation; Notification-Templates in DE. *(Scope-Schnitt 12.06.: v1 DE-only — EN-Templates + Sprach-Wechsler → v2; i18n-Pflicht-Wiring + `verify:i18n`-Gate bleiben unantastbar, alles i18n-ready.)*
- [ ] **REQ-i18n-architektur**: Statische Kataloge für `de`, `en`, `pl`, `ru`, `uk` und `hu` mit je neun Namespaces und vollständiger formeller Anredevariante; produktive Aktivierung separat über `I18N_ENABLED_LOCALES` (Default `de,en`). Language-Resolution: aktivierte User-Präferenz → aktivierter Tenant-Default → aktiviertes `Accept-Language` → DE. Build-Gates prüfen Hard-Strings, Key-/Token-Parität, ICU-/CLDR-Pluralisierung, Unicode und unerlaubte Sprach-Fallbacks. *(CR-020, Umsetzung `I18N-01`; keine Runtime-Übersetzung.)*
- [x] **REQ-i18n-outbound**: Contact.language steuert Sprache der automatischen Outbound-Kommunikation; Notification-Templates in DE. *(Scope-Schnitt 12.06.: v1 DE-only — EN-Templates + Sprach-Wechsler → v2; i18n-Pflicht-Wiring + `verify:i18n`-Gate bleiben unantastbar, alles i18n-ready.)* — AK-P3 (auf main; v1 DE-only: Sprach-Settings-Hinweis + vollständige de-Locale, `Kontakt.language` als nullable Feld angelegt (kein v1-Editor); Auswertung für Outbound-Sprachwahl folgt mit den EN-Templates in v2).
- [ ] **REQ-i18n-six-locale-outbound**: Customer-Portal, transaktionale React-E-Mails, Worker-Zuordnung und inline erzeugte Systemmails verwenden dieselbe aktivierte Empfängersprache aus `de/en/pl/ru/uk/hu`; deaktivierte oder unbekannte Präferenzen fallen kontrolliert auf DE zurück. Eigene Portal-Mailvorlagen und andere nutzergenerierte Inhalte werden nicht automatisch übersetzt. *(CR-020, `I18N-01`.)*
- [ ] **REQ-systemmail-brand-ux**: Alle fest von HiveGrid formulierten Systemmails laufen durch einen gemeinsamen responsiven Markenrahmen mit öffentlichem HiveGrid-Logo, klarer Informationshierarchie, konkretem CTA, lokalisiertem HTML und Plaintext, Supportkontakt sowie unveränderlichen Plattformlinks für AGB, Datenschutz und Impressum. Rohe Runtime-HTML-/Textpfade sind nicht zulässig; nutzergenerierte Kampagnen-, Workflow- und Portaltexte bleiben außerhalb dieses Vertrags. *(CR-022, `MAIL-03`.)*
### Modul 31 — Branding
- [ ] **REQ-branding-theme-phase1**: User-Level Theme-Preference (Hell/Dunkel) mit SSR-kompatibler Cookie-Implementierung ohne Theme-Flash. *(Scope-Schnitt 12.06.: kein System-Modus — bewusst nur 2 Optionen; `next-themes` aus Boilerplate.)*
- [x] *(vorerst deaktiviert, 2026-07-11)* **REQ-branding-theme-phase1**: Der vorhandene User-Level-Theme-Unterbau bleibt bestehen; der Light/Dark-Toggle und die Dark-Anwendung im App-/Admin-Bereich sind bis zu einer produktiven Freigabe via `DARK_MODE_IN_APP=false` ausgeschaltet (PR #81). *Ready-to-Verify mit AK-P20; kein neuer Dark-Mode-Scope.*
### Modul 32 — Feature-Flags
@@ -193,7 +198,7 @@
### Modul 33a — Apps-Engine
- [ ] **REQ-apps-engine-datenmodell**: DataConnection, AppSyncRun, AppSyncItem und type-safe Adapter-Registry als zentrales Integrations-Framework.
- [ ] **REQ-apps-engine-lifecycle**: OAuth2-Connect-Flow (Gmail, Outlook, AirCall, PandaDoc), API-Key-Connect (KWP, Payment-Provider-APIs), Connection-Health-Monitoring und Settings-UI.
- [ ] **REQ-apps-engine-lifecycle**: OAuth2-Connect-Flow (Gmail, Outlook, AirCall, PandaDoc, KWP), API-Key-Connect (u. a. HalloPetra und Payment-Provider-APIs), Connection-Health-Monitoring und Settings-UI.
### Modul 34 — Public API & Webhooks
@@ -202,7 +207,7 @@
### Modul 35 — DSGVO-Export / Account-Löschung
- [ ] **REQ-dsgvo-export**: GDPR-Daten-Export als ZIP via BullMQ-Worker mit 72h-signed-Download-URL (S3-kompatibles Object Storage, Hetzner) und Download-Link-Email.
- [ ] **REQ-dsgvo-export**: GDPR-Daten-Export als SSE-C-verschlüsseltes ZIP via BullMQ-Worker (S3-kompatibles Object Storage, Hetzner), bis zu 72 h verfügbar und ausschließlich als authentifiziertes `200`-Attachment über die App; direkter Zugriff ohne Customer-Key scheitert, Ready-E-Mail verlinkt nur die App-Route.
- [ ] **REQ-dsgvo-tenant-deletion**: Tenant-Account-Löschung mit Crypto-Shredding (Per-Tenant-DEK löschen), Lago-Subscription-Cancel/Mollie-Zahlungsreferenz-Bereinigung und vollständiger Storage/Cache-Bereinigung.
### Modul 36 — Mobile-PWA (PWA-only, kein nativer Client)
@@ -227,7 +232,7 @@
### Querschnitt — Integration-Contracts
- [ ] **REQ-integration-sidebar**: Alle neuen Modul-Bereiche müssen in der Sidebar-Konfiguration registriert sein (Registrierung in apps/web/app/application/sidebar/).
- [ ] **REQ-integration-routes**: Verbindliche URL-Schemata für Mandanten-App, Plattform-Admin, Customer-Portal, Public-Forms, Booking, Help und API (INTEGRATION-CONTRACTS §3).
- [ ] **REQ-integration-routes**: Verbindliche URL-Schemata für Mandanten-App, Plattform-Admin, Customer-Portal (`portal.hivegrid.de/<tenant>` plus verifizierte Custom-Hosts), Public-Forms, Booking, Help und API (INTEGRATION-CONTRACTS §3).
- [ ] **REQ-integration-activity-wiring**: Jede schreibende Aktion mit Entitäts-Bezug muss logActivity() aus @hivegrid/activity aufrufen.
- [ ] **REQ-integration-audit-wiring**: Audit läuft automatisch über Prisma-Middleware (M21); Ausnahmen (S3-Upload, externe Webhooks) manuell über auditEvent() aus @hivegrid/audit.
- [ ] **REQ-integration-notification-wiring**: Benachrichtigungen immer über notify() aus @hivegrid/notifications, kein direkter Kanal-Zugriff in Modul-Code.
@@ -238,9 +243,9 @@
**Definition (verbindlich):** v2 = alles, was gemacht werden MUSS — nur sequenziert nach dem v1-Launch. Kein Vielleicht-Backlog.
**Scope-Schnitt 2026-06-11 (15 REQs aus v1 verschoben — Definitionen oben mit *(→ v2)* markiert, Historie in `SCOPE-V1-CUTS.md`):**
**Scope-Schnitt 2026-06-11 (15 REQs aus v1 verschoben — Definitionen oben mit *(→ v2)* markiert):**
- **Mobile (PWA-Ausbau, AD-17):** REQ-mobile-pwa, REQ-mobile-offline-sync, REQ-mobile-push — v1 = mobile-first responsive Web / PWA; v2 = installierbare PWA-Vertiefung (Expo/Capacitor verworfen — PWA-only; nativer Client + App-Store → v3)
- **Customer-Portal:** REQ-portal-datenmodell, REQ-portal-auth-magic-link, REQ-portal-projekt-sicht
- **Customer-Portal:** REQ-portal-datenmodell, REQ-portal-auth-magic-link, REQ-portal-projekt-sicht, REQ-portal-runtime-isolation, REQ-portal-commercial-access, REQ-portal-custom-domain
- ~~**KI-Kür:** REQ-ki-hivemind, REQ-ki-rag-embeddings, REQ-ki-whisper — v1 baut Andock-Adapter~~ → **KI→MCP-Pivot ([[AD-26]]): zurückgestellt (v3-Kandidat); v2 liefert stattdessen `REQ-mcp-server` (MCP-Server, siehe [[VR-MCP]]/[[VD-MCP]]). Kein eigenes LLM/RAG/Whisper.**
- **Postfach-Sync:** REQ-email-sync-strategie, REQ-email-inbox-view — Sende-Domain + BCC-Brücke bleiben v1
- **Public-API:** REQ-public-api-read, REQ-public-webhooks
@@ -248,8 +253,8 @@
- **Onboarding:** REQ-onboarding-wizard — v1 = Auto-SHK-Provisionierung ohne Wizard-UI
**Scope-Schnitt 2026-06-12 #12 (Abschluss-Runde, 3 REQs verschoben + 4 Dünnungen):**
- **KWP-Integration (ERSTES v2-Modul):** REQ-kwp-datenmodell, REQ-kwp-architektur (⚠ Recut: REST-API statt kwpsync.exe), REQ-kwp-schema-drift — Kalender-Realität: Hersteller-API-Zugang ~19.07. > v1-Launch ~10.07.; Callback-URL gemeldet, Andockpunkte in v1
- **Dünnungs-Notes (REQ bleibt v1):** Theme nur Hell/Dunkel (kein System-Modus) · Demo-Daten ohne KI-Walkthrough · Forms ohne personalisierte Links/JS-Snippet · Material-Listen ohne Lagerist-Sicht
- **KWP-Integration (ERSTES v2-Modul):** REQ-kwp-datenmodell, REQ-kwp-architektur (⚠ Recut: REST/OAuth2 statt kwpsync.exe), REQ-kwp-schema-drift — Auth-/Resource-/Refresh-Dauerbetrieb ist bewiesen; initialer Phase-32-Scope read-only. Writeback ist kein Blocker dieses Scopes und bleibt nach AD-32/CR-003 hinter `VEXT-6` + erneuter Freigabe geparkt; Andockpunkte bleiben erhalten.
- **Dünnungs-Notes (REQ bleibt v1):** Theme-Unterbau bleibt, Toggle vorerst deaktiviert (PR #81; nur Hell/Dunkel, kein System-Modus) · Demo-Daten ohne KI-Walkthrough · Forms ohne personalisierte Links/JS-Snippet · Material-Listen ohne Lagerist-Sicht
**Scope-Schnitt 2026-06-12 (Boilerplate-Recheck, 1 REQ verschoben + Dünnungs-Notes an 9 REQs):**
- **Public-API-Paket:** REQ-auth-api-keys — wandert mit REQ-public-api-read/-webhooks; Boilerplate-`ApiKey`-Modell bleibt im Code
@@ -258,7 +263,7 @@
Bereits zuvor v2 (in Phase-1-Specs referenziert, nicht vollständig spezifiziert):
- **M11 WhatsApp**: Von M13 (Team-Chat) referenziert; vollständige Spec und Implementierung verschoben auf spätere Phase.
- **REQ-branding-tenant-phase2**: Tenant-Branding, White-Label und Custom-Domain (TenantBranding: logo, Farben, Custom-Domain) — Feature-Gate branding.white_label nur in Enterprise-Plan; verschoben auf Phase 2.
- **REQ-branding-tenant-phase2**: Vollständiges App-White-Label (eigene App-Domain, Fonts, vollständiges Theme, freie HTML-Mailtemplates, HiveGrid-Branding entfernen) bleibt Phase 2 und Enterprise-only. **Abgrenzung AD-30:** Die einzelne Customer-Portal-Domain ist ein separates P26-Entitlement und wird in `VA-P26c` umgesetzt.
- **REQ-signatur-provider Fallback**: Einfacher PDF-Upload mit manueller Signatur-Erfassung bleibt Fallback; Standard ist self-hosted SES (AD-25), externe Provider nur BYOK/Opt-in.
- **DeepL-Übersetzungs-Pipeline (M30)**: Automatische Übersetzungsvorschläge via DeepL für Locale-Files — Phase 2.
- **KI/HiveMind/RAG/Whisper**: kein v1/v2-Scope nach AD-26; v2 liefert stattdessen `REQ-mcp-server`.
@@ -269,11 +274,12 @@ Explizit ausgeschlossen. Dokumentiert zur Vermeidung von Scope-Creep.
| Feature | Reason |
|---------|--------|
| Konkrete Pricing-Stufen | Billing-Engine wird gebaut, Preise geparkt (AD-15); Geerkens auf Sonderkondition/Trial |
| Konkrete Pricing-Stufen | Grundsätzlich weiter geparkt (AD-15). Ausnahme: Customer-Portal/Custom-Domain gemäß AD-30/CR-001; Business enthält das Portal, bezahlt die Domain einmalig. |
| Volle Migrations-Pipelines pro Altsystem | Sauberer Start; KWP-Sync füllt nach; HubSpot/Quiply als Read-only-Archiv, nur punktuelle CSV-Importe (AD-14) |
| KWP-Writeback im initialen Phase-32-Scope | Keine fachlichen KWP-Mutationen. M091, M094-outbound, M074-outbound, `kwp.push_auftrag` und Project-/Auftrag-Create bleiben bis `VEXT-6` + erneuter Freigabe geparkt (AD-32/CR-003). |
| ~~EU-Email-Provider-Wahl (AD-6)~~ | ✅ **GELOCKT 2026-06-11: Mailjet** (Boilerplate-verdrahtet, `MAILJET_*`) — kein offener Punkt mehr |
| ~~Captcha/Bot-Schutz (AD-7)~~ | ✅ **GELOCKT 2026-06-11: mCaptcha self-hosted** (`infra/mcaptcha/` fertig vorbereitet) — kein offener Punkt mehr |
| KWP Windows-Sync-Programm M089 (alte M19-Variante) | Entfällt durch offizielle KWP-API; M089–M095 vor Umsetzung neu schneiden; KWP wird als DataConnection type='rest-api' in M33a abgebildet |
| KWP Windows-Sync-Programm M089 (alte M19-Variante) | Entfällt durch offizielle KWP-API; KWP wird als `App(key='kwp', connectionType='oauth2')` mit tenant-spezifischer `DataConnection` und dynamischem Tenant-Relay in M33a abgebildet; bindender Vertrag: `.planning/KWP-API-CONTRACT.md` |
## Traceability
@@ -293,12 +299,12 @@ Phase-Mapping aus ROADMAP.md (Stufe 2, revidiert auf 21 Phasen). Bau-Reihenfolge
| REQ-auth-rbac | Phase 2 | Pending |
| REQ-auth-user-lifecycle | Phase 2 | Pending |
| REQ-audit-datenmodell | Phase 1 | Pending |
| REQ-audit-retention-export | Phase 3 | Pending |
| REQ-audit-permissions | Phase 3 | Pending |
| REQ-audit-retention-export | Phase 3 | Done |
| REQ-audit-permissions | Phase 3 | Done |
| REQ-notification-datenmodell | Phase 1 | Pending |
| REQ-notification-versand-pipeline | Phase 3 | Pending |
| REQ-notification-versand-pipeline | Phase 3 | Done |
| REQ-i18n-architektur | Phase 1 | Pending |
| REQ-i18n-outbound | Phase 3 | Pending |
| REQ-i18n-outbound | Phase 3 | Done |
| REQ-feature-flags-system | Phase 1 | Pending |
| REQ-files-datenmodell | Phase 4 | Pending |
| REQ-files-upload-preview | Phase 4 | Pending |
@@ -329,9 +335,9 @@ Phase-Mapping aus ROADMAP.md (Stufe 2, revidiert auf 21 Phasen). Bau-Reihenfolge
| REQ-projekt-sub-areas | Phase 9 | Pending |
| REQ-rechnung-sub-entity | Phase 9 | Pending |
| REQ-projekt-abnahme | Phase 9 | Pending |
| REQ-suche-datenmodell | Phase 11 | Pending |
| REQ-suche-hybrid | Phase 11 | Pending |
| REQ-suche-ui | Phase 11 | Pending |
| REQ-suche-datenmodell | Phase 11 | R-P11a core complete; M056 follow-up open |
| REQ-suche-hybrid | Phase 11 | R-P11a core complete; M057 proof open |
| REQ-suche-ui | Phase 11 | R-P11a core complete (AD-28); design follow-up open |
| REQ-dashboard-datenmodell | Phase 11 | Pending |
| REQ-dashboard-widgets | Phase 11 | Pending |
| REQ-automation-datenmodell | Phase 12 | Pending |
@@ -365,10 +371,10 @@ Phase-Mapping aus ROADMAP.md (Stufe 2, revidiert auf 21 Phasen). Bau-Reihenfolge
| REQ-hr-urlaub-krank | Phase 17 | Pending |
| REQ-plattform-admin-identität | Phase 19 | Pending |
| REQ-plattform-admin-features | Phase 19 | Pending |
| REQ-billing-datenmodell | Phase 20 | Pending |
| REQ-billing-trial-dunning | Phase 20 | Pending |
| REQ-onboarding-demo-daten | Phase 20 | Pending |
| REQ-branding-theme-phase1 | Phase 20 | Pending |
| REQ-billing-datenmodell | Phase 20 | Ready-to-Verify (AK-P20 8/8) |
| REQ-billing-trial-dunning | Phase 20 | Ready-to-Verify (AK-P20 8/8) |
| REQ-onboarding-demo-daten | Phase 20 | Ready-to-Verify (AK-P20 8/8) |
| REQ-branding-theme-phase1 | Phase 20 | Ready-to-Verify (AK-P20 8/8); Toggle deaktiviert |
| REQ-dsgvo-export | Phase 21 | Pending |
| REQ-dsgvo-tenant-deletion | Phase 21 | Pending |
| REQ-feedback-widget | Phase 21 | Pending |
@@ -407,4 +413,4 @@ Phase-Mapping aus ROADMAP.md (Stufe 2, revidiert auf 21 Phasen). Bau-Reihenfolge
| **Summe** | **89 v1 + 1 v2-MCP** |
---
*Requirements definiert: 2026-06-07 via /gsd:ingest-docs (Stufe 1). Phase-Mapping ergänzt: 2026-06-07 via /gsd:new-project (Stufe 2 — ROADMAP). Re-Mapping auf 21 Phasen: 2026-06-07 (Roadmap-Revision — dicke Buckets aufgeteilt). Scope-Schnitte 2026-06-11/12 (#1–#12): 19 REQs → v2, Dünnungs-Notes an 13 REQs, AD-6/7-Lock nachgetragen. **R-REFIT 2026-06-16 (Pivot AD-20): Module 1–4 projekt-zentrisch nachgezogen; REQ-crm-lead-promotion → REQ-lead-projekt-konvertierung; Sales/Projekt-Reqs zu „Projekt & Pipelines" konsolidiert (REQ-projekt-kern-datenmodell, REQ-pipeline-rechte-config u.a.); REQ-rechnung-sub-entity NEU. AD-26: v1-KI-Layer entfernt, `REQ-mcp-server` als v2-P4 aufgenommen.** *
*Requirements definiert: 2026-06-07. Re-Mapping auf 21 Phasen: 2026-06-07. Scope-Schnitte 2026-06-11/12 (#1–#12): 19 REQs → v2, Dünnungs-Notes an 13 REQs, AD-6/7-Lock nachgetragen. **R-REFIT 2026-06-16 (Pivot AD-20): Module 1–4 projekt-zentrisch nachgezogen; REQ-crm-lead-promotion → REQ-lead-projekt-konvertierung; Sales/Projekt-Reqs zu „Projekt & Pipelines" konsolidiert (REQ-projekt-kern-datenmodell, REQ-pipeline-rechte-config u.a.); REQ-rechnung-sub-entity NEU. AD-26: v1-KI-Layer entfernt, `REQ-mcp-server` als v2-P4 aufgenommen.** *
@@ -1,12 +1,12 @@
# Roadmap: HiveGrid 2.0 — v2 (Mo 13.07. – Fr 31.07.2026)
# Roadmap: HiveGrid 2.0 — v2 (Start 13.07.2026 · Carry-over offen)
> **Status:** Entwurf 2026-06-15 (aus Modul-Specs destilliert). Ergänzt die v1-ROADMAP (Phasen 1–21). v2 = 43 committed-deferred Milestones, nach v1-Launch (10.07.) sequenziert — kein Vielleicht-Backlog.
> **Status:** Entwurf 2026-06-15, inzwischen ticket-getrieben fortgeführt. Ergänzt die v1-ROADMAP (Phasen 1–21). v2 = 43 committed-deferred Scope-Bausteine, nach v1-Launch (10.07.) sequenziert — kein Vielleicht-Backlog.
## Overview
v2 bringt die eigentlichen USP-/Revenue-Hebel, die in v1 bewusst geschnitten wurden: **KWP-Sync** (das Haupt-Verkaufsargument), **Self-Service-Abo**, **Postfach-Sync**, **Customer-Portal**, **Mobile-PWA-Ausbau**, **MCP-Server** und **Public-API**. v1 hat die tragfähige Kette + alle **Andockpunkte** geliefert; v2 dockt rückwirkend an (Dependency-Inversion bleibt das Prinzip).
**Bau-Strategie:** Wie v1 zwei dependency-frei parallele Tracks (Raffael + Akeshan), Designer (David) 1–2 Phasen voraus. v2-Sprint in 3 Wochen: **v2-W1** 13.–19.07. · **v2-W2** 20.–26.07. · **v2-W3** 27.–31.07.
**Bau-Strategie:** Wie v1 zwei dependency-frei parallele Tracks (Raffael + Akeshan), Designer (David) 1–2 Phasen voraus. Ursprüngliches Drei-Wochen-Fenster: **v2-W1** 13.–19.07. · **v2-W2** 20.–26.07. · **v2-W3** 27.–31.07. Retimierte Arbeit wird als v2-Carry-over geführt; insbesondere läuft `VA-P26a` bis 05.08., `VA-P26b` frühestens danach und `VA-P26c` bleibt bis zur finalen Slice-Planung undatiert.
**Die kritische geteilte Vorbedingung:** Das **M33a-Apps-Engine-Adapter-Interface** (v1-P5, M008–M010) trägt KWP (v2-P5), die HR-Drittanbieter (v2-P10) und das Provider-Pattern für Postfach/Telefonie. Wenn das in v1 sauber steht, docken die v2-Integrationen ohne Kern-Umbau an.
@@ -15,7 +15,7 @@ v2 bringt die eigentlichen USP-/Revenue-Hebel, die in v1 bewusst geschnitten wur
- **Memberspot/Boobora (M138):** kommt in **keiner Spec** vor. M14 nennt nur generische „HR-Onboarding + externe Systeme via Apps-Engine". → eigene Drittanbieter-Spec nötig.
### Wiederkehrendes Risiko: „Partner-API-Vertrag offen"
**KWP (P5), HalloPetra (P11), HR-Drittanbieter (P10)** hängen alle am selben Muster — externer Adapter über M33a — und sind alle durch einen noch ausstehenden Partner-API-Vertrag blockiert. KWP-Zugang ~20.07. ist der härteste Kalender-Anker.
**HalloPetra (P11) und HR-Drittanbieter (P10)** hängen wie KWP am Muster „externer Adapter über M33a" und warten noch auf ihren Partnervertrag. Für **KWP (P5)** sind Discovery, dynamische Relay-Auflösung, tenant-spezifischer OpenAPI-Vertrag sowie Auth-/Resource-/Refresh-Dauerbetrieb verifiziert. Der initiale Phase-32-Scope ist nach AD-32/CR-003 read-only und nicht mehr durch Project-Create blockiert. Ausschließlich Writeback bleibt hinter `VEXT-6`, belastbarem Providervertrag und erneuter Freigabe geparkt.
### Hinweis: „phase:1"-Specs nur teilweise v2
M15 (Portal), M37/M32 (Admin), M38/M39 (Help), M20/M22/M30 (Querschnitt) sind in den Specs als `phase:1` markiert. **Das Fundament gehört laut Spec in v1** (großteils erledigt/gedünnt) — nur das **Komfort-/Tiefen-Delta** ist echtes v2. Die Phasen unten beschreiben das Delta.
@@ -31,14 +31,14 @@ M15 (Portal), M37/M32 (Admin), M38/M39 (Help), M20/M22/M30 (Querschnitt) sind in
| v2-P3 | Self-Service-Billing & Onboarding-Wizard | M157 (+M28-SB-Delta) | Akeshan | W1→W2 | yes |
| v2-P4 | **MCP-Server** *(ex „KI-Tiefe — HiveMind/RAG", [[AD-26]])* | [[VR-MCP]]/[[VD-MCP]] (kein M0xx) | Raffael | W1→W2 | yes |
| v2-P5 | KWP-Integration *(ex-P10, RECUT)* | M089-095, M074 | Raffael | W2 | yes |
| v2-P6 | Customer-Portal *(ex-P18)* | M141-146 | Akeshan | W2 | yes |
| v2-P6 | Customer-Portal *(ex-P18)* | M141-146 | Akeshan | W1→Carry-over | yes |
| v2-P7 | Mobile-PWA-Ausbau | M167-171 | Akeshan | W2→W3 | yes |
| v2-P8 | Plattform-Admin-Tiefe | M038/039/033/040 | Raffael+Akeshan | W3 | yes |
| v2-P9 | Help-Center & Help-Desk | M172-175 | Akeshan | W3 | yes |
| v2-P10 | Komfort & Querschnitt | M149/150/117/029/138 | Akeshan | W3 | yes |
| v2-P11 | Telefonie-Erweiterung & DSGVO-Vollausbau | M105, M166 | Raffael | W3 | yes |
**Execution-Order:** v2-P1/P2 (W1) → v2-P3/P4 (W1→W2) → v2-P5/P6 (W2) → v2-P7 (W2→W3) → v2-P8/P9/P10/P11 (W3). Tracks parallel: Raffael P1→P4→P5→P8→P11 · Akeshan P2→P3→P6→P7→P9→P10.
**Execution-Order:** v2-P1/P2 (W1) → v2-P3/P4 (W1→W2) → v2-P5 (W2) → v2-P7 (W2→W3) → v2-P8/P9/P10/P11 (W3). P6 beginnt mit `VA-P26a` in W1 und läuft retimiert in den Carry-over; `VA-P26b`/`VA-P26c` folgen nach den Gates. Tracks parallel: Raffael P1→P4→P5→P8→P11 · Akeshan P2→P3→P6 sowie die übrigen disjunkten P7/P9/P10-Slices.
### Nummern-Mapping: v2-Px ↔ ROADMAP-Phase 22–34 ↔ ex-Pn (C-2)
@@ -65,7 +65,6 @@ M15 (Portal), M37/M32 (Admin), M38/M39 (Help), M20/M22/M30 (Querschnitt) sind in
### v2-P1: Public-API & Webhooks
**Owner:** Raffael · **Slot:** W1 (13.–17.07.) · **Goal:** Externe Systeme lesen HiveGrid-Hauptentitäten per versionierter REST-API und empfangen/senden Events über signierte Webhooks.
**Milestones:** M161 (OpenAPI + Read-Endpoints), M162 (API-Key-Auth + Scopes + Rate-Limit), M163 (Webhooks signiert), M027 (API-Keys + Tarif-Gates)
**Source-Specs:** `_bmad-output/specs/M34-public-api.md`
**Depends on:** v1-`ApiKey`-Modell (M027-Vorbereitung lag in v1 ungenutzt bereit) · Redis (Token-Bucket) · v1-Frozen/past_due-Middleware (Writes 402) · RLS via `app.tenant_id` · v1-P12 Automation (`external_event`-Trigger + ausgehende Webhook-Action)
**Host-Contract:** Public API nur `https://api.hivegrid.de/v1/...` (staging: `https://staging-api.hivegrid.de/v1/...`);
keine Public-API-Routen unter `app.hivegrid.de/api`.
@@ -80,7 +79,6 @@ keine Public-API-Routen unter `app.hivegrid.de/api`.
### v2-P2: Postfach-Sync (Email-Inbox)
**Owner:** Akeshan · **Slot:** W1 (13.–17.07.) · **Goal:** Gmail/Outlook-Postfächer werden bidirektional ins CRM gespiegelt, auto-gematcht und im Activity-Stream sichtbar.
**Milestones:** M096 (Gmail-OAuth via Apps-Engine), M097 (Sync + Inbox-UI + Threading + Auto-Verknüpfung), M098 (Versand + Vorlagen)
**Source-Specs:** `_bmad-output/specs/M09-email-inbox.md` (OAuth-Sync/Inbox/Threading-Teile)
**Depends on:** v1-Sende-Domain DKIM/SPF/DMARC (P14, NICHT neu bauen) · `EmailProviderInterface` (Apps-Engine-Pattern) · v1-Activity-Stream + Contact/Project-FKs (Matching) · Webhook-Ingest-Infra (geteilt mit P1) · v1-Files (Anhänge) · Token-Encryption (DEK)
**Success Criteria:**
1. OAuth-Connect Gmail (Pub/Sub-Watch) + Microsoft (Graph-Subscription, 3-Tage-Renewal-Worker); Token-Refresh + Revoke.
@@ -92,13 +90,12 @@ keine Public-API-Routen unter `app.hivegrid.de/api`.
**Recut/Risiko:** ⚠️ **Gmail restricted scopes** (`gmail.modify/send`) → Google-Verifizierung + ggf. CASA-Assessment (Wochen Vorlauf, Antrag lief in v1 EXT-13). **Microsoft-Graph-Subscription** läuft ~3 Tage → Renewal-Worker kritisch. Versand über User-Mailbox (Provider-Quotas).
### v2-P3: Self-Service-Billing & Onboarding-Wizard
**Owner:** Akeshan · **Slot:** W1→W2 (Abo-UI 13.–17., Wizard 18./19.) · **Goal:** Tenants buchen/wechseln Pläne self-service über Web-Checkout und durchlaufen einen branchen-getriebenen Onboarding-Wizard.
**Owner:** Akeshan · **Slot:** W1→W2 (Abo-UI 13.–17., Wizard 18./19.) · **Goal:** Tenants buchen/wechseln Pläne und pauschale Add-ons self-service über Web-Checkout und durchlaufen einen branchen-getriebenen Onboarding-Wizard.
**Milestones:** M157 (Wizard-Framework + State-Machine) + M28-Self-Service-Delta (In-App-Subscription, Block P)
**Source-Specs:** `_bmad-output/specs/M28-subscriptions-billing.md` (Block P), `M29-onboarding.md`
**Depends on:** v1-Payment-Checkout + Webhook-Handler + Legacy-ProviderWebhookLog · v1-`SubscriptionFeature`/`ProductFeature` (Feature-Gate-Modell) · v1-Read-Only-Middleware · v1-TenantUserInvitation · **deklaratives Branchen-Template-Verzeichnis** (geteilt mit P6/P10) · ~~v2-P4 (KI-Walkthrough-Coach)~~ → KI-Coach entfällt ([[AD-26]]: kein eigenes LLM; v2-P4 = MCP-Server)
**Depends on:** v1-HiveGrid-Entitlements + Lago-Billing-Gateway + Mollie-Payment-/Webhook-Vertrag (`BILL-02` bis `BILL-10`) · v1-Read-Only-Middleware · v1-TenantUserInvitation · **deklaratives Branchen-Template-Verzeichnis** (geteilt mit P6/P10) · ~~v2-P4 (KI-Walkthrough-Coach)~~ → KI-Coach entfällt ([[AD-26]]: kein eigenes LLM; v2-P4 = MCP-Server)
**Success Criteria:**
1. Self-Service-Trial ohne Vertriebs-Freigabe (`requires_manual_activation=false`) mit Zahlungsmethoden-Pflicht.
2. Plan-Wechsel/Add-On-Käufe laufen über den Web-Checkout-Flow (PWA-only → kein App-Store, keine Store-Billing-Auflage).
2. Plan-Wechsel/Add-On-Käufe laufen über den Web-Checkout-Flow (PWA-only → kein App-Store, keine Store-Billing-Auflage). Der Vertrag unterstützt wiederkehrende Pauschal-Add-ons und einmalige Einrichtungspositionen; Usage-Metering bleibt ausgeschlossen. `VA-P26c` nutzt dies für Portal und Custom-Domain.
3. Onboarding-Wizard resumebar nach Signup, Step-Validierung, Block der Rückwärts-Navigation nach irreversiblen Actions.
4. SHK-Branchen-Template (Pipelines/Rollen/Custom-Felder/Forms/Demo/Checkliste) deklarativ aus YAML geseedet; weitere Branchen „coming soon".
5. Erste-Schritte-Checkliste (Detection-Rules) + Demo-Daten-Bulk-Löschung.
@@ -125,44 +122,47 @@ als eigener Service/Container `hivegrid-mcp` (`apps/mcp`); kein `/mcp`-Pfad, nic
~~**Owner:** Raffael · **Slot:** W1→W2 (Start 18./19.07.) · **Goal:** Aus dem v1-LLM-Gateway wird semantische Tiefe — RAG über Tenant-Daten, EU-Whisper, perspektivisch der autonome HiveMind-Agent.~~ *(v3-Kandidat, zurückgestellt — [[AD-26]])*
~~**Milestones:** M087 (RAG-Layer + Aktions-Grenze) + Whisper-EU + pgvector-Hybrid-Suche + zweiter EU-Provider~~
~~**Source-Specs:** `_bmad-output/specs/M18-ki-layer.md` (RAG/HiveMind/Whisper-Teile)~~
~~**Depends on:** v1-LLM-Gateway (Multi-Provider-Abstraktion) · v1-`RetrievalProvider`-Interface + Outbox-Index-Events · v1-AiCredits/AiTokenUsage · v2-P9 Help-Center (RAG-Korpus) · v1-Activity-Stream/Custom-Felder/Forms (RAG-Quellen) · Promptfoo in CI~~
~~**Success Criteria:** Embedding-Pipeline → `TenantEmbedding` (pgvector, HNSW/IVFFlat) · RAG für Programm-Hilfe/Lead-Zusammenfassung/Hybrid-Suche (RRF) · Whisper-EU (Scaleway-GPU) async · HiveMind-Agent mit Action-Boundary · Multi-Provider-Failover (Mistral→Scaleway→AlephAlpha) + Promptfoo in CI.~~
~~**Screens (David):** KI-Chat/Assistent-Panel + History · HiveMind-Insight-Anzeige · Custom-Tool-Editor + Scheduled-Actions · AI-Usage-Dashboard · Whisper-Aufnahme/Transkription.~~
~~**Recut/Risiko:** DSGVO-Hard-Constraint (nur EU-Provider, AVV); HiveMind autonom erst nach Reifegrad-Gate; pgvector-Index- + Whisper-Modell-Wahl offen.~~
### v2-P5: KWP-Integration *(ex-P10 — RECUT auf REST/OAuth)*
**Owner:** Raffael · **Slot:** W2 (20.–26.07., E2E mit Geerkens Fr 24.07.) · **Goal:** KWP wird regulärer REST/OAuth-Adapter über die Apps-Engine — bidirektionaler Sync (Aufträge/Stammdaten/Belege/Plantafel/Dokumente) mit „KWP gewinnt"-Konfliktregel.
**Milestones:** M089 (API-Connector), M090 (Connection-Health), M091 (Push-Queue + Replay), M092 (Contract-Sentinel), M093 (Konflikt „KWP gewinnt"), M094 (Plantafel-Sync), M095 (Dokumenten-Archiv-Sync), M074 (Task-ERP-Sync)
**Source-Specs:** `_bmad-output/specs/M19-kwp-integration.md` + **`docs/milestones/M19-KWP-API-RECUT.md` (bindend)**
**Depends on:** **HART: v1-M33a Apps-Engine-Adapter-Interface (M008–M010)** · v1-Cloud-Outbox + Idempotency-Wrapper (M007) · v1-`@hivegrid/storage` + FileEntityLink · v1-Extension-Points an Auftrag/Abnahme/Material (P9) · v1-P12 Automation (`kwp.push_auftrag`-Action) · AVV/Subprozessoren (P11)
### v2-P5: KWP-Integration *(ex-P10 — RECUT auf REST/OAuth2)*
**Owner:** Raffael · **Slot:** Read-only Implementierung ab W2; Live-E2E separat ohne Termin nach `VR-P32c/d` + `VN-1` · **Goal:** KWP wird regulärer REST/OAuth2-Adapter über die Apps-Engine. Der initiale/current Scope ist read-only KWP → HiveGrid für Aufträge/Stammdaten/Belege/Plantafel/Dokumente/Tasks mit „KWP gewinnt"-Konfliktregel; HiveGrid führt keine fachliche KWP-Mutation aus.
**Milestones:** current read-only: M089 (API-Connector), M090 (Connection-Health), M092 (Contract-Sentinel), M093 (Konflikt „KWP gewinnt"), M095 (Dokumenten-Archiv-Sync) sowie M094-inbound (Plantafel) und M074-inbound (Tasks); **geparkt:** M091 (Push-Queue + Replay), M094-outbound, M074-outbound
**Depends on:** **HART: v1-M33a Apps-Engine-Adapter-Interface (M008–M010)** · v1-`@hivegrid/storage` + FileEntityLink · v1-Extension-Points an Auftrag/Abnahme/Material (P9) · AVV/Subprozessoren (P11). Cloud-Outbox/M007 und P12-`kwp.push_auftrag` werden erst vom geparkten Writeback benötigt.
**Success Criteria:**
1. KWP-API-Connector als erster konkreter Adapter hinterm M33a-Interface; Credentials per-Tenant-DEK-verschlüsselt in `DataConnection.config`.
2. Bidirektionaler Sync: Push (Won→Auftrag) via Outbox + Rate-Limited-Replay; Pull via Webhook (falls KWP-Support) oder Cron, idempotent über `AppSyncItem`.
1. KWP-API-Connector als erster konkreter Adapter hinterm M33a-Interface; Kundenkürzel und OAuth-Metadaten/Refresh-Token per-Tenant-DEK-verschlüsselt in `DataConnection.credentialsCiphertext`, Relay-Host dynamisch über den offiziellen Loadbalancer.
2. Read-only Sync: Pull mangels dokumentierter Webhooks per konservativ rate-limitiertem Cron, idempotent über `AppSyncItem`; keine Create-, Update-, Delete-, Import- oder sonstigen fachlichen KWP-Schreibrequests.
3. Konflikt „KWP gewinnt" (LWW mit Audit-Restore) + Optimistic Locking HiveGrid-seitig.
4. API-Contract-Sentinel (zod-Validierung + Versions-Check) pausiert Sync bei Drift + alarmiert Plattform-Admin.
5. Plantafel-Sync + Dokumenten-Archiv-Sync (KWP-Doc → Storage) laufen über die API.
**Screens (David/Akeshan):** KWP-Setup-Wizard (OAuth/API-Key, Initial-Sync-Vorschau) · Connection-Health-View · Sync-Log + KwpErrorReport · Konflikt-Resolution (Diff + Restore) · Admin: KWP-Sync-Status pro Tenant + Contract-Diff + Sync-Freigabe
**Recut/Risiko:** ⚠️ **kwpsync.exe NICHT bauen** (3→2-Komponenten). **Größter Blocker: konkreter KWP-API-Vertrag offen** (Auth/Endpoints/Webhook-Support/Rate-Limits/Versionierung/Doc-API) — Zugang ~20.07. AVV-Neubewertung: Creds liegen jetzt verschlüsselt in der Cloud (Spec-Aussage „verlässt Kundennetz nie" gilt nicht mehr 1:1).
4. API-Contract-Sentinel (Tenant-OpenAPI-Fingerprint + endpoint-spezifische Response-Validierung) pausiert Sync bei Drift + alarmiert Plattform-Admin.
5. Plantafel-, Task- und Dokumenten-Archiv-Daten laufen KWP → HiveGrid über die API; KWP-Dokumente werden in `@hivegrid/storage` übernommen.
6. Vollständige Scoped-Adapterabdeckung nach CR-005: 554 Tenant-Operationen inventarisiert; alle 113
Operationen der fünf HiveGrid-`*-extern`-Scopes besitzen einen festen Contract. 77 semantische Reads
sind allowlisted, 36 Mutation-Contracts bleiben fixture-validiert und garantiert vor HTTP gesperrt.
**Screens (David/Akeshan):** KWP-Setup-Wizard (Kundenkürzel + OAuth2/PKCE, Initial-Sync-Vorschau) · Connection-Health-View · Sync-Log + KwpErrorReport · Konflikt-Resolution (Diff + Restore) · Admin: KWP-Sync-Status pro Tenant + Contract-Diff + Sync-Freigabe
**Recut/Risiko:** ⚠️ **kwpsync.exe NICHT bauen** (3→2-Komponenten). Auth-/Resource-/Refresh-Dauerbetrieb ist bewiesen; es gibt keine dokumentierten Webhooks, Delta-Cursor oder einheitlichen Versionsfelder. AD-32/CR-003 parken M091, `kwp.push_auftrag`, Project-/Auftrag-Create und die Outbound-Anteile von M094/M074 hinter `VEXT-6` + erneuter Freigabe. CR-005 erweitert nur die explizite Contract-Abdeckung; Mutation-Contracts sind nicht runtime-ausführbar und kein Writeback. AVV-Neubewertung: OAuth-Metadaten/Refresh-Token liegen verschlüsselt in der Cloud; Azure-Exchange-URLs sind kurzlebige Transferdaten.
### v2-P6: Customer-Portal *(ex-P18)*
**Owner:** Akeshan · **Slot:** W2 (20.–22.07.) · **Goal:** Endkunden sehen über eine eigene Auth-Schicht ihre Projekte/Status/Dokumente, laden Dateien hoch, erhalten Auto-Status-Mails.
**Owner:** Akeshan · **Slot:** `VA-P26a` retimiert 16.07.–05.08.; `VA-P26b` frühestens ab 06.08. mit neu zu planendem Ziel; `VA-P26c` Termin offen · **Goal:** Endkunden sehen über eine eigene Auth-Schicht ihre Projekte/Status/Dokumente, laden Dateien hoch, erhalten Auto-Status-Mails und erreichen das Portal über einen dedizierten Standardhost oder optional eine verifizierte Kundendomain.
**Milestones:** M141 (Auth/Magic-Link), M142 (Projekt-Sicht + Status-Mails), M143 (Endkunden-Upload + Reklamation), M144 (Subunternehmer-Zugang), M145 (Skalierungs-Sicht/Service-Inbox), M146 (Lebensdauer + DSGVO + Konfig)
**Source-Specs:** `_bmad-output/specs/M15-customer-portal.md`
**Depends on:** v1-Auth-Pattern (parallel, NICHT geteilt) + Tenant-Lifecycle (`frozen`→read-only) · v1-Project-Stage-Trigger + Acceptance-PDF-Auto-Freigabe · **v1-Files/FileEntityLink** (Doc-Freigabe + Portal-Uploads, in P4 vorbereitet) · v1-Sende-Domain (Auto-Mails) · v1-Form-Builder (`portal_form`) · v1-Automation (`portal.*`) · v1-notify() · v1-DSGVO-Lösch-Workflow · v1-URL-Pfad `app.hivegrid.de/portal/<tenant>/…`
**Requirements:** REQ-portal-datenmodell, REQ-portal-auth-magic-link, REQ-portal-projekt-sicht, REQ-portal-runtime-isolation, REQ-portal-commercial-access, REQ-portal-custom-domain
**Depends on:** v1-Auth-Pattern (parallel, NICHT geteilt) + Tenant-Lifecycle (`frozen`→read-only) · v1-Project-Stage-Trigger + Acceptance-PDF-Auto-Freigabe · **v1-Files/FileEntityLink** (Doc-Freigabe + Portal-Uploads, in P4 vorbereitet) · v1-Sende-Domain (Auto-Mails) · v1-Form-Builder (`portal_form`) · v1-Automation (`portal.*`) · v1-notify() · v1-DSGVO-Lösch-Workflow · P1-Host-Routing/URL-Contract · `VA-P24a` für pauschale Add-ons/Einmalpositionen · Estate-Traefik/DNS/TLS
**Success Criteria:**
1. Eigene `PortalUser`-Klasse strikt getrennt von TenantUser (eigene Cookies, Routes, keine Permission-Vermischung); Magic-Link primär.
2. Endkunde sieht nur eigene Projekte/konfigurierte Stages/freigegebene Dokumente; fehlender Zugang → 404 (keine Existenz-Offenlegung).
3. Upload (mobile-Kamera, Multi-File, Limits) → Files + Activity + PL-Notification.
4. Auto-Status-Mails bei `project.stage_changed` (Debounce, Bedingungen: sichtbare Stage/aktiver Access/Pref/nicht frozen).
5. Tenant-Admin konfiguriert Phasen-Sichtbarkeit/Doc-Auto-Freigabe/Templates; DSGVO-Lösch/Export für PortalUser.
**Screens (David — eigener Polish, extern sichtbar):** Endkunde: Login/Setup/Reset, Portal-Dashboard, Projekte-Liste, Project-Detail (Fortschritt/Docs/Upload/Reklamation), Settings · Tenant-Admin: Portal-Konfig, PortalUser-Verwaltung, Access-Matrix, Mail-Template-Editor
**Recut/Risiko:** Eigene Auth = eigenes Härtungs-Budget (Rate-Limits, Captcha, kein User-Enumeration, wasserdichte Cookie-Trennung). Spec ist als `phase:1 kritisch für Geerkens` markiert → **ggf. Vorzieh-Kandidat** (Scope-Schnitt AD-18 hat es bewusst v2 — bei Bedarf neu entscheiden). Ausgeklammert: Multi-Portal/Branding/Custom-Domain/PortalSubscription/PWA-Push.
1. Eigener Coolify-Service/Container `hivegrid-portal` aus demselben immutable Web-Image; fail-closed Surface-Routing, getrennte Sessions/Secrets/Healthchecks und dedizierter minimal berechtigter DB-Login `hivegrid_portal` isolieren App/Admin.
2. Eigene `PortalUser`-Klasse strikt getrennt von TenantUser (eigene Cookies, Routes, keine Permission-Vermischung); Magic-Link primär.
3. Endkunde sieht nur eigene Projekte/konfigurierte Stages/freigegebene Dokumente; fehlender Zugang → 404 (keine Existenz-Offenlegung).
4. Upload (mobile-Kamera, Multi-File, Limits) → Files + Activity + PL-Notification.
5. Auto-Status-Mails bei `project.stage_changed` (Debounce, Bedingungen: sichtbare Stage/aktiver Access/Pref/nicht frozen).
6. Tenant-Admin konfiguriert Phasen-Sichtbarkeit/Doc-Auto-Freigabe/Templates; DSGVO-Lösch/Export für PortalUser.
7. Standardhost ist `portal.hivegrid.de/<tenant>`; ein optionaler Custom-Host wird per TXT+CNAME self-service verifiziert, automatisch mit TLS/Ingress provisioniert und sicher einem Tenant zugeordnet. Der Standardhost bleibt Fallback.
8. Portal-Entitlement: Starter/Team 19,99 EUR netto/Monat, Business/Enterprise inklusive; Custom-Domain Starter/Team/Business 299,99 EUR netto je Einrichtung, Enterprise eine inklusive. Ein Domainwechsel ist eine neue kostenpflichtige Einrichtung, sofern keine individuelle Enterprise-Regel greift. PortalUser/Projekte unbegrenzt, Basispaket-Limits bleiben. Öffentliche Freischaltung erst nach `VA-P26b`; Domain-Reclaim-Cooldown 30 Tage.
**Screens (David — eigener Polish, extern sichtbar):** Endkunde: Login/Setup/Reset, Portal-Dashboard, Projekte-Liste, Project-Detail (Fortschritt/Docs/Upload/Reklamation), Settings · Tenant-Admin: Portal-Konfig, PortalUser-Verwaltung, Access-Matrix, Mail-Template-Editor, Paket-/Domain-Setup mit DNS/TLS-Status
**Recut/Risiko:** Eigene Auth = eigenes Härtungs-Budget (Rate-Limits, Captcha, kein User-Enumeration, wasserdichte Cookie-Trennung). Die Portal-Runtime ist ein zusätzlicher Coolify-/Deploy-/RLS-Security-Slice in `VA-P26a`; deshalb wurde `VA-P26a` am 15.07.2026 auf 16.07.–05.08. retimiert und `VA-P26b` hinter das Security-Gate verschoben. Custom-Domain = separater Provisioner- und Domain-Takeover-Sicherheitsbereich. Ausgeklammert bleiben eigenes `apps/portal`/Portal-Image im ersten Schnitt, Multi-Portal, vollständiges App-White-Label, Apex/Wildcard/mehrere Portal-Domains und PWA-Push; PortalSubscription als eigenes paralleles Abomodell bleibt ausgeschlossen, die Freischaltung läuft über die zentralen HiveGrid-Entitlements (AD-30).
### v2-P7: Mobile-PWA-Ausbau
**Owner:** Akeshan · **Slot:** W2→W3 (23.–27.07.) · **Goal:** Die mobile-first-PWA aus v1 wird zur vollwertigen installierbaren App — Add-to-Homescreen, Service-Worker-Offline-Härtung, Web-Push, Baustellen-tauglich. **Kein nativer Client, kein App-Store** (AD-17, PWA-only).
**Milestones:** M167 (PWA-Manifest + Installierbarkeit), M168 (Web-Features: Web-Push/Kamera/Foto), M169 (mobile Navigation + Routes), M170 (Service-Worker-Offline-Modus), M171 (Force-Update + PWA-Härtung) — auf PWA umzuschneiden
**Source-Specs:** `_bmad-output/specs/M36-mobile-app.md` (⚠ Recut → PWA-only; Capacitor/Expo verworfen)
**Depends on:** **v1-OfflineSyncQueue (P9) + serverseitige Idempotency-Keys** · v1-notify()/NotificationDevice (→ Web-Push/VAPID, P21-Andockpunkt) · v1-Auth (Email/Pwd + Magic-Link + offline Permissions-Snapshot) · v1-Files (Foto), Abnahme/Tasks/Chat offline · mobile-first responsive Web (Voraussetzung)
**Success Criteria:**
1. Offline-Pflicht: Pre-Cache beim Login (Projekte/Tasks/Kontakte/Checklisten/Acceptance-Templates) über Service-Worker + IndexedDB, Offline-Read + Offline-Write-Queue (Foto/Note/Task-Status/Checklist/Acceptance/Chat).
@@ -173,22 +173,21 @@ als eigener Service/Container `hivegrid-mcp` (`apps/mcp`); kein `/mcp`-Pfad, nic
**Recut/Risiko:** ⚠️ **PWA-only-Recut** der M36-Spec (kein EAS-Build, keine Native-Module, keine Store-Compliance). iOS-Safari-PWA-Grenzen (Web-Push iOS ≥16.4 nur im installierten Standalone-Modus), Offline-Storage-Budget, Background-Sync-Verfügbarkeit. **Kein** Apple/Google-Review-Risiko mehr. Native-App + Stores → frühestens v3.
### v2-P8: Plattform-Admin-Tiefe
**Owner:** Raffael + Akeshan · **Slot:** W3 (27.–29.07.) · **Goal:** Getrennte AdminUser-Identität/RBAC auf `admin.hivegrid.de` + Feature-Flag-Massen-Statistik (löst die v1-Auflagen-Brücke ab).
**Milestones:** M038 (Mandanten-MA-Verwaltung), M039 (AdminUser-Konten + Rollen), M033 (Flag-Massen-Statistik), M040 (interne Lead-Pipeline)
**Source-Specs:** `_bmad-output/specs/M37-plattform-admin.md` (Block A–D), `M32-feature-flags.md` (Massen-Statistik)
**Depends on:** v1-Auth-Bausteine (TOTP/Bcrypt/Session — wiederverwendet, eigene Tabellen) · v1-FeatureFlag-Modell + `tenantHasFlag()` (P8 ergänzt nur Massen-UI) · v1-AdminAuditLog · v1-Admin-Welt-Auflagen (M034 Host-Routing/Cookie-Trennung/TOTP — die v1-Brücke) · Read-Replica (Filter-Vorschau) · Redis (Dashboard-Cache)
**Owner:** Raffael + Akeshan · **Slot:** M040a vorgezogen ab 16.07.; übrige Tiefe W3 (27.–31.07.) · **Goal:** Native Plattform-Leads und getrennte AdminUser-Identität/RBAC auf `admin.hivegrid.de` + Feature-Flag-Massen-Statistik (löst die v1-Auflagen-Brücke ab).
**Milestones:** M038 (Mandanten-MA-Verwaltung), M039 (AdminUser-Konten + Rollen), M033 (Flag-Massen-Statistik), M040a (native Plattform-Leads/Intake/Admin-Inbox/Cutover in `R-LEADS`), M040b (AdminDeal/Kanban/Forecast/Promotion in `VA-P28b`)
**Depends on:** M040a verwendet die bereits ausgelieferten M034-/AK-P19-Verträge (Admin-Host/Shell/Auth/Audit), aber nicht dessen offene Billing-/Support-/Queue-DoD · v1-Auth-Bausteine (TOTP/Bcrypt/Session — wiederverwendet, eigene Tabellen) · v1-FeatureFlag-Modell + `tenantHasFlag()` (P8 ergänzt nur Massen-UI) · Read-Replica (Filter-Vorschau) · Redis (Dashboard-Cache). M040b hängt zusätzlich von M040a + M038/M039 ab.
**Success Criteria:**
1. Eigene `AdminUser`-Klasse, hart getrennt (eigene Cookies SameSite=Strict, kein Cross-Routing, **kein BYPASSRLS** — Admin liest Tenant-Daten via RLS mit gesetztem `app.tenant_id`).
2. AdminRBAC mit eigenen Bundles + Default-Rollen (super_admin/support/sales/engineering/viewer), 2FA-Pflicht, 8h-Session, Self-Permission-Schutz.
3. AdminAuditLog cross-tenant mit Reason-Pflicht bei sensitiven Aktionen; Impersonate mit Reason + Banner.
4. Flag-Massen-Statistik: Effektiv-Auswertung (X aktiv/Y nicht), Live-Filter-Vorschau, Bulk-Override; deterministische Auswertung (Override > Filter > Default) + Audit.
**Screens (David — interner Polish):** AdminUser-Verwaltung + AdminRole-Editor + Admin-Security-Settings · Feature-Flag Effektiv-Statistik + Filter-Editor (Live-Match) + Bulk-Override · interne Lead-Pipeline (HiveGrid-eigene Verkäufe) · Cross-Tenant-Audit-View
**Recut/Risiko:** Kein BYPASSRLS = bewusste Hardgrenze. Impersonate-Cookie-Scope offen. M032 Tenant-Self-Service-Flags (`/labs/`) = spätere Phase.
5. M040a: source-authentifizierter/idempotenter Plattform-Lead-Eingang, native AdminLead-Inbox, Legacy-Backfill und kontrollierte Stilllegung von `lead-inbox`; M040b ergänzt Deal-Kanban/Forecast/Promotion ohne zweite Lead-Datenbasis.
**Screens (David — interner Polish):** AdminUser-Verwaltung + AdminRole-Editor + Admin-Security-Settings · Feature-Flag Effektiv-Statistik + Filter-Editor (Live-Match) + Bulk-Override · Plattform-Lead-Inbox/-Detail/-Sources (M040a) · Deal-Pipeline/-Detail (M040b) · Cross-Tenant-Audit-View
**Recut/Risiko:** AD-31: M040a ist als `R-LEADS` vorgezogen; `VD-P28` bleibt nach AD-28 ein Design-Nachzug. Kein BYPASSRLS = bewusste Hardgrenze. Impersonate-Cookie-Scope offen. M032 Tenant-Self-Service-Flags (`/labs/`) = spätere Phase.
### v2-P9: Help-Center & Help-Desk
**Owner:** Akeshan · **Slot:** W3 (28.–30.07.) · **Goal:** Öffentliches file-basiertes Help-Center mit Deep-Links aus der App + In-App-Feedback-Widget → Plattform-Admin.
**Milestones:** M172 (Markdown-Artikel Git-PRs), M173 (Routes + Suche + SEO + kontextuelle Hilfe), M174 (Email-Ticket-System), M175 (In-App-Feedback-Widget)
**Source-Specs:** `_bmad-output/specs/M38-help-center.md`, `M39-help-desk.md`
**Depends on:** Public-Routing außerhalb Auth-Middleware + IP-Rate-Limiting · v1-Files (Feedback-Attachments) · **v1-Feedback-Widget → Support-Inbox (P21-Andockpunkt, generische Quelle)** · v2-P8 AdminAuditLog + Admin-Permissions · v2-P4 MCP-Resources optional für Help-Artikel · v2-P10 i18n (Sprachsegment)
**Success Criteria:**
1. Markdown mit Frontmatter, Build-Time-Index (Volltext + Kategorien + Sitemap), Build-Fail bei kaputten Referenzen.
@@ -202,7 +201,6 @@ als eigener Service/Container `hivegrid-mcp` (`apps/mcp`); kein `/mcp`-Pfad, nic
### v2-P10: Komfort & Querschnitt
**Owner:** Akeshan · **Slot:** W3 (29.–31.07.) · **Goal:** Querschnitts-Komfort — anpassbare Dashboards/Export, Notification-Bündelung/Quiet-Hours, Sprach-Wechsler/EN, HR-Drittanbieter-Onboarding.
**Milestones:** M149 (Custom-Widgets + Drilldown), M150 (Dashboard-Export/Report), M117 (Notif-Bündelung + Quiet-Hours), M029 (Sprach-Wechsler + EN), M138 (HR-Onboarding-Drittanbieter)
**Source-Specs:** `_bmad-output/specs/M20-dashboard.md`, `M22-notifications.md`, `M30-i18n.md`, `M14-hr-hub.md`
**Depends on:** v1-Dashboard/Widget-Registry (P11, voll gebaut) + Role-Default-Layouts (deklaratives Template, geteilt mit P3) · v1-notify() (P10 ergänzt Bundle-Manager/Quiet-Hours-Resolver) · v1-i18n-Library + DE-Locale (P10 füllt EN + DeepL) · v1-M33a Apps-Engine (HR-Drittanbieter) · WebSocket (Chat-geteilt) · v1-Forms/Tasks (Onboarding-Checklisten)
**Success Criteria:**
1. Dashboard: User passt Layout an (Drag/Resize, Widget-Catalog permission-gegated), Drilldown pro Kachel, CSV-Export, Realtime mit Opt-Out.
@@ -215,7 +213,6 @@ als eigener Service/Container `hivegrid-mcp` (`apps/mcp`); kein `/mcp`-Pfad, nic
### v2-P11: Telefonie-Erweiterung & DSGVO-Vollausbau
**Owner:** Raffael · **Slot:** W3 (29.–31.07.) · **Goal:** Zweiten Telefonie-Provider anbinden + DSGVO vertiefen (AVV-Versionierung, Subprozessoren-Workflow, Auskunfts-/Export-Workflow ersetzt manuelles Playbook).
**Milestones:** M105 (HalloPetra-Adapter), M166 (AVV + Subprozessoren + Auskunfts-Workflow)
**Source-Specs:** `_bmad-output/specs/M12-telefonie.md` (Provider-Pattern), `M35-dsgvo-export.md`
**Depends on:** **v1-TelephonyProviderInterface + AirCall-Adapter (P15) als Referenz** · v1-Automation-Trigger (`call.*`) · v1-notify() · v1-Files (Export-ZIP, AVV-PDF) · BullMQ-Worker · v1-Account-Löschung (P2/P21) · v1-Frozen→Deletion (P20) · v2-P8 AdminAuditLog + Legal-Verwaltung
**Success Criteria:**
1. HalloPetra als zusätzlicher Provider hinterm `TelephonyProviderInterface` ohne Kern-Umbau; Webhook-Auto-Match → Activity + Automation-Trigger.
@@ -230,15 +227,15 @@ als eigener Service/Container `hivegrid-mcp` (`apps/mcp`); kein `/mcp`-Pfad, nic
## Geteilte v2-Mechanismen (einmal robust bauen)
- **Deklaratives Branchen-Template-Seeding** — zieht durch P3 (Onboarding), P6 (PortalConfig), P10 (Dashboard-/Notification-Defaults).
- **M33a-Adapter-Pattern** — trägt P5 (KWP), P2 (Email-Provider), P10 (HR-Drittanbieter), P11 (Telefonie-Provider). Alle mit „Partner-API-Vertrag offen"-Risiko.
- **M33a-Adapter-Pattern** — trägt P5 (KWP), P2 (Email-Provider), P10 (HR-Drittanbieter), P11 (Telefonie-Provider). KWP hat einen live bewiesenen OAuth-/Health-Vertrag und startet read-only; nur Writeback wartet hinter `VEXT-6` auf den belastbaren Providervertrag. HalloPetra und HR warten noch auf ihren Partnervertrag.
- **Webhook-Ingest-Infra** — geteilt P1 (Public-API) + P2 (Email).
## Offene Vorlauf-Tasks (Specs/Verträge, vor Bau)
1. **KWP-API-Vertrag** (Zugang ~20.07.) → Recut-Detailplanung pro Milestone.
1. **KWP-Writeback-Vertrag (`VEXT-6`):** Dokumentierte Mutationsoperationen einschließlich Project-/Auftrag-Create, Scopes/BNWIN-Rechte, Request-/Response-Schemas, Idempotenz-/Fehlersemantik, Rate-Limit-Verhalten und kontrollierten Testpfad bestätigen lassen. Kein Blocker des initialen read-only Scopes; Dev-Slice erst nach erneuter Produktfreigabe.
2. **HalloPetra-Spec** (Telefonie-Provider-Vertrag) — neu.
3. **Memberspot/Boobora-Spec** (HR-Drittanbieter) — neu.
4. **Konkrete Preise/Plans** (für Self-Service P3) — in v1 EXT-14 fixiert.
5. **AVV-PDF-Inhalt** anwaltlich (P11) — in v1 EXT-03 beauftragt.
---
*Erzeugt: 2026-06-15 aus 18 v2-relevanten Modul-Specs (Teilmenge der 36 Specs gesamt, vgl. PHASE-SOURCES.md) + KWP-Recut-Doku. Coverage: 43/43 v2-Milestones gemappt. Nächste Schritte (User): → Tickets pro Phase (Plane), Assignee-Klärung, v2-Screen-Map, dann sauberer Update-Pass.*
*Erzeugt: 2026-06-15 · aktive Quellen zuletzt bereinigt: 2026-08-02. Coverage: 43/43 v2-Scope-Bausteine gemappt.*
@@ -2,7 +2,7 @@
## Overview
HiveGrid 2.0 entsteht in einem Big-Bang-Launch (AD-19): erst live, wenn das vollständige Phase-1-Produkt steht. Die interne Bau-Reihenfolge folgt der Hybrid-Strategie AD-11 — zuerst ein Walking-Skeleton-Fundament (Boilerplate einziehen, EU-Sterilisation, Integration-Contracts **plus die Service-Kerne Audit, Notifications, i18n und Feature-Flags** — sie sind Vorbedingung des gesamten Auth-Blocks), dann Identität/Multi-Tenancy, die Querschnitts-Oberflächen (Audit-Viewer, Notification-Center, Sprach-UX) und die nutzerseitigen Primitive (Files, Tasks), darauf die Apps-Engine, das CRM-Datenmodell und die durchgängige SHK-Wertschöpfungskette Lead → Sales → Auftrag (KWP-Sync = erstes v2-Modul — API-Zugang erst ~19.07., nach v1-Launch; Scope-Schnitt #12). Erst danach kommt die Breite: globale Suche/Dashboard, die USP-Säulen Automation-Engine und ~~KI-Layer~~ (AD-16) **[⛔ KI→MCP-Pivot ([[AD-26]]): Die KI-Hälfte der USP entfällt in v1 — HiveGrid hostet kein eigenes LLM/RAG, sondern wird MCP-Server ([[VR-MCP]]). Die Automation-Säule bleibt unverändert.]**, die Kommunikations-Bausteine (Email/Marketing, Telefonie/Chat, Kalender/Booking/Forms/Signatur), HR-Hub, Customer-Portal und schließlich die Plattform- und Launch-Schicht (Admin, Billing/Onboarding/Branding, Public-API/DSGVO/Mobile/Help). Jede Phase liefert eine eigenständig verifizierbare Fähigkeit; Coverage über alle 90 v1-Requirements ist lückenlos (Scope-Schnitte 11./12.06.2026: 19 Reqs → v2). Die Kommunikations-Phasen hängen primär an der Apps-Engine (Connections) und am CRM (Contact-Matching) — sie brauchen NICHT die Automation/KI-Säulen als Vorbedingung. **Dependency-Inversion-Prinzip:** Es existieren keine unaufgelösten Vorwärts-Abhängigkeiten — spätere Module integrieren sich rückwirkend in frühere Oberflächen (Ownership-Register + Extension-Point-Pflichten in `PHASE-SOURCES.md`); jeder plan-phase-Lauf MUSS die Retro-Integrations-Aufgaben seiner Phase aus dem Register mit einplanen.
HiveGrid 2.0 entsteht in einem Big-Bang-Launch (AD-19): erst live, wenn das vollständige Phase-1-Produkt steht. Die interne Bau-Reihenfolge folgt der Hybrid-Strategie AD-11 — zuerst ein Walking-Skeleton-Fundament (Boilerplate einziehen, EU-Sterilisation, Integration-Contracts **plus die Service-Kerne Audit, Notifications, i18n und Feature-Flags** — sie sind Vorbedingung des gesamten Auth-Blocks), dann Identität/Multi-Tenancy, die Querschnitts-Oberflächen (Audit-Viewer, Notification-Center, Sprach-UX) und die nutzerseitigen Primitive (Files, Tasks), darauf die Apps-Engine, das CRM-Datenmodell und die durchgängige SHK-Wertschöpfungskette Lead → Sales → Auftrag (KWP-Sync = erstes v2-Modul; der Auth-/Resource-/Refresh-Dauerbetrieb ist bewiesen, der initiale Scope ist read-only; Scope-Schnitt #12, AD-32/CR-003). Erst danach kommt die Breite: globale Suche/Dashboard, die USP-Säulen Automation-Engine und ~~KI-Layer~~ (AD-16) **[⛔ KI→MCP-Pivot ([[AD-26]]): Die KI-Hälfte der USP entfällt in v1 — HiveGrid hostet kein eigenes LLM/RAG, sondern wird MCP-Server ([[VR-MCP]]). Die Automation-Säule bleibt unverändert.]**, die Kommunikations-Bausteine (Email/Marketing, Telefonie/Chat, Kalender/Booking/Forms/Signatur), HR-Hub, Customer-Portal und schließlich die Plattform- und Launch-Schicht (Admin, Billing/Onboarding/Branding, Public-API/DSGVO/Mobile/Help). Jede Phase liefert eine eigenständig verifizierbare Fähigkeit; Coverage über alle 90 v1-Requirements ist lückenlos (Scope-Schnitte 11./12.06.2026: 19 Reqs → v2). Die Kommunikations-Phasen hängen primär an der Apps-Engine (Connections) und am CRM (Contact-Matching) — sie brauchen NICHT die Automation/KI-Säulen als Vorbedingung. **Dependency-Inversion-Prinzip:** Spätere Module integrieren sich rückwirkend in frühere Oberflächen; die Ticket-Docs führen die dafür nötigen Abhängigkeiten und Extension-Points.
> 🔴 **MODELL-PIVOT 2026-06-13 (Projekt-zentrisch, AD-20):** Das CRM/Pipeline-Modell wird umgebaut — ein `Projekt`-Kern, Pipelines = konfigurierbare Views; „Deal"/„Auftrag" = Pipeline-Typen, keine eigenen Entitäten; **Lead → Projekt**; Abnahme bleibt v1 als Checklisten-Sub-Area; Rechnung = Sub-Entity v1. Betrifft **P6–P9** (siehe Phasen-Notizen unten). Die Success-Criteria/Requirements von P6–P9 werden gemeinsam mit dem neuen ER-Modell neu gefasst. Single Source: `.planning/ENTITY-MODEL.md`.
@@ -23,7 +23,7 @@ Decimal phases appear between their surrounding integers in numeric order.
- [ ] **Phase 7: Lead-Inbox** - Lead-Triage-Arbeitsplatz, Multi-Quellen-Auto-Anlage, Anti-Spam, Statistiken
- [ ] **Phase 8: Projekt & Pipelines (Kern)** - konfigurierbare Pipelines (Deal/Auftrag = Views, AD-20), Kanban, Forecast/KPIs, Field-Level-Rechte (PipelineFieldVisibility)
- [ ] **Phase 9: Projekt & Pipelines (Auftrag)** - Auftrags-Sub-Areas, Rechnung-Sub-Entity, Plantafel, digitale Abnahme (offline-fähig)
- [ ] ~~**Phase 10: KWP-Integration**~~ — **→ v2, ERSTES v2-Modul** (deferred 2026-06-12; API-Zugang ~19.07. > Launch; Nummer reserviert, Ausführung überspringt P10)
- [ ] ~~**Phase 10: KWP-Integration**~~ — **→ v2, ERSTES v2-Modul** (deferred 2026-06-12; historischer Kalenderentscheid, aktueller Stand unter Phase 32; Nummer reserviert, Ausführung überspringt P10)
- [ ] **Phase 11: Globale Suche & Dashboard** - Keyword-Suche (Meilisearch, AD-5 sequenziert), Cmd+K, Widget-Dashboard mit festen Rollen-Layouts
- [ ] **Phase 12: Automation-Engine** - Visueller Flow-Editor, Trigger/Action-Library, Guards, Dry-Run, 24h-Undo
- [ ] ~~**Phase 13: KI-Layer**~~ — **entfällt in v1 (AD-26)**; kein LLM/RAG/Whisper, kein Sprach-zu-Automation-Unterbau. MCP-Server ist v2-P4.
@@ -33,10 +33,10 @@ Decimal phases appear between their surrounding integers in numeric order.
- [ ] **Phase 17: HR-Hub** - Verschlüsselter HR-Hub, Passwort-Safe, Urlaubs-/Krank-Workflow
- [ ] ~~**Phase 18: Customer-Portal**~~ — **→ v2** (deferred 2026-06-11; Nummer reserviert, Ausführung überspringt P18)
- [ ] **Phase 19: Plattform-Admin** - Getrennte Admin-Welt (admin.hivegrid.de), Tenant-Management + Abo-Zusammenstellung, Queue-Monitoring, Support-Inbox
- [ ] **Phase 20: Billing, Onboarding & Branding** - Legacy-Provider-Billing/Trial/Dunning (Abo-Baukasten-Recut), Auto-SHK-Provisionierung, Theme-Preference
- [ ] **Phase 20: Billing, Onboarding & Branding** - HiveGrid-Entitlements mit Lago-Billing/Mollie-Payments, Trial/Dunning/Frozen, Auto-SHK-Provisionierung; Theme-Unterbau bei vorerst deaktiviertem Toggle
- [ ] **Phase 21: DSGVO & Launch-Reife** - DSGVO-Export + Lösch-Workflow (Crypto-Shredding), Feedback-Widget, Launch-Checkliste
### v2-Phasen (Sprint Mo 13.07.–Fr 31.07., nach Launch — 43 Milestones, 2 Tracks dependency-frei parallel)
### v2-Phasen (Start Mo 13.07., retimierter Carry-over offen — 43 historische Scope-IDs, 2 Tracks parallel)
> 🟦 **v2 = committed-deferred (kein Vielleicht-Backlog).** Voll ausgearbeitete Detail-Fassung (Success-Criteria · Screens · v1-Andockpunkte · Recut/Risiko) je Phase: `.planning/ROADMAP-V2.md`. Bei den „phase:1"-Modulen (P26/P28/P29/P30) ist nur das **v2-Delta** gemeint, nicht das v1-Fundament.
@@ -47,13 +47,13 @@ Decimal phases appear between their surrounding integers in numeric order.
- [ ] **Phase 25: MCP-Server** - Remote-MCP-Server für externe KI-Clients mit Read-Ressourcen und bestätigungspflichtigen Action-Tools (ersetzt HiveMind/RAG, AD-26)
- [ ] **Phase 26: Customer-Portal** ⭐ - Endkunden-Portal (eigene Auth/Magic-Link, Projekt-Sicht, Upload, Reklamation) — **kritisch** (ex-P18)
- [ ] **Phase 27: Mobile-PWA-Ausbau** - Installierbare PWA (Add-to-Homescreen, Service-Worker-Offline, Web-Push) für den Baustellen-Einsatz — kein nativer Client/App-Store (AD-17, PWA-only)
- [ ] **Phase 28: Plattform-Admin-Tiefe** - Getrennte AdminUser-Identität/AdminRBAC + Feature-Flag-Massen-Statistik + interne Lead-Pipeline
- [ ] **Phase 28: Plattform-Admin-Tiefe** - Native Plattform-Leads (M040a vorgezogen) + getrennte AdminUser-Identität/AdminRBAC + Feature-Flag-Massen-Statistik + Deal-Ausbau (M040b)
- [ ] **Phase 29: Help-Center & Help-Desk** - Öffentliches Help-Center (SEO, kontextuell) + Email-Ticket-Desk + Feedback-Ausbau
- [ ] **Phase 30: Dashboard-Deluxe & Querschnitt** - Custom-Widgets/Export + Notif-Bündelung/Quiet-Hours + EN-Locale (DeepL)
- [ ] **Phase 31: DSGVO-Vollausbau** - AVV-Versionierung + Subprozessoren-Workflow + Auskunfts-/Voll-Export-Workflow (ersetzt manuelles Playbook)
**Block 2 — Partner-API-Vertrag offen → ans Ende, agil vorziehbar, sobald Zugang/Spec da:**
- [ ] **Phase 32: KWP-Integration** *(Recut)* - Bidirektionaler Sync HiveGrid↔KWP über die offizielle REST-API (ex-P10; Zugang ~20.07.; kwpsync.exe NICHT bauen)
**Block 2 — externe Runtime-/Partnerverträge → ans Ende, agil vorziehbar, sobald die jeweilige Capability belegt ist:**
- [ ] **Phase 32: KWP-Integration** *(Recut)* - initial read-only OAuth2-Adapter gegen den dynamischen KWP-Relay; Writeback nach `VEXT-6` geparkt (AD-32/CR-003; kwpsync.exe NICHT bauen)
- [ ] **Phase 33: Telefonie-Erweiterung (HalloPetra)** - HalloPetra als zweiter Provider hinterm TelephonyProviderInterface (⚠ Spec offen)
- [ ] **Phase 34: HR-Drittanbieter-Onboarding** - Memberspot/Boobora via Apps-Engine (⚠ Spec offen)
@@ -63,8 +63,6 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Das Repo ist eine lauffähige Codebasis, EU-steril, mit den Querschnitts-Neubauten, den Service-Kernen (Audit, Notifications, i18n, Feature-Flags) und den verbindlichen Integration-Contracts als Bau-Vertrag für alle Folgephasen.
**Depends on**: Nothing (first phase)
**Requirements**: REQ-integration-sidebar, REQ-integration-routes, REQ-integration-activity-wiring, REQ-integration-audit-wiring, REQ-integration-notification-wiring, REQ-integration-view-model-pflicht, REQ-integration-smoke-tests, REQ-audit-datenmodell, REQ-notification-datenmodell, REQ-i18n-architektur, REQ-feature-flags-system
**Source-Specs**: `docs/ARCHITECTURE-DECISIONS.md`, `docs/INTEGRATION-CONTRACTS.md`; Service-Kern-Teile aus `_bmad-output/specs/M21-audit-log.md`, `M22-notifications.md`, `M30-i18n.md`, `M32-feature-flags.md`
**Milestone-PLANs**: 15 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 1)
**Success Criteria** (what must be TRUE):
1. Die HiveGrid-Codebase baut lokal durch; Workspace-Pakete, CLI, Env-Namen, Cookies, Header und Queue-Namen nutzen HiveGrid-Contracts ohne Alt-Aliase (AD-10). *Planner-Hinweis: historische Boilerplate-Reste sind Arbeitsmaterial und kein Upstream-Merge-Ziel.*
2. GitHub/Google-OAuth-Reste und `User.githubId/googleId` sind entfernt; keine US-Kern-Abhängigkeit mehr im Auth-Pfad (EU-Sterilisation).
@@ -80,27 +78,25 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Ein Handwerksbetrieb kann sich selbst registrieren, sicher anmelden und in einem vollständig RLS-isolierten Mandanten mit rollenbasierten Rechten arbeiten.
**Depends on**: Phase 1
**Requirements**: REQ-auth-multi-tenancy, REQ-auth-methoden, REQ-auth-rbac, REQ-auth-user-lifecycle
**Source-Specs**: `_bmad-output/specs/M27-auth-multi-tenancy.md`
**Milestone-PLANs**: 9 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 2); Scope-Schnitt 12.06.: M027 (API-Keys) → v2 mit Public-API — Boilerplate-`ApiKey`-Modell bleibt ungenutzt im Code
**Scope-Notiz:** M027 (API-Keys) → v2 mit Public-API; Boilerplate-`ApiKey`-Modell bleibt ungenutzt im Code.
**Success Criteria** (what must be TRUE):
1. Ein Nutzer kann sich per Self-Service registrieren, erhält einen auto-generierten Tenant-Slug (Reserved-Words geblockt) und landet unter app.hivegrid.de.
2. Login mit Email+Passwort (NIST/Breach-Check) plus TOTP-2FA funktioniert; Sessions sind in Postgres serverseitig (Geräte-Liste, Revoke, „von allen Geräten abmelden") mit Redis-Cache (AD-4).
3. RLS-Policies (USING/WITH CHECK, `SET LOCAL app.tenant_id`, App-Rolle ohne BYPASSRLS) verhindern nachweisbar mandantenübergreifenden Datenzugriff (AD-1).
4. 6 SHK-Standard-Rollen sind geseedet *(Staging/Dev; Produktion startet admin-only, AD-29)*; ein Admin kann Nutzer einladen (48h-Token), deaktivieren und DSGVO-konform per PII-Anonymisierung löschen.
4. Jeder neue Workspace erhält fünf editierbare SHK-Tenant-Rollen; der Owner erhält ausschließlich die globale Rolle `Admin` (AD-29). Ein Admin kann Nutzer einladen (48h-Token), deaktivieren und DSGVO-konform per PII-Anonymisierung löschen.
5. *(→ v2, Scope-Schnitt 12.06.)* ~~Ein Nutzer kann API-Keys mit Scopes und Rate-Limit erstellen~~ — wandert mit der Public-API (M161–163) nach v2.
**Plans**: TBD
**UI hint**: yes
### Phase 3: Querschnitts-Oberflächen
**Goal**: Die Bedien-Oberflächen der in Phase 1 gebauten Plattformdienste stehen — Audit-Viewer mit Export, Notification-Center mit Nutzer-Einstellungen und die Sprach-Settings (v1 DE-only).
**Goal**: Die Bedien-Oberflächen der in Phase 1 gebauten Plattformdienste stehen — Audit-Viewer mit Export, Notification-Center mit Nutzer-Einstellungen und aktivierungsgegatete Sprach-Settings für `de/en/pl/ru/uk/hu` (CR-020).
**Depends on**: Phase 2
**Requirements**: REQ-audit-retention-export, REQ-audit-permissions, REQ-notification-versand-pipeline, REQ-i18n-outbound
**Source-Specs**: `_bmad-output/specs/M21-audit-log.md`, `_bmad-output/specs/M22-notifications.md`, `_bmad-output/specs/M30-i18n.md` (Oberflächen-Teile; Service-Kerne → Phase 1)
**Milestone-PLANs**: 5 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 3); Scope-Schnitt 12.06.: M029 (Sprach-Wechsler) + M117 (Bündelung/Quiet-Hours) → v2; M028/M152 gedünnt
**Scope-Notiz:** M117 (Bündelung/Quiet-Hours) → v2; M028/M152 gedünnt. M029 und die statischen Sechs-Sprachen-Kataloge wurden mit CR-020 als `I18N-01` vorgezogen; neue Sprachen bleiben bis zum jeweiligen Review-Gate deaktiviert.
**Success Criteria** (what must be TRUE):
1. Ein Nutzer mit Audit-Permission sieht den Audit-Viewer (gefiltert, permission-gegated); Export als NDJSON/CSV ins Object Storage (Hetzner-S3) funktioniert mit fixer Default-Retention. *(Scope-Schnitt 12.06.: konfigurierbare Retention-Policy/Legal-Hold/Saved-Views → v2; Boilerplate liefert Retention-Cron + PDF-Export.)*
2. Die Versand-Pipeline stellt Notifications über BullMQ in alle Kanäle zu (In-App via SSE, Email; Push-Stub bis v2) — sofort, ohne Bündelung; ein Nutzer sieht das Notification-Center und schaltet Kategorien pro Kanal an/aus. *(Scope-Schnitt 12.06.: Quiet-Hours/Bündelung/Push-Limits = M117 → v2, bewusste Entscheidung.)*
3. Alle Oberflächen-Strings laufen durch `t()` mit vollständiger `de`-Locale (`verify:i18n`-Gate grün); Contact.language ist als Feld vorhanden und steuert die Outbound-Sprache ab v2. *(Scope-Schnitt 12.06.: v1 DE-only; Wechsler + Fallback-UX + EN-Templates → v2 — alles i18n-ready, Nachrüsten ohne Refactoring.)*
3. Alle Oberflächen- und Systemtexte laufen durch `t()` mit vollständigen Katalogen für `de/en/pl/ru/uk/hu`; aktivierte User-/Tenant-/Browserpräferenz und Empfängersprache steuern UI, Portal und Outbound kontrolliert. Jede neue Sprache bleibt bis zum dokumentierten Muttersprachler-Gate in `I18N_ENABLED_LOCALES` deaktiviert. *(CR-020 / `I18N-01`.)*
**Plans**: TBD
**UI hint**: yes
@@ -108,8 +104,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Die nutzerseitigen Plattform-Primitive stehen bereit — Dateien lassen sich an jede Entität hängen (chunked Upload, Preview inkl. HEIC→JPG) und Tasks mit Fälligkeit/Reminder an CRM-/Sales-/Projekt-Entitäten.
**Depends on**: Phase 2
**Requirements**: REQ-files-datenmodell, REQ-files-upload-preview, REQ-tasks-datenmodell, REQ-tasks-reminder-archivierung
**Source-Specs**: `_bmad-output/specs/M23-files.md`, `_bmad-output/specs/M26-tasks.md`
**Milestone-PLANs**: 7 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 4); M074 (Task-ERP-Sync) → Phase 10; Scope-Schnitt 12.06.: M054/M055 gedünnt
**Scope-Notiz:** M074 (Task-ERP-Sync) → Phase 10; M054/M055 gedünnt.
**Success Criteria** (what must be TRUE):
1. Ein Nutzer kann Dateien chunked hochladen (TUS) mit RLS auf Storage-Pfaden (S3-kompatibles Hetzner Object Storage, Infra-ADR-009); Previews (PDF→PNG, Bild→WebP, **HEIC→JPG — Pflicht für iPhone-Monteur-Fotos**) sind sichtbar. *(Scope-Schnitt 12.06.: Versionierung, Office-/Video-Previews, Resume-Upload, OCR → v2; Permissions/Sharing + Tags + Archiv-Flag bleiben.)*
2. Dateien lassen sich über FileEntityLink an Entitäten hängen; Customer-Portal-Upload ist vorbereitet.
@@ -122,10 +117,8 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Externe Systeme werden über ein einziges, typsicheres Integrations-Framework angebunden — der Vertrag, über den später Gmail, Outlook, AirCall, Signatur-Adapter (SES-Default/PandaDoc-BYOK), Legacy-Provider und KWP laufen.
**Depends on**: Phase 2
**Requirements**: REQ-apps-engine-datenmodell, REQ-apps-engine-lifecycle
**Source-Specs**: `_bmad-output/specs/M33a-apps-engine.md`
**Milestone-PLANs**: 3 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 5)
**Success Criteria** (what must be TRUE):
1. Ein Admin kann eine DataConnection über einen OAuth2-Connect-Flow (Gmail, Outlook, AirCall, optional PandaDoc-BYOK) oder API-Key-Connect (KWP, Legacy-Provider, Signatur-Adapter) in der Settings-UI herstellen.
1. Ein Admin kann eine DataConnection über einen OAuth2-Connect-Flow (Gmail, Outlook, AirCall, optional PandaDoc-BYOK, KWP) oder API-Key-Connect (Legacy-Provider, Signatur-Adapter) in der Settings-UI herstellen.
2. Die type-safe Adapter-Registry erlaubt das Registrieren neuer Connection-Typen ohne Änderung am Kern; AppSyncRun/AppSyncItem protokollieren Sync-Läufe.
3. Connection-Health-Monitoring zeigt den Status jeder Verbindung; OAuth-Tokens sind per-Tenant-DEK-verschlüsselt gespeichert (AD-8).
**Plans**: TBD
@@ -137,8 +130,6 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Ein Vertriebler kann Kontakte, Firmen und Leads als typisierte First-Class-Entitäten verwalten — mit Custom-Feldern, Tags, Activity-Stream und Duplikat-Schutz.
**Depends on**: Phase 5, Phase 4
**Requirements**: REQ-crm-datenmodell, REQ-crm-listen-views, REQ-crm-detail-views, REQ-lead-projekt-konvertierung, REQ-crm-activity-stream, REQ-crm-custom-felder, REQ-crm-duplikat-erkennung, REQ-crm-tags, REQ-crm-permissions
**Source-Specs**: `_bmad-output/specs/M01-crm-kern.md`
**Milestone-PLANs**: 5 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 6)
**Success Criteria** (what must be TRUE):
1. Alle CRM-Kernentitäten (Contact, Company, Lead, Relation, Activity, CustomField, Tag) sind typisierte Prisma-Tabellen mit RLS-Policies; der Boilerplate-Entity-Builder ist entfernt (AD-2).
2. Ein Nutzer kann Kontakt-/Firmen-Listen server-seitig filtern, sortieren, paginieren, per Bulk-Action bearbeiten und als CSV exportieren.
@@ -154,8 +145,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Eingehende Leads aus allen Quellen landen in einem Triage-Arbeitsplatz, werden automatisch angelegt, gegen Spam geschützt und sind auswertbar.
**Depends on**: Phase 6
**Requirements**: REQ-lead-inbox-liste, REQ-lead-quellen-auto-anlage, REQ-lead-status-workflow, REQ-lead-anti-spam, REQ-lead-statistiken, REQ-lead-permissions
**Source-Specs**: `_bmad-output/specs/M02-lead-inbox.md`
**Milestone-PLANs**: 4 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 7); M049 (Auto-Projekt) → Phase 8 (braucht den Projekt-Kern); P7 liefert das `lead.qualified`-Event als Extension-Point
**Scope-Notiz:** M049 (Auto-Projekt) → Phase 8 (braucht den Projekt-Kern); P7 liefert das `lead.qualified`-Event als Extension-Point.
**Success Criteria** (what must be TRUE):
1. Ein Bearbeiter sieht die Lead-Inbox mit Status-Filter, Quick-Actions, Bulk-Operationen und Real-time-Refresh.
2. Leads aus Form-Submission, eingehender Email und AirCall-Inbound werden automatisch angelegt und stoßen Automation-Trigger an (sofern Automation aktiv).
@@ -171,8 +161,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Ein Vertriebler führt Projekte durch mehrere SHK-Pipelines (Sales-Sicht) mit konfigurierbarem Kanban, Forecast und feingranularer Field-Level-Sichtbarkeit von Volumen-Daten — ein `Projekt`-Kern, „Deal" ist nur der Pipeline-Typ.
**Depends on**: Phase 7
**Requirements**: REQ-projekt-kern-datenmodell, REQ-pipeline-rechte-config, REQ-projekt-kanban-listen-view, REQ-projekt-pipeline-wechsel, REQ-projekt-forecast-kpis
**Source-Specs**: `_bmad-output/specs/M03-sales-pipeline.md`
**Milestone-PLANs**: 7 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 8); inkl. M049 (Auto-Projekt, aus Phase 7 hierher)
**Scope-Notiz:** M049 (Auto-Projekt) wurde aus Phase 7 hierher verschoben.
**Success Criteria** (what must be TRUE):
1. Der `Projekt`-Kern (typisierte Superset-Tabelle + CustomFields) existiert mit fortlaufenden Projekt-Nummern (HiveNumberSeq); mehrere Pipelines (Pipeline mit typ_hint sales/auftrag/custom, PipelineStage = Status, Verlust-/Gewinn-Gründe) sind als geseedete SHK-Pipelines konfigurierbar.
2. Ein Nutzer kann Projekte im konfigurierbaren Kanban per Drag-&-Drop verschieben (mit Stage-Wechsel-Validation) oder in der Listen-View mit Filter/Bulk-Actions bearbeiten; Updates kommen in Real-Time (SSE, AD-9).
@@ -188,8 +177,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Ein gewonnenes Projekt erhält in der Auftrags-Pipeline-Sicht seine Auftrags-Features — Plantafel-Scheduling pro Monteur, Sub-Areas (inkl. Rechnung-Sub-Entity v1) und eine digitale, offline-fähige Abnahme auf der Baustelle (kein neuer Datensatz, nur Pipeline-Wechsel).
**Depends on**: Phase 8
**Requirements**: REQ-projekt-sub-areas, REQ-rechnung-sub-entity, REQ-projekt-abnahme
**Source-Specs**: `_bmad-output/specs/M04-auftragspipeline.md`
**Milestone-PLANs**: 6 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 9); Scope-Schnitt 12.06.: M070 gedünnt — Lagerist-Sicht/Material-Ausgang → v2 (Material-Listen am Auftrag bleiben; Noah-Frage auf E-Liste)
**Scope-Notiz:** M070 gedünnt — Lagerist-Sicht/Material-Ausgang → v2; Material-Listen am Auftrag bleiben.
**Success Criteria** (what must be TRUE):
1. Die Auftrags-Welt ist eine Pipeline-View auf denselben `Projekt`-Kern (kein separates Project-/ProjectPipeline-Objekt, kein Won-Handoff — das Projekt wechselt nur die Pipeline und erhält Auftrags-Felder); Sub-Areas am Projekt: Termine, **Rechnung = neues Sub-Entity v1 (HiveNumberSeq)**, Checklisten, Aufgaben, Aktivitäten, Dokumente, ProjektMitglied/Monteure.
2. Ein Disponent kann auf einer Plantafel Aufträge pro Monteur/Tag einplanen; die Ansicht ist offline-fähig.
@@ -199,30 +187,40 @@ Decimal phases appear between their surrounding integers in numeric order.
### Phase 10: KWP-Integration — **→ v2 (KOMPLETT DEFERRED, 2026-06-12 — ERSTES v2-Modul)**
> 🔴 **Scope-Schnitt #12 (Kalender-Realität):** KWP-API-Zugang lt. Hersteller-Mail erst ~**19.07.** — nach dem v1-Launch (~10.07.). KWP bleibt USP; v2 startet damit. **Sofort erledigt:** Callback-URL gemeldet (`https://app.hivegrid.de/integrations/kwp/oauth/callback`, PKCE-Flow), bnWin.net-Update 8.1 N3 bei Geerkens angestoßen. v1 behält Apps-Engine + Extension-Points (Auftrag/Abnahme/Material). Beschreibung unten gilt für die v2-Planung.
> 🔴 **Scope-Schnitt #12 (historischer Kalenderentscheid):** Der ursprünglich erst für ~19.07. angekündigte KWP-Zugang lag nach dem damaligen v1-Launch-Ziel; KWP blieb deshalb v2. **Update 12.07.:** OIDC-Discovery, dynamische Relay-Auflösung, tenant-spezifischer OpenAPI-Vertrag und Produktions-/Staging-Redirect sind verifiziert. Runtime-Token/Scopes und der Vertrag zum Anlegen eines neuen Auftrags bleiben extern blockiert. v1 behält Apps-Engine + Extension-Points (Auftrag/Abnahme/Material). Beschreibung unten gilt für Phase 32.
**Goal**: HiveGrid synchronisiert Auftrags- und Stammdaten bidirektional mit dem im SHK-Markt verbreiteten ERP KWP (Kernsystem des Erstkunden) — über die offizielle KWP-API als DataConnection, mit Schema-Drift-Schutz. Damit ist die Kette Lead → Sales → Auftrag → KWP durchgängig.
> 🟢 **Superseding Scope 2026-07-22 (AD-32/CR-003):** Der Auth-/Resource-/Refresh-Dauerbetrieb ist bewiesen.
> Der folgende historische Zielstand wird für die aktuelle Phase 32 auf read-only KWP → HiveGrid geschnitten.
> M091, M094-outbound, M074-outbound und Project-/Auftrag-Create bleiben hinter `VEXT-6` + erneuter Freigabe
> geparkt und blockieren den read-only Pfad nicht.
**Goal**: HiveGrid bindet das im SHK-Markt verbreitete ERP KWP (Kernsystem des Erstkunden) über die
offizielle KWP-API als DataConnection an. Der initiale Scope liest Auftrags- und Stammdaten KWP → HiveGrid
und schützt den Inbound-Pfad gegen Schema-Drift; HiveGrid mutiert keine KWP-Ressource.
**Depends on**: Phase 9, Phase 5
**Requirements**: REQ-kwp-datenmodell, REQ-kwp-architektur, REQ-kwp-schema-drift
**Source-Specs**: `_bmad-output/specs/M19-kwp-integration.md` (⚠ M089–M095-Recut — siehe Phase-Note)
**Milestone-PLANs**: 8 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 10); inkl. M074 (Task-ERP-Sync, aus Phase 4 hierher)
**Scope-Notiz:** M074 (Task-ERP-Sync) wurde aus Phase 4 hierher verschoben.
**Success Criteria** (what must be TRUE):
1. KWP ist als `DataConnection type='rest-api'` in der Apps-Engine angebunden; keine KWP-DB-Credentials liegen in der Cloud (KwpSettings, KwpRegistry, KwpProjectQueue, KwpApiKey).
2. Auftrags-/Stammdaten fließen bidirektional zwischen HiveGrid und KWP; bei Konflikten gilt „KWP gewinnt" (AD-14/AD-17).
3. Ein Schema-Drift-Sentinel erkennt MSSQL-Schema-Änderungen per Snapshot-Vergleich (KwpSchemaSnapshot) und benachrichtigt den Tenant-Admin.
1. KWP ist als `App(key='kwp', connectionType='oauth2')` mit tenant-spezifischer `DataConnection` in der Apps-Engine angebunden; Kundenkürzel und OAuth-Material liegen per Tenant-DEK verschlüsselt in `DataConnection.credentialsCiphertext`, der Relay-Host wird dynamisch aufgelöst.
2. Die im KWP-Vertrag freigegebenen Auftrags-/Stammdaten fließen read-only KWP → HiveGrid; bei
Inbound-Konflikten gilt „KWP gewinnt" (AD-14/AD-17). Project-/Auftrag-Create und sonstiger Writeback
sind hinter `VEXT-6` + erneuter Freigabe geparkt.
3. Ein API-Contract-Sentinel erkennt Drift per OpenAPI-Fingerprint und endpoint-spezifischer Response-Validierung und benachrichtigt den Tenant-Admin; einheitliche KWP-Versionsfelder werden nicht vorausgesetzt.
**Plans**: TBD
**Note**: M089-M095-Recut bindend — das offizielle KWP-API macht das Windows-Sync-Programm M089 obsolet (M090/091/092/094/095 vereinfachen sich, M093 bleibt). M089-M095 sind in der Plan-Phase neu zu schneiden, bevor Code entsteht; die alte kwpsync.exe-Drei-Komponenten-Architektur aus der M19-Spec ist NICHT zu bauen. KWP bleibt Backend-Sync ohne eigene UI (kein UI hint).
**Note**: M089-M095-Recut bindend — der historische Bezeichner M089 wird als API-Connector weitergeführt; nur
das ursprünglich dahinter geplante Windows-Sync-Programm ist obsolet. M091 und alle Outbound-Anteile sind
geparkt. Die alte kwpsync.exe-Drei-Komponenten-Architektur aus der M19-Spec ist NICHT zu bauen. Setup-,
Health-, Sync-Log- und Konflikt-Oberflächen sind im Designer-Brief P32 beschrieben.
### Phase 11: Globale Suche & Dashboard
**Goal**: Ein Nutzer findet jede Entität per Hotkey über das gesamte System und sieht seine Kennzahlen in einem rollenbasierten Widget-Dashboard.
**Depends on**: Phase 9
**Requirements**: REQ-suche-datenmodell, REQ-suche-hybrid, REQ-suche-ui, REQ-dashboard-datenmodell, REQ-dashboard-widgets
**Source-Specs**: `_bmad-output/specs/M24-globale-suche.md`, `_bmad-output/specs/M20-dashboard.md`
**Milestone-PLANs**: 5 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 11); Scope-Schnitt 11.06.: Custom-Widgets (M149) + Export (M150) → v2; 12.06.: M147 gedünnt (feste Rollen-Layouts)
**Scope-Notiz:** Custom-Widgets (M149) + Export (M150) → v2; M147 gedünnt; Suche = Spotlight-Overlay ohne nutzerseitige `/search`-Vollseite.
**Success Criteria** (what must be TRUE):
1. Self-hosted Meilisearch liefert permission-aware Keyword-Treffer über den SearchAdapter. Kein pgvector/RAG/Embedding in v1/v2 nach AD-26.
2. Entity-Mutationen aktualisieren den Index über das Outbox-Pattern; SearchIndexEntry und RecentSearch sind befüllt.
3. Ein Nutzer öffnet per Cmd+K ein debounced Such-Modal mit RecentSearch und kann in eine Vollbild-Such-View wechseln.
3. Ein Nutzer öffnet die debounced Spotlight-Suche mit RecentSearch per Cmd+K/Ctrl+K oder Header-Suchsymbol; Desktop zeigt ein Modal, Mobile ein viewportfüllendes Overlay. Eine nutzerseitige `/search`-Seite existiert nicht; `/search/api` bleibt interner Resource-Endpunkt.
4. Ein Nutzer sieht ein rollenbasiertes Dashboard (3 feste Rollen-Layouts GF/Büro/Monteur, SHK-Default geseedet) mit Widgets aus Sales, Projekte, Tasks und HR. *(Scope-Schnitt 12.06.: Drag&Drop-Grid + User-Layout-Persistenz → v2; KI-Widgets → Backlog/v3 nach AD-26.)*
5. Dashboard-Widgets aktualisieren sich live (WebSocket/SSE) mit Aggregat-Cache.
**Plans**: TBD
@@ -232,10 +230,8 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Die erste USP-Säule steht in voller Tiefe (AD-16): ein visueller Automation-Editor über alle Module mit vollständiger Trigger-/Action-Library, Guards, Dry-Run und 24h-Undo. Sprach-zu-Automation entfällt nach AD-26.
**Depends on**: Phase 11
**Requirements**: REQ-automation-datenmodell, REQ-automation-trigger-library, REQ-automation-action-library, REQ-automation-flow-editor, REQ-automation-schutz
**Source-Specs**: `_bmad-output/specs/M17-automation-engine.md`
**Milestone-PLANs**: 8 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 12)
**Success Criteria** (what must be TRUE):
1. Ein Nutzer baut im Graph-Editor Flows aus der vollständigen Trigger-Library (CRM, Sales, Projekte, Email, Forms, Kalender, Zeit, Webhooks) und Action-Library (CRM, Notifications, HTTP, Tasks, If/Else, Delay, Loop; KWP-Push registriert sich mit v2-P10 nach — Registry ist erweiterbar gebaut).
1. Ein Nutzer baut im Graph-Editor Flows aus der vollständigen Trigger-Library (CRM, Sales, Projekte, Email, Forms, Kalender, Zeit, Webhooks) und Action-Library (CRM, Notifications, HTTP, Tasks, If/Else, Delay, Loop). Die Registry bleibt für einen möglichen KWP-Writeback erweiterbar; eine ausführbare KWP-Push-Action darf erst nach `VEXT-6` und erneuter ausdrücklicher Produktfreigabe registriert werden (AD-32/CR-003).
2. Ein Nutzer erstellt eine Automation im visuellen Editor, testet sie als Dry-Run und kann Ausführungen innerhalb von 24h zurückrollen.
3. Loop-Guard, Rate-Limit, Idempotenz-Key, Resume-Mode und Trigger-Volumen-Metering pro Tenant verhindern Runaway-Automationen.
4. AutomationRule (JSON-Graph), AutomationExecution, AutomationStepExecution und AutomationTemplate persistieren Flows und Läufe nachvollziehbar.
@@ -243,12 +239,10 @@ Decimal phases appear between their surrounding integers in numeric order.
**UI hint**: yes
### Phase 13: KI-Layer
> ⛔ **KI→MCP-Pivot ([[AD-26]]): Phase 13 (KI-Layer) entfällt in v1; Phase 25 (HiveMind/RAG) zurückgestellt → ersetzt durch MCP-Server ([[VR-MCP]]).** HiveGrid hostet kein eigenes LLM/RAG/Whisper mehr, sondern stellt seine Daten/Aktionen als Remote-MCP-Server externen KI-Clients bereit. Tickets R-P13/D-P13/EXT-11 sowie die Milestones M083–M086/M088 sind gelöscht. Success-Criteria unten sind **überholt** und nur historisch erhalten.
> ⛔ **KI→MCP-Pivot ([[AD-26]]): Phase 13 (KI-Layer) entfällt in v1; Phase 25 (HiveMind/RAG) zurückgestellt → ersetzt durch MCP-Server ([[VR-MCP]]).** HiveGrid hostet kein eigenes LLM/RAG/Whisper mehr, sondern stellt seine Daten/Aktionen als Remote-MCP-Server externen KI-Clients bereit. Tickets R-P13/D-P13/EXT-11 sowie die historischen Scope-IDs M083–M086/M088 sind gestrichen. Success-Criteria unten sind **überholt** und nur historisch erhalten.
**Goal**: ~~Der EU-only KI-Unterbau steht produktiv: Multi-Provider-LLM-Gateway mit Kostenschutz und die Sprach-zu-Automation als exklusives Automation-Feature.~~ *(Scope-Schnitt 11.06.: HiveMind/RAG, Whisper, AlephAlpha → v2 — v1 baut die Andock-Adapter.)* **→ entfällt, siehe Pivot-Banner.**
**Depends on**: Phase 12
**Requirements**: ~~REQ-ki-llm-gateway~~ → entfernt ([[AD-26]]); ersetzt durch `REQ-mcp-server`
**Source-Specs**: ~~`_bmad-output/specs/M18-ki-layer.md`~~ (KI-Layer entfällt — [[AD-26]])
**Milestone-PLANs**: ~~5 PLANs in `docs/milestones/`~~ → M083–M086/M088 gelöscht ([[AD-26]])
**Success Criteria** ~~(what must be TRUE)~~ — **überholt durch [[AD-26]]**:
1. ~~Das EU-LLM-Gateway (Mistral La Plateforme primär, Provider-Abstraktion — zweiter EU-Provider folgt v2; Infra-Wechsel 12.06.: Scaleway entfällt) trackt Tokens und bucht gegen das lokale AiCredits-Konto; harte Limits + Drossel greifen; keine US-Kern-Abhängigkeit.~~
2. ~~Sprach-zu-Automation (M086) läuft EXKLUSIV im Automation-Kontext: Satz → visueller Flow-Vorschlag mit Rückfragen + Existenz-Prüfungen; aktiviert nie selbst.~~
@@ -261,8 +255,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Der Betrieb arbeitet seinen Email-Verkehr direkt in HiveGrid ab — bidirektionale Gmail/Outlook-Inbox mit CRM-Matching — und versendet DSGVO-konforme Marketing-Kampagnen.
**Depends on**: Phase 6, Phase 5
**Requirements**: REQ-email-datenmodell, REQ-marketing-datenmodell, REQ-marketing-double-optin, REQ-marketing-versand
**Source-Specs**: `_bmad-output/specs/M09-email-inbox.md` (nur Sende-Domain/Inbound-Teile; OAuth-Sync → v2), `_bmad-output/specs/M10-email-marketing.md`
**Milestone-PLANs**: 6 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 14); Scope-Schnitt 11.06.: M096–M098 (Postfach-Sync) → v2
**Scope-Notiz:** M096–M098 (Postfach-Sync) → v2.
**Success Criteria** (what must be TRUE):
1. Die Sende-Domain pro Mandant ist verifiziert (DKIM/SPF/DMARC, Auto-Probe); Mails aus HiveGrid (Automation, Marketing, manuell) gehen über Mailjet raus und erscheinen am Kontakt.
2. Eingehende Mails an die Tenant-Inbound-Adresse erzeugen Leads/Aktivitäten; die **BCC-Logging-Brücke** protokolliert in Gmail/Outlook geschriebene Mails am Kontakt (kein OAuth nötig).
@@ -275,8 +268,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Telefonie und interne Kommunikation laufen in HiveGrid — Click-to-Call/Inbound über AirCall mit Auto-Lead-Anlage und Real-Time-Team-Chat mit entity-linked Channels.
**Depends on**: Phase 6, Phase 5
**Requirements**: REQ-telefonie-datenmodell, REQ-telefonie-provider-adapter, REQ-chat-datenmodell, REQ-chat-realtime, REQ-chat-features
**Source-Specs**: `_bmad-output/specs/M12-telefonie.md`, `_bmad-output/specs/M13-team-chat.md`
**Milestone-PLANs**: 9 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 15); Scope-Schnitt 11.06.: HalloPetra (M105) → v2
**Scope-Notiz:** HalloPetra (M105) → v2.
**Success Criteria** (what must be TRUE):
1. Click-to-Call und Inbound-Anrufe laufen über den AirCall-Adapter (Apps-Engine-Connection, verschlüsselte OAuth-Tokens); unbekannte Nummern legen automatisch einen Lead an; Anruf-Events stehen als Automation-Trigger bereit (verpasster Anruf → Rückruf-Aufgabe).
2. Team-Chat bietet Real-Time-Messaging (WebSocket, Presence, Typing, Read-Receipts, Redis-Pub/Sub) für drei Channel-Typen (public, private, entity-linked), AD-9.
@@ -289,8 +281,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Termin- und Dokument-Workflows sind abgedeckt — bidirektionaler Kalender-Sync, öffentliche Buchungsseiten, ein Drag-&-Drop-Form-Builder und Multi-Signer-Angebots-Signatur.
**Depends on**: Phase 7, Phase 5
**Requirements**: REQ-kalender-datenmodell, REQ-kalender-sync-adapter, REQ-booking-datenmodell, REQ-booking-slot-kalkulierung, REQ-booking-integrationen, REQ-form-datenmodell, REQ-form-editor, REQ-form-actions, REQ-signatur-datenmodell, REQ-signatur-provider
**Source-Specs**: `_bmad-output/specs/M25-calendar-sync.md`, `_bmad-output/specs/M06-booking.md`, `_bmad-output/specs/M05-form-builder.md`, `_bmad-output/specs/M07-angebot-signatur.md`
**Milestone-PLANs**: 15 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 16); Scope-Schnitt 12.06.: M122 gedünnt — personalisierte Links + JS-Snippet → v2 (URL/QR/iFrame bleiben); M129 bleibt explizit voll
**Scope-Notiz:** M122 gedünnt — personalisierte Links + JS-Snippet → v2; URL/QR/iFrame bleiben. M129 bleibt vollständig.
**Success Criteria** (what must be TRUE):
1. Kalender synchronisiert bidirektional mit **Google** (CalendarAdapter, Auto-Token-Refresh, Webhook-Subscriptions) und legt HiveGrid-Termine an. *(Scope-Schnitt 11.06.: Outlook-Adapter → v2; Interface ist provider-agnostisch gebaut. Booking: eine Zuteilungs-Strategie „Erster der frei ist", Round-Robin/Wahl → v2.)*
2. Öffentliche Booking-Seiten berechnen Slots timezone-aware (Verfügbarkeitsregeln, Ausnahmen, Kalender-Sync, Puffer) und legen nach Buchung Lead, Activity und Bestätigungs-Email an (iFrame-Embed).
@@ -303,8 +294,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Interne Personalprozesse sind in einem verschlüsselten HR-Hub abgedeckt — Personalakten, Passwort-Safe und Urlaubs-/Krank-Workflow.
**Depends on**: Phase 4
**Requirements**: REQ-hr-datenmodell, REQ-hr-passwort-safe, REQ-hr-urlaub-krank
**Source-Specs**: `_bmad-output/specs/M14-hr-hub.md`
**Milestone-PLANs**: 7 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 17); Scope-Schnitt 11.06.: Memberspot/Boobora (M138) → v2; Surveys bleiben
**Scope-Notiz:** Memberspot/Boobora (M138) → v2; Surveys bleiben.
**Success Criteria** (what must be TRUE):
1. HR-Profile, Urlaubs-/Krank-/Payslip-/Request-Daten liegen AES-256-GCM-verschlüsselt vor; sensible Felder nutzen KMS-backed Envelope-Encryption (AD-8).
2. Jeder Mitarbeiter hat einen verschlüsselten Passwort-Safe mit Audit-Trail und DSGVO-Export.
@@ -315,9 +305,8 @@ Decimal phases appear between their surrounding integers in numeric order.
### Phase 18: Customer-Portal — **→ v2 (deferred 2026-06-11)**
**Goal**: *(v2)* Getrenntes Endkunden-Portal mit Magic-Link und freigegebener Projekt-Sicht. AD-18 revidiert — komplette Phase nach v2 verschoben; Phasen-Nummer bleibt reserviert.
**Depends on**: — (v2-Planung)
**Requirements**: *(→ v2: REQ-portal-datenmodell, REQ-portal-auth-magic-link, REQ-portal-projekt-sicht)*
**Source-Specs**: `_bmad-output/specs/M15-customer-portal.md`
**Milestone-PLANs**: 0 in v1 (M141–M146 → v2)
**Requirements**: *(→ v2: REQ-portal-datenmodell, REQ-portal-auth-magic-link, REQ-portal-projekt-sicht; durch AD-30/CR-001 ergänzt um REQ-portal-runtime-isolation, REQ-portal-commercial-access, REQ-portal-custom-domain)*
**Scope-Notiz:** M141–M146 liegen in v2.
**v1-Andockpunkte (bleiben):** P4-Portal-Upload-Vorbereitung (FileEntityLink), `portal.hivegrid.de` im P1-URL-Schema.
**Plans**: — (v2)
@@ -325,8 +314,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Die Plattform ist aus einer getrennten Admin-Welt betreibbar — Tenant-Management, Subscription-Overrides, Feature-Flag-Verwaltung (UI zur Engine aus Phase 1), Queue-Monitoring und Support-Inbox.
**Depends on**: Phase 2
**Requirements**: REQ-plattform-admin-identität, REQ-plattform-admin-features
**Source-Specs**: `_bmad-output/specs/M37-plattform-admin.md`, `_bmad-output/specs/M32-feature-flags.md` (Admin-UI-Teile)
**Milestone-PLANs**: 7 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 19); Scope-Schnitt 11.06.: M033 (Flag-Massen-Statistik) + M040 (Plattform-Lead-Pipeline) → v2; 12.06.: M038/M039 (getrennte AdminUser-Identität) → v2, M035 gedünnt. **Neu:** Admin stellt Tenant-Abos zusammen (Konnektoren schalten + Legacy-Provider-Positionen — Abo-Baukasten-Mechanik; Self-Service-UI → v2)
**Scope-Notiz:** M033 (Flag-Massen-Statistik) + M040 (Plattform-Lead-Pipeline) → v2; M038/M039 (getrennte AdminUser-Identität) → v2, M035 gedünnt. **Aktueller Billing-Vertrag:** Admin verwaltet lokale Plans/Seats/Entitlements und die Lago-/Mollie-Referenzen; Customer-Self-Service bleibt ausserhalb v1.
**Success Criteria** (what must be TRUE):
1. Ein Plattform-Admin meldet sich auf `admin.hivegrid.de` an (Host-Routing auf die Admin-Routen, **Cookie-Domain-Trennung** zu app.hivegrid.de, TOTP-Pflicht + MFA-Step-up); Admin-User haben **keinen Tenant-Workspace** und erscheinen in keiner Mandanten-Mitgliederliste; kein Generalschlüssel zwischen Plattform und Mandanten. *(Scope-Schnitt 12.06.: getrennte AdminUser-Identität/AdminRBAC-Parallelwelt = M038/M039 → v2; v1 nutzt Boilerplate-Modell User-Extension + `admin-mfa-gate`.)*
2. Ein Admin verwaltet Tenants, Subscription-Overrides und Feature-Flags aus einer zentralen Konsole; das Admin-Dashboard zeigt die Boilerplate-KPIs (Tenants/User/MRR). *(Churn/ARPU/Health-Kacheln → v2.)*
@@ -335,16 +323,15 @@ Decimal phases appear between their surrounding integers in numeric order.
**UI hint**: yes
### Phase 20: Billing, Onboarding & Branding
**Goal**: Ein neuer Betrieb kommt vom Self-Service-Signup per Auto-SHK-Provisionierung ins Produkt (Wizard-UI → v2), läuft auf Legacy-Provider-Billing und kann sein Theme wählen.
**Goal**: Ein neuer Betrieb kommt vom Self-Service-Signup per Auto-SHK-Provisionierung ins Produkt (Wizard-UI → v2) und nutzt den lokalen HiveGrid-Billing-State mit Lago fuer Billing/Invoicing und Mollie fuer Payments.
**Depends on**: Phase 19, Phase 6
**Requirements**: REQ-billing-datenmodell, REQ-billing-trial-dunning, REQ-onboarding-demo-daten, REQ-branding-theme-phase1
**Source-Specs**: `_bmad-output/specs/M28-subscriptions-billing.md` (⚠ M154-Recut: Abo-Baukasten statt Seat-Typen), `_bmad-output/specs/M29-onboarding.md` (Wizard-UI → v2), `_bmad-output/specs/M31-branding.md`; **Legacy-Referenz:** `archive/hivegrid-cloud/app/config/pricing-plans.ts`
**Milestone-PLANs**: 8 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 20); Scope-Schnitt 11.06.: M157 (Wizard-UI) → v2; 12.06.: M030 + M160 gedünnt
**Scope-Notiz:** M157 (Wizard-UI) → v2; M030 + M160 gedünnt.
**Success Criteria** (what must be TRUE):
1. Billing läuft über Legacy-Provider als **Abo-Baukasten**: Basis-Preis pro Nutzer + Feature-Module als daten-getriebene Positionen (keine Seat-Typen — M154-Recut); Trial mit Dunning (Tag 1/3/7) und Frozen-Modus (Read-Only-Middleware) greift; konkrete Preise geparkt (AD-15, Kostenmatrix folgt). Verbrauchs-Zähler + Drossel aktiv, Aufschlags-Abrechnung → v2.
1. Billing nutzt **HiveGrid-Entitlements + Lago-Billing-State + Mollie-Payment-State** fuer Plans und Seats; Trial mit Dunning (Tag 1/3/7) und Frozen-Modus (Read-Only-Middleware) greift. Verbrauchs-Zähler dienen nur der Limit-Transparenz; Usage-Billing bleibt ausserhalb v1.
2. Ein neuer Tenant wird nach Signup automatisch SHK-provisioniert (Seeds M158, ohne Wizard-UI — die folgt v2); Trial-Freischaltung durch Plattform-Admin (wie spec'd).
3. Optionale Demo-Daten (Kontakte, Projekte in Sales-/Auftragssichten, Tasks) lassen sich per Settings-Knopf provisionieren und via is_demo_data-Flag löschen. *(Scope-Schnitt 12.06. + AD-26: KI-Walkthrough entfällt; einfaches Löschen statt Multi-Step-Bulk.)*
4. Ein Nutzer schaltet zwischen Hell und Dunkel um, flash-frei (SSR-Cookie). *(Scope-Schnitt 12.06.: kein System-Modus — bewusst nur 2 Optionen; `next-themes` aus Boilerplate.)*
4. Der Light/Dark-Unterbau bleibt erhalten, der Toggle ist aber vorerst deaktiviert (`DARK_MODE_IN_APP=false`), solange keine produktiv freigegebene Theme-Funktion angeboten wird. *(PR #81, 2026-07-11.)*
**Plans**: TBD
**UI hint**: yes
@@ -352,10 +339,8 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Der DSGVO-Lebenszyklus ist abgedeckt und die Plattform launch-fertig. Damit ist der Big-Bang-Launch (AD-19) auslösbar. *(Scope-Schnitt 11.06.: Public-API, Mobile-PWA-Ausbau, Help-Center/Desk, DSGVO-Auskunfts-Tooling → v2.)*
**Depends on**: Phase 20, Phase 10, Phase 4
**Requirements**: REQ-dsgvo-export, REQ-dsgvo-tenant-deletion, REQ-feedback-widget
**Source-Specs**: `_bmad-output/specs/M35-dsgvo-export.md` (M34/M36/M38/M39 → v2)
**Milestone-PLANs**: 2 PLANs in `docs/milestones/` → siehe `.planning/PHASE-SOURCES.md` (Phase 21)
**Success Criteria** (what must be TRUE):
1. Ein Nutzer kann einen DSGVO-ZIP-Export (72h-signed-URL) anstoßen; eine Tenant-Löschung führt Crypto-Shredding (Per-Tenant-DEK), Legacy-Provider-Cancel und Storage/Cache-Bereinigung durch (AD-8).
1. Ein Nutzer kann einen SSE-C-verschlüsselten DSGVO-ZIP-Export mit authentifiziertem, bis zu 72 h verfügbarem `200`-App-Download anstoßen; direkter Storage-Zugriff ohne Customer-Key scheitert. Eine Tenant-Löschung führt Crypto-Shredding (Per-Tenant-DEK), Billing-Cancel über die Lago-/Mollie-/HiveGrid-Gateways und Storage/Cache-Bereinigung durch (AD-8).
2. DSGVO-Auskunft funktioniert als dokumentiertes manuelles Playbook: Suche → Kontakt-Detail (Activity-Stream) → CSV-Export → Anwalts-Vorlage → Frist-Task (+25 Tage). AVV-Vorlage liegt vor (Externals E6).
3. Das In-App-Feedback-Widget (Bug/Feature/Frage, Screenshot, Rate-Limit) ist live und speist die Admin-Support-Inbox (P19, generische Quelle); eine Minimal-FAQ-Seite existiert.
4. Monteure arbeiten mobil über die PWA/responsive Web-App (mobile-first Screens + P9-Offline) — der PWA-Ausbau (Installierbarkeit/Web-Push) folgt v2; ein nativer Client ist nicht vorgesehen (AD-17, PWA-only).
@@ -371,8 +356,7 @@ Decimal phases appear between their surrounding integers in numeric order.
### Phase 22: Public-API & Webhooks (v2)
**Goal**: Externe Systeme lesen HiveGrid-Hauptentitäten per versionierter REST-API und empfangen/senden Events über signierte Webhooks.
**Depends on**: Phase 2 (ApiKey-Modell), Phase 12 (Automation `external_event`-Trigger)
**Milestones**: M161, M162, M163, M027
**Source-Specs**: `_bmad-output/specs/M34-public-api.md`
**Historische Scope-IDs**: M161, M162, M163, M027
**Success Criteria** (what must be TRUE):
1. GET contacts/companies/deals/projects/tasks/leads — cursor-paginiert, Filter/Sort/Sparse-Fieldsets/Embed (Tiefe 1); `read_only`-Scope lässt sensible Felder aus (nicht 403).
2. Eingehende Lead-Webhooks legen Leads an (API-Key/HMAC/URL-Token + Payload-Mapping + Auto-Match); ausgehende Subscriptions HMAC-signiert mit Idempotenz, Retry/Backoff, Auto-Disable nach 10 Fehlern.
@@ -383,8 +367,7 @@ Decimal phases appear between their surrounding integers in numeric order.
### Phase 23: Postfach-Sync (Email-Inbox) (v2)
**Goal**: Gmail/Outlook-Postfächer werden bidirektional ins CRM gespiegelt, auto-gematcht und im Activity-Stream sichtbar.
**Depends on**: Phase 5 (Apps-Engine/Provider-Pattern), Phase 6 (CRM-Matching), Phase 14 (Sende-Domain — nicht neu bauen)
**Milestones**: M096, M097, M098
**Source-Specs**: `_bmad-output/specs/M09-email-inbox.md` (OAuth-Sync/Inbox/Threading-Teile)
**Historische Scope-IDs**: M096, M097, M098
**Success Criteria** (what must be TRUE):
1. OAuth-Connect Gmail (Pub/Sub-Watch) + Microsoft (Graph-Subscription, 3-Tage-Renewal-Worker); Push-Sync, Initial-Sync 90 Tage resumebar.
2. Auto-Match (From-Adresse, Subject-Pattern `[Projekt #123]`, 1-offenes-Projekt-Heuristik) mit manuellem Override; Inbox-Liste + Detail mit Thread, sicherem HTML-Render, Reply/Forward.
@@ -394,13 +377,12 @@ Decimal phases appear between their surrounding integers in numeric order.
**Risiko**: Gmail restricted scopes → Google-Verifizierung/CASA (Antrag lief in v1 EXT-13); Graph-Subscription-Renewal kritisch.
### Phase 24: Self-Service-Billing & Onboarding-Wizard (v2)
**Goal**: Tenants buchen/wechseln Pläne self-service über Web-Checkout und durchlaufen einen branchen-getriebenen Onboarding-Wizard.
**Depends on**: Phase 20 (Legacy-Provider/Billing-Fundament)
**Goal**: Tenants buchen/wechseln Pläne und pauschale Add-ons self-service über Web-Checkout und durchlaufen einen branchen-getriebenen Onboarding-Wizard.
**Depends on**: Phase 20 (HiveGrid-Entitlements sowie Lago-/Mollie-Billing-Fundament)
**Retro-Integration**: Kein KI-Walkthrough-Coach nach AD-26; Phase 25 liefert MCP-Server statt eigenem LLM/Coach.
**Milestones**: M157 (+ M28-Self-Service-Delta, Block P)
**Source-Specs**: `_bmad-output/specs/M28-subscriptions-billing.md` (Block P), `M29-onboarding.md`
**Historische Scope-IDs**: M157 (+ M28-Self-Service-Delta, Block P)
**Success Criteria** (what must be TRUE):
1. Self-Service-Trial ohne Vertriebs-Freigabe (Zahlungsmethode-Pflicht); Plan-Wechsel/Add-Ons über Web-Checkout (PWA-only → kein App-Store, keine Store-Billing-Auflage).
1. Self-Service-Trial ohne Vertriebs-Freigabe (Zahlungsmethode-Pflicht); Plan-Wechsel/Add-Ons über Web-Checkout (PWA-only → kein App-Store, keine Store-Billing-Auflage). Pauschale Monats-Add-ons und einmalige Einrichtungspositionen werden unterstützt; kein Usage-Metering. Das Portal nutzt diesen Vertrag über `VA-P26c`.
2. Onboarding-Wizard resumebar, Step-Validierung, Rückwärts-Block nach irreversiblen Actions.
3. SHK-Branchen-Template (Pipelines/Rollen/Felder/Forms/Demo/Checkliste) deklarativ geseedet; Erste-Schritte-Checkliste + Demo-Daten-Bulk-Löschung.
**Plans**: TBD
@@ -412,7 +394,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Externe KI-Clients können HiveGrid-Daten über tenant-gescopete Read-Ressourcen lesen und freigegebene Schreib-Aktionen über bestätigungspflichtige Action-Tools ausführen.
**Depends on**: Phase 22 (API-Key/Auth/Scopes/Rate-Limit), Phase 2 (Tenant/RLS), Phase 1 (Audit/Permissions)
**Retro-Integration**: Help-Artikel und andere Daten können optional als MCP-Resources exponiert werden; keine RAG-/Embedding-Pipeline.
**Milestones**: [[VR-MCP]] / [[VD-MCP]] (kein M0xx-Milestone)
**Ticket-Scope**: [[VR-MCP]] / [[VD-MCP]] (keine historische M0xx-ID)
**Source-Specs**: [[VR-MCP]] / [[VD-MCP]] · [[AD-26]]
**Success Criteria** (what must be TRUE):
1. Remote-MCP-Server mit Streamable HTTP und `@modelcontextprotocol/sdk` exponiert Read-Ressourcen für Hauptentitäten.
@@ -423,22 +405,24 @@ Decimal phases appear between their surrounding integers in numeric order.
**Constraint**: ~~ausschließlich EU-Provider (DSGVO), AVV mit allen Providern.~~ → MCP: kein LLM-Hosting, daher kein Provider-AVV; Tenant-Scope/RLS + API-Key-Auth gelten.
### Phase 26: Customer-Portal (v2) ⭐ *(ex-P18)*
**Goal**: Endkunden sehen über eine eigene Auth-Schicht ihre Projekte/Status/Dokumente, laden Dateien hoch, erhalten Auto-Status-Mails. **Kritisch** — wenn der Sprint im Plan liegt, in v2 liefern.
**Depends on**: Phase 4 (FileEntityLink — in v1 vorbereitet), Phase 6 (CRM/Project), Phase 9 (Project-Stages/Acceptance), Phase 14 (Sende-Domain)
**Milestones**: M141, M142, M143, M144, M145, M146
**Source-Specs**: `_bmad-output/specs/M15-customer-portal.md`
**Goal**: Endkunden sehen über eine eigene Auth-Schicht ihre Projekte/Status/Dokumente, laden Dateien hoch, erhalten Auto-Status-Mails und erreichen das Portal über `portal.hivegrid.de/<tenant>` oder optional eine verifizierte Kundendomain. **Kritisch** — wenn der Sprint im Plan liegt, in v2 liefern.
**Depends on**: Phase 1 (Host-/Route-Contract), Phase 4 (FileEntityLink — in v1 vorbereitet), Phase 6 (CRM/Project), Phase 9 (Project-Stages/Acceptance), Phase 14 (Sende-Domain), Phase 20/24 (Entitlements + pauschale Add-on-/Einmal-Checkout-Basis), Estate-Traefik/DNS/TLS
**Historische Scope-IDs**: M141, M142, M143, M144, M145, M146
**Requirements**: REQ-portal-datenmodell, REQ-portal-auth-magic-link, REQ-portal-projekt-sicht, REQ-portal-runtime-isolation, REQ-portal-commercial-access, REQ-portal-custom-domain
**Success Criteria** (what must be TRUE):
1. Eigene `PortalUser`-Klasse strikt getrennt von TenantUser (eigene Cookies/Routes, Magic-Link primär); kein Permission-Leak, fehlender Zugang → 404.
2. Endkunde sieht nur eigene Projekte/konfigurierte Stages/freigegebene Dokumente; Upload (Kamera, Multi-File) → Files + Activity + PL-Notification.
3. Auto-Status-Mails bei `project.stage_changed` (Debounce/Bedingungen); Tenant-Admin konfiguriert Sichtbarkeit/Templates; DSGVO-Lösch/Export für PortalUser.
**Plans**: TBD
1. Das Portal läuft als separater `hivegrid-portal`-Container aus demselben immutable Web-Image; fail-closed Surface-Routing, getrennte Sessions/Secrets und der dedizierte minimal berechtigte DB-Login `hivegrid_portal` isolieren es von App/Admin.
2. Eigene `PortalUser`-Klasse strikt getrennt von TenantUser (eigene Cookies/Routes, Magic-Link primär); kein Permission-Leak, fehlender Zugang → 404.
3. Endkunde sieht nur eigene Projekte/konfigurierte Stages/freigegebene Dokumente; Upload (Kamera, Multi-File) → Files + Activity + PL-Notification.
4. Auto-Status-Mails bei `project.stage_changed` (Debounce/Bedingungen); Tenant-Admin konfiguriert Sichtbarkeit/Templates; DSGVO-Lösch/Export für PortalUser.
5. Portal-Entitlement und Paket-Gates sind serverseitig wirksam: Starter/Team 19,99 EUR netto/Monat, Business/Enterprise inklusive; PortalUser/Projekte unbegrenzt bei unveränderten Ressourcenlimits. Die Custom-Domain kostet Starter/Team/Business 299,99 EUR netto je Einrichtung, Enterprise enthält eine; öffentlicher Produktstart erst nach `VA-P26b`.
6. Eine Custom-Portal-Domain ist per TXT+CNAME self-service aktivierbar, automatisch mit TLS/Ingress versorgt, sicher hostgebunden und überwachbar; ein Domainwechsel ist eine neue kostenpflichtige Einrichtung, sofern keine individuelle Enterprise-Regel greift. Standardhost bleibt Fallback, Reclaim-Cooldown 30 Tage.
**Plans**: `VA-P26a`, `VA-P26b`, `VA-P26c` (Termin für `VA-P26c` offen)
**UI hint**: yes (extern sichtbar, eigener Polish)
### Phase 27: Mobile-PWA-Ausbau (v2)
**Goal**: Die mobile-first-PWA aus v1 wird zur vollwertigen installierbaren App — Add-to-Homescreen, Service-Worker-Offline-Härtung, Web-Push, schneller Baustellen-Einsatz. **Kein nativer Client** (Expo/Capacitor) und **kein App-Store** — native → frühestens v3 (AD-17, PWA-only).
**Depends on**: Phase 9 (OfflineSyncQueue), Phase 21 (notify()-Push-Kanal → Web-Push), Phase 2 (Auth/Magic-Link)
**Milestones**: M167, M168, M169, M170, M171 (auf PWA umzuschneiden — kein EAS-Build, keine Store-Compliance)
**Source-Specs**: `_bmad-output/specs/M36-mobile-app.md` (⚠ Recut → PWA-only; Capacitor/Expo verworfen)
**Historische Scope-IDs**: M167, M168, M169, M170, M171 (auf PWA umzuschneiden — kein EAS-Build, keine Store-Compliance)
**Success Criteria** (what must be TRUE):
1. Offline: Pre-Cache beim Login + Offline-Write-Queue (Foto/Note/Task-Status/Checklist/Acceptance/Chat) über Service-Worker + IndexedDB; Sync-on-Reconnect idempotent (lokale UUID), Konflikt-Resolution.
2. Installierbar: Web-App-Manifest + Add-to-Homescreen + Standalone-Display; Kamera/Foto via Web-APIs mit lokalem Resize.
@@ -448,14 +432,14 @@ Decimal phases appear between their surrounding integers in numeric order.
**Risiko**: PWA-Offline-Storage-Budget + iOS-Safari-PWA-Grenzen (Web-Push iOS ≥16.4 nur im Standalone-Modus); Background-Sync-Verfügbarkeit. **Kein** App-Store-Review-Risiko (entfällt vollständig).
### Phase 28: Plattform-Admin-Tiefe (v2)
**Goal**: Getrennte AdminUser-Identität/RBAC auf admin.hivegrid.de + Feature-Flag-Massen-Statistik (löst die v1-Auflagen-Brücke ab).
**Goal**: Native Plattform-Leads plus getrennte AdminUser-Identität/RBAC auf admin.hivegrid.de + Feature-Flag-Massen-Statistik (löst die v1-Auflagen-Brücke ab).
**Depends on**: Phase 19 (Admin-Welt-Fundament/M034: Host-Routing/Cookie-Trennung/TOTP), Phase 2 (Auth-Bausteine)
**Milestones**: M038, M039, M033, M040
**Source-Specs**: `_bmad-output/specs/M37-plattform-admin.md` (Block A–D), `M32-feature-flags.md` (Massen-Statistik)
**Historische Scope-IDs**: M038, M039, M033, M040a (`R-LEADS`, ab 16.07. vorgezogen), M040b (`VA-P28b`, v2-W3)
**Success Criteria** (what must be TRUE):
1. Eigene `AdminUser`-Klasse hart getrennt (eigene Cookies SameSite=Strict, **kein BYPASSRLS** — Admin liest Tenant-Daten via RLS mit gesetztem `app.tenant_id`); AdminRBAC + 2FA-Pflicht + Self-Permission-Schutz.
2. AdminAuditLog cross-tenant mit Reason-Pflicht; Impersonate mit Reason + Banner.
3. Flag-Massen-Statistik (Effektiv-Auswertung + Live-Filter-Vorschau + Bulk-Override), deterministische Auswertung (Override > Filter > Default); interne Lead-Pipeline.
3. Flag-Massen-Statistik (Effektiv-Auswertung + Live-Filter-Vorschau + Bulk-Override), deterministische Auswertung (Override > Filter > Default).
4. M040a: native, source-authentifizierte/idempotente Plattform-Leads samt Admin-Inbox, Migration und `lead-inbox`-Decommission; M040b: Deal-Kanban/Forecast/Promotion auf derselben Datenbasis.
**Plans**: TBD
**UI hint**: yes
@@ -463,8 +447,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Öffentliches file-basiertes Help-Center mit Deep-Links aus der App + In-App-Feedback-Widget (Ausbau), das im Plattform-Admin landet.
**Depends on**: Phase 21 (Feedback-Widget→Support-Inbox-Andockpunkt), Phase 19 (Admin)
**Retro-Integration**: Help-Artikel können optional als MCP-Resources in Phase 25 exponiert werden; kein RAG-/Embedding-Korpus.
**Milestones**: M172, M173, M174, M175
**Source-Specs**: `_bmad-output/specs/M38-help-center.md`, `M39-help-desk.md`
**Historische Scope-IDs**: M172, M173, M174, M175
**Success Criteria** (what must be TRUE):
1. Markdown mit Frontmatter, Build-Time-Index (Volltext/Kategorien/Sitemap), Build-Fail bei kaputten Referenzen; öffentliche Routen `/help/{lang}/{category}/{slug}` ohne Auth + SEO + Suche.
2. Deep-Link Route→Artikel (Hilfe-Icon pro App-Route); Feedback-Widget → `Feedback` mit Auto-Kontext + Screenshot + Rate-Limit.
@@ -473,22 +456,20 @@ Decimal phases appear between their surrounding integers in numeric order.
**UI hint**: yes
### Phase 30: Dashboard-Deluxe & Querschnitt (v2)
**Goal**: Querschnitts-Komfort — anpassbare Dashboards/Export, Notification-Bündelung/Quiet-Hours, Sprach-Wechsler/EN.
**Goal**: Querschnitts-Komfort — anpassbare Dashboards/Export und Notification-Bündelung/Quiet-Hours. Der frühere Sprach-Wechsler-/EN-Scope wurde durch CR-020 in `I18N-01` vorgezogen.
**Depends on**: Phase 11 (Dashboard/Widget-Registry), Phase 3 (Notification-Center), Phase 1 (i18n-Library)
**Milestones**: M149, M150, M117, M029
**Source-Specs**: `_bmad-output/specs/M20-dashboard.md`, `M22-notifications.md`, `M30-i18n.md`
**Historische Scope-IDs**: M149, M150, M117, M029
**Success Criteria** (what must be TRUE):
1. Dashboard: Layout anpassbar (Drag/Resize, permission-gegateter Widget-Catalog), Drilldown, CSV-Export, Realtime mit Opt-Out.
2. Notifications: Bündelung (5-Min-Window → 1 Push/Mail mit count), Quiet-Hours (queued, Urgent-Override), Pro-User-Präferenzen Event×Kanal.
3. i18n: Sprach-Wechsler + EN-Locale (DeepL DE→EN mit Review), Build-Validierung, Fallback DE, Empfänger-Sprach-Auflösung Outbound.
3. i18n-Nachzug: nur noch offene Review-/Release-Gates aus `I18N-01`; der technische Sprach-Wechsler, sechs statische Basis-Kataloge, Fallback DE und Empfänger-Sprach-Auflösung werden bereits unter CR-020 umgesetzt.
**Plans**: TBD
**UI hint**: yes
### Phase 31: DSGVO-Vollausbau (v2)
**Goal**: DSGVO vertiefen — AVV-Versionierung, Subprozessoren-Workflow, Auskunfts-/Voll-Export-Workflow (ersetzt das manuelle v1-Playbook).
**Depends on**: Phase 21 (DSGVO-Export/Lösch-Fundament), Phase 28 (Admin-Legal-Verwaltung/AdminAuditLog)
**Milestones**: M166
**Source-Specs**: `_bmad-output/specs/M35-dsgvo-export.md`
**Historische Scope-ID**: M166
**Success Criteria** (what must be TRUE):
1. AVV-Versionierung mit dynamischem PDF + elektronischer Akzeptanz, Re-Akzeptanz bei Updates (14-Tage-Frist → Read-Only).
2. Subprozessoren-Liste mit Drittland-Warnung + 14-Tage-Widerspruchs-Workflow.
@@ -498,25 +479,23 @@ Decimal phases appear between their surrounding integers in numeric order.
**Risiko**: AVV-PDF-Inhalt anwaltlich finalisieren (v1 EXT-03 beauftragt).
### Phase 32: KWP-Integration (v2 — RECUT) *(ex-P10)*
**Goal**: KWP wird regulärer REST/OAuth-Adapter über die Apps-Engine — bidirektionaler Sync (Aufträge/Stammdaten/Belege/Plantafel/Dokumente) mit „KWP gewinnt"-Konfliktregel.
**Depends on**: Phase 5 (M33a Apps-Engine-Adapter-Interface — HART), Phase 9 (Auftrag/Abnahme/Material-Extension-Points), Phase 12 (Automation `kwp.push`-Action)
**Trigger (Block 2)**: KWP-API-Zugang ~20.07.; agil vorziehbar, sobald Vertrag/Zugang da.
**Milestones**: M089, M090, M091, M092, M093, M094, M095, M074
**Source-Specs**: `_bmad-output/specs/M19-kwp-integration.md` + **`docs/milestones/M19-KWP-API-RECUT.md` (bindend)**
**Goal**: KWP wird regulärer REST/OAuth2-Adapter über die Apps-Engine. Der initiale/current Scope liest die vertraglich freigegebenen Bereiche Adresse/Aktivität/Termin/Vorgang/Archiv nach HiveGrid und schützt den Inbound-Pfad mit Contract-Sentinel, „KWP gewinnt" und Audit-Restore; HiveGrid mutiert keine KWP-Ressource.
**Depends on**: Phase 5 (M33a Apps-Engine-Adapter-Interface — HART), Phase 9 (Auftrag/Abnahme/Material-Extension-Points) und `@hivegrid/storage` für Inbound-Dokumente. Phase 12/Cloud-Outbox werden erst vom geparkten Writeback benötigt.
**Trigger (Block 2)**: Auth-/Resource-/Refresh-Dauerbetrieb ist belegt; der read-only Scope ist freigegeben. Writeback hat ein separates Reaktivierungs-Gate: `VEXT-6` + erneute ausdrückliche Produktfreigabe.
**Historische Scope-IDs**: current read-only: M089, M090, M092, M093, M095 sowie die Inbound-Anteile von M094 und M074; **geparkt:** M091, M094-outbound, M074-outbound
**Success Criteria** (what must be TRUE):
1. KWP-API-Connector als erster konkreter Adapter hinterm M33a-Interface; Credentials per-Tenant-DEK in `DataConnection.config`.
2. Bidirektionaler Sync (Push via Outbox+Replay, Pull via Webhook/Cron, idempotent über `AppSyncItem`); Konflikt „KWP gewinnt" (LWW + Audit-Restore) + Optimistic Locking.
3. API-Contract-Sentinel (zod-Validierung + Versions-Check) pausiert Sync bei Drift + alarmiert Admin; Plantafel- + Dokumenten-Archiv-Sync über die API.
1. KWP-API-Connector als erster konkreter Adapter hinterm M33a-Interface; Kundenkürzel und OAuth-Material per-Tenant-DEK in `DataConnection.credentialsCiphertext`, Relay-Host dynamisch aufgelöst.
2. Pull läuft mangels dokumentierter Webhooks per konservativ rate-limitiertem Cron und idempotent über `AppSyncItem`; kein Create-, Update-, Delete-, Import- oder sonstiger fachlicher KWP-Schreibrequest. Konflikt „KWP gewinnt" nutzt HiveGrid-Snapshots + Audit-Restore, weil KWP keine einheitlichen Versionsfelder liefert.
3. API-Contract-Sentinel (OpenAPI-Fingerprint + endpoint-spezifische Zod-Validierung) pausiert Sync bei Drift + alarmiert Admin; Dokumente laufen über den dokumentierten Azure-Blob-Exchange in `@hivegrid/storage`.
**Plans**: TBD
**UI hint**: yes
**Note**: ⚠ kwpsync.exe NICHT bauen (3→2-Komponenten). Konkreter KWP-API-Vertrag (Auth/Endpoints/Webhook-Support/Doc-API) ist der Bau-Blocker.
**Note**: ⚠ kwpsync.exe NICHT bauen (3→2-Komponenten). AD-32/CR-003 superseden den unqualifizierten bidirektionalen Vertrag: M091, `kwp.push_auftrag`, Project-/Auftrag-Create und die Outbound-Anteile von M094/M074 bleiben verpflichtend erhalten, aber bis zum belastbaren Providervertrag aus `VEXT-6` und erneuter Freigabe geparkt.
### Phase 33: Telefonie-Erweiterung (HalloPetra) (v2)
**Goal**: HalloPetra als zweiter Telefonie-Provider hinterm vorhandenen `TelephonyProviderInterface` — ohne Kern-Umbau.
**Depends on**: Phase 15 (TelephonyProviderInterface + AirCall-Adapter als Referenz)
**Trigger (Block 2)**: HalloPetra-API-Vertrag/Spec; agil vorziehbar, sobald spezifiziert.
**Milestones**: M105
**Source-Specs**: `_bmad-output/specs/M12-telefonie.md` (Provider-Pattern) — ⚠ **HalloPetra selbst ist in keiner Spec; Vorlauf-Spec nötig.**
**Historische Scope-ID**: M105
**Success Criteria** (what must be TRUE):
1. HalloPetra-Adapter implementiert `TelephonyProviderInterface` (connect/triggerOutboundCall/subscribeToWebhooks/verifyWebhookSignature/parseWebhookEvent/getRecordingUrl) ohne Kern-Änderung.
2. Webhook-Auto-Match auf Contact/Lead/Projekt, Activity + Automation-Trigger; Click-to-Call + Inbound providerunabhängig.
@@ -527,8 +506,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Goal**: Externe HR-Onboarding-/Lohn-Drittanbieter (Memberspot/Boobora) über die Apps-Engine anbinden.
**Depends on**: Phase 5 (Apps-Engine), Phase 17 (HR-Hub)
**Trigger (Block 2)**: Memberspot/Boobora-API-Vertrag/Spec; agil vorziehbar, sobald spezifiziert.
**Milestones**: M138
**Source-Specs**: `_bmad-output/specs/M14-hr-hub.md` — ⚠ **Memberspot/Boobora in keiner Spec; Vorlauf-Spec nötig.**
**Historische Scope-ID**: M138
**Success Criteria** (what must be TRUE):
1. HR-Onboarding-Checklisten pro neuem MA (verlinkte Forms/Tasks/Reminders).
2. Drittanbieter (Memberspot/Boobora/Lohn) als DataConnection über die Apps-Engine angebunden (gleicher Adapter-Mechanismus wie KWP).
@@ -539,7 +517,7 @@ Decimal phases appear between their surrounding integers in numeric order.
**Execution Order:**
Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9 → 10 → 11 → 12 → 13 → 14 → 15 → 16 → 17 → 18 → 19 → 20 → 21
**v1-Launch nach Phase 21 (~10.07.).** Danach **v2 (Phasen 22–34, ~13.–31.07.):** Block 1 (22→31) in 2 dependency-freien Tracks; Block 2 (32 KWP, 33 HalloPetra, 34 HR-Drittanbieter) ans Ende, agil vorziehbar sobald Partner-API/Spec vorliegt. P10/P18 sind als v1-Nummern reserviert und werden in v2 als Phase 32 (KWP) bzw. Phase 26 (Portal) ausgeführt.
**v1-Launch nach Phase 21 (~10.07.).** Danach startet **v2 (Phasen 22–34) am 13.07.**; der 31.07. ist das ursprüngliche Drei-Wochen-Gate, retimierte Arbeit läuft als Carry-over weiter. Insbesondere läuft Phase 26 mit `VA-P26a` bis 05.08., `VA-P26b` frühestens danach und `VA-P26c` undatiert. Block 1 (22→31) läuft in zwei weitgehend disjunkten Tracks; Block 2 (32 KWP, 33 HalloPetra, 34 HR-Drittanbieter) bleibt capability-abhängig. P10/P18 sind als v1-Nummern reserviert und werden in v2 als Phase 32 (KWP) bzw. Phase 26 (Portal) ausgeführt.
| Phase | Plans Complete | Status | Completed |
|-------|----------------|--------|-----------|
@@ -564,7 +542,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 →
| 19. Plattform-Admin | 0/TBD | Not started | - |
| 20. Billing, Onboarding & Branding | 0/TBD | Not started | - |
| 21. DSGVO & Launch-Reife | 0/TBD | Not started | - |
| — v2 (Sprint 13.–31.07.) — | | | |
| — v2 (Start 13.07. · Carry-over offen) — | | | |
| 22. Public-API & Webhooks | 0/TBD | Not started (v2) | - |
| 23. Postfach-Sync (Email-Inbox) | 0/TBD | Not started (v2) | - |
| 24. Self-Service-Billing & Onboarding-Wizard | 0/TBD | Not started (v2) | - |
@@ -575,15 +553,17 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 →
| 29. Help-Center & Help-Desk | 0/TBD | Not started (v2) | - |
| 30. Dashboard-Deluxe & Querschnitt | 0/TBD | Not started (v2) | - |
| 31. DSGVO-Vollausbau | 0/TBD | Not started (v2) | - |
| 32. KWP-Integration (Recut) | 0/TBD | Block 2 — API-Zugang ~20.07. | - |
| 32. KWP-Integration (Recut) | 0/TBD | Initial read-only aktiv; Writeback hinter `VEXT-6` geparkt | AD-32/CR-003 |
| 33. Telefonie-Erweiterung (HalloPetra) | 0/TBD | Block 2 — Spec offen | - |
| 34. HR-Drittanbieter-Onboarding | 0/TBD | Block 2 — Spec offen | - |
---
*Roadmap erzeugt: 2026-06-07 via /gsd:new-project (Stufe 2 — Phasenstruktur). Revidiert: 2026-06-07 — 14 → 21 Phasen (dicke Buckets aufgeteilt: Automation/KI, Kommunikation, HR/Portal, Plattform/Launch; Querschnittsdienste in Plumbing + Files/Tasks). 109/109 v1-Requirements gemappt. Bau-Reihenfolge nach AD-11; Go-Live Big-Bang nach AD-19.*
*Roadmap erstellt: 2026-06-07. Revidiert: 2026-06-07 — 14 → 21 Phasen (dicke Buckets aufgeteilt: Automation/KI, Kommunikation, HR/Portal, Plattform/Launch; Querschnittsdienste in Plumbing + Files/Tasks). 109/109 v1-Requirements gemappt. Bau-Reihenfolge nach AD-11; Go-Live Big-Bang nach AD-19.*
*Revidiert: 2026-06-10 nach Dependency-Audit (61 Vorwärts-Verletzungen geprüft) — Service-Kerne M001/M003/M006/M011 von P3 → P1 (P3 umbenannt zu „Querschnitts-Oberflächen"), M074 → P10, M031–M033 → P19; Deps von P4/P5/P19 auf Phase 2 gelockert.*
*Revidiert: 2026-06-10 (zweiter Pass) — Dependency-Inversion vollständig: M049 → P8 (einziger echter Entity-Move); alle 40 verbleibenden Vorwärts-Refs per Retro-Integrations-Ownership invertiert (Register + Extension-Point-Pflichten + Audit-Kontrakt in PHASE-SOURCES.md). 0 unaufgelöste Vorwärts-Abhängigkeiten.*
*Revidiert: 2026-06-11/12 — **Scope-Schnitt v1/v2** (10 Entscheidungs-Blöcke, Historie in SCOPE-V1-CUTS.md): v1 = 146 MS / 94 Reqs; 30 MS → v2 (Mobile→PWA-Ausbau, Portal, Postfach-Sync, Public-API, Help, HiveMind/Whisper, HalloPetra, Wizard-UI, Dashboard-Deluxe, Admin-Teile, M166). P18 deferred, P21 umbenannt. Neu: Entitlement-Gate-Pflicht (Konnektor je Modul, P1-Contract) + M154-Recut „Abo-Baukasten" (Legacy-Referenz pricing-plans.ts: Core/Swarm/Colony). AD-5 sequenziert, AD-17/AD-18 revidiert.*
*Revidiert: 2026-06-10 (zweiter Pass) — Dependency-Inversion vollständig: M049 → P8 (einziger echter Entity-Move); die Retro-Integrationen wurden anschließend in die Ticket-Docs überführt.*
*Revidiert: 2026-06-11/12 — **Scope-Schnitt v1/v2**: v1 = 146 MS / 94 Reqs; 30 MS → v2 (Mobile→PWA-Ausbau, Portal, Postfach-Sync, Public-API, Help, HiveMind/Whisper, HalloPetra, Wizard-UI, Dashboard-Deluxe, Admin-Teile, M166). P18 deferred, P21 umbenannt. Neu: Entitlement-Gate-Pflicht (Konnektor je Modul, P1-Contract) + M154-Recut „Abo-Baukasten" (Legacy-Referenz pricing-plans.ts: Core/Swarm/Colony). AD-5 sequenziert, AD-17/AD-18 revidiert.*
*Revidiert: 2026-06-12 — **Scope-Schnitt #11 (Boilerplate-Recheck):** v1 = 141 MS / 93 Reqs; M027 (API-Keys), M029 (Sprach-Wechsler — v1 DE-only), M038/M039 (getrennte AdminUser-Identität — v1 = Boilerplate-Modell mit Auflagen: kein Tenant-Workspace, admin.hivegrid.de-Host-Routing + Cookie-Trennung, TOTP-Pflicht), M117 (Bündelung/Quiet-Hours) → v2. Dünnungen: M028, M035, M054 (HEIC→JPG bleibt Pflicht), M055, M147 (feste Rollen-Layouts), M152. Stale-Fixes: P11/P13/P14-Übersichtszeilen, URL-Schema Portal = Pfad gemäß INTEGRATION-CONTRACTS §6.*
*Revidiert: 2026-06-12 (dritter Pass) — **Scope-Schnitt #12:** v1 = **133 MS / 90 Reqs**, v2 = 43 MS. **P10 KWP komplett → v2 als ERSTES v2-Modul** (Kalender-Realität: API-Zugang ~19.07. > Launch ~10.07.; Callback-URL gemeldet, bnWin.net 8.1 N3 angestoßen, Andockpunkte bleiben). Dünnungen: M030 (nur Hell/Dunkel), M070 (Lagerist → v2), M122 (personalisierte Links/JS-Snippet → v2), M160 (KI-Walkthrough → v2). M129 bleibt explizit voll. Inversions-Register 31→28 (KWP-Inversionen wandern mit v2-Owner).*
*Ergänzt: 2026-06-15 — **v2-Phasen ausgebaut (Phase 22–34, GSD-Format).** Die 43 v2-Milestones thematisch zu 13 Phasen geschnitten (Coverage 43/43), Detail-Fassung in `.planning/ROADMAP-V2.md`. Block 1 (22–31) sofort baubar; Block 2 (32 KWP / 33 HalloPetra / 34 HR-Drittanbieter) ans Ende — „Partner-API-Vertrag offen", agil vorziehbar. Dependencies geprüft: keine Vorwärts-Abhängigkeiten (KI-Coach→Wizard und Help→RAG-Korpus per Retro-Integration aufgelöst). Bei den „phase:1"-Modulen (26/28/29/30) ist nur das v2-Delta verplant, nicht das v1-Fundament. HalloPetra (M105) + Memberspot/Boobora (M138) sind in keiner Spec → Vorlauf-Spec nötig.*
*Ergänzt: 2026-06-15 — **v2-Phasen ausgebaut (Phase 22–34).** Die 43 historischen Scope-IDs wurden thematisch zu 13 Phasen geschnitten; Detail-Fassung in `.planning/ROADMAP-V2.md`. Block 1 (22–31) sofort baubar; Block 2 (32 KWP / 33 HalloPetra / 34 HR-Drittanbieter) ans Ende — „Partner-API-Vertrag offen", agil vorziehbar. Dependencies geprüft: keine Vorwärts-Abhängigkeiten. Bei den „phase:1"-Modulen (26/28/29/30) ist nur das v2-Delta verplant, nicht das v1-Fundament. HalloPetra (M105) + Memberspot/Boobora (M138) sind in keiner Spec → Vorlauf-Spec nötig.*
*Aktualisiert: 2026-07-12 — **KWP-Vertragsspiegel:** Discovery, dynamischer Tenant-Relay, Tenant-OpenAPI und beide OAuth-Redirects verifiziert. Block 2 für KWP ist auf Runtime-Token/Scopes und die fehlende Auftrag-Create-Capability eingegrenzt; keine dokumentierten Webhooks/Rate-Limits/einheitlichen Versionsfelder, Archivtransfer über Azure Blob. Historische Scope-Schnitt-Datumsangaben oben bleiben als Entscheidungsprotokoll erhalten.*
*Aktualisiert: 2026-07-22 — **KWP-Read-only-Scope (AD-32/CR-003):** Auth-/Resource-/Refresh-Dauerbetrieb bewiesen; initiale Phase 32 ohne KWP-Mutationen. M091, M094-outbound, M074-outbound und Project-/Auftrag-Create bleiben hinter `VEXT-6` + erneuter Freigabe geparkt. Historische Datumsstände bleiben als Entscheidungsprotokoll erhalten.*
@@ -1,187 +0,0 @@
# Scope-Verengung v1 — Cut-Log (laufende Entscheidungen)
**Begonnen:** 2026-06-11 · Wird am Ende der Streich-Session in einem Batch propagiert (ROADMAP, REQUIREMENTS, PHASE-SOURCES, SPRINT-4W, EXTERNALS, Report).
**Definition v2 (User, verbindlich):** *„v2 ist alles, was gemacht werden MUSS, aber halt erst in der v2."* → v2 = committed Scope, nur sequenziert. Kein Streichen, kein Vielleicht-Backlog. Nach v1-Launch wird v2 regulär geplant (eigene Phasen).
---
## Cut #1 — Mobile-Store-App → v2 (2026-06-11) · ⚠ Tech-Teil „Expo" überholt durch #14 (PWA-only)
- **Raus aus v1:** M167–M171 (P21: 15 → 10 MS) · REQ-mobile-capacitor, REQ-mobile-offline-sync, REQ-mobile-push → v2
- **Tech-Entscheidung:** ~~v2-App mit Expo (React Native) statt Capacitor~~ → **überholt durch Entscheidung #14 (16.06.): PWA-only, kein Expo/Capacitor.** M36-Spec auf PWA recutten; M167–M171 bei v2-Planung als PWA-Ausbau neu schneiden
- **Bleibt v1-Pflicht:** Monteure via **PWA/responsive Web** — (a) mobile-first für Monteur-Screens (Plantafel, Abnahme, Auftrag, Tasks, Foto), (b) Mobile-Viewport im Visual-Reg-Gate (P1), (c) P9-Offline (Plantafel/Abnahme) unverändert. AD-17-*Absicht* bleibt erfüllt; native Hülle = v2
- **Expo-Readiness jetzt (gratis):** P9-OfflineSyncQueue als pures TS mit Storage-Interface (Web: IndexedDB / Expo: SQLite) · P1-Push-Kanal-Stub bleibt · P21-Public-API perspektivisch VM-förmige Endpoints
- **Externals:** A3 Apple ✅ **Konto bereits vorhanden** · A4 Google Play → v2-Vorbereitung, unkritisch · B7 FCM/APNs → v2
- **AD-Wirkung:** AD-17 revidiert (Offline v1 via PWA; native App v2/Expo) — **⚠ weiter revidiert durch Entscheidung #14 (16.06.): PWA-only in v1 UND v2; Expo/Capacitor/App-Store komplett verworfen; native → frühestens v3.**
## Cut #2 — Customer-Portal (P18) → v2 (2026-06-11)
- **Raus aus v1:** M141–M146 (P18 komplett, −6 MS) · REQ-portal-datenmodell, REQ-portal-auth-magic-link, REQ-portal-projekt-sicht → v2
- **Mitwandernde Retro-Integrationen (→ v2):** Theme→Portal (`M141→M030`, war P20-Aufgabe) · Portal-DSGVO-Löschung (`M146→M165`, war P21-Aufgabe)
- **Bleibt v1 (kostenlos, für friktionsfreies v2-Andocken):** P4-Portal-Upload-Vorbereitung (FileEntityLink) · `portal.hivegrid.de` im P1-URL-Schema
- **Sprint-Wirkung:** Dev C in W4 deutlich entlastet (P16 → ~~P18~~ → P21)
- **AD-Wirkung:** AD-18 revidiert (Portal voll = v2)
## Entscheidung #3 — USP-Säulen (2026-06-11)
- **P12 Automation: bleibt VOLL** („wir brauchen dringend Automation") — inkl. Editor, Dry-Run, 24h-Undo, Guards, Klartext-Logs (Bauprinzipien A.10/LP-10 unangetastet). Trigger/Action-Library skaliert automatisch mit v1-Modulen (Dependency-Inversion) — v2-Modul-Trigger registrieren sich in v2 nach.
- **P13 KI: OFFEN** — Dünnungs-Kandidaten (HiveMind/RAG→v2 inkl. pgvector-Synergie in P11, Whisper→v2, AlephAlpha→v2, Pay-as-you-go-Verdrahtung→v2) notiert, keine Entscheidung. Sprach-zu-Automation + Gateway + Promptfoo bleiben in jedem Fall.
## Entscheidung #4 — Email-Marketing: bleibt VOLL (Option A, 2026-06-11)
- **M100–M104 bleiben komplett in v1** (Kampagnen-Builder, Segmente, Versand-Engine, A/B+Reporting, Unsubscribe/Bounces). Bestätigt die ursprüngliche User-Hochstufung in der Spec („Phase-1-Voll-Modul — kritisch für Launch, löst HubSpot-Marketing-Hub ab", LP-7).
- **Konsequenz 1 — P14-Email-Hälfte:** Die **Versand-Infrastruktur muss in v1 bleiben** (TenantSendingDomain + Verifizierung, Mailjet-Anbindung — Marketing-Spec setzt verifizierte Sending-Domain aus M9 voraus). Der Dünnungs-Kandidat bleibt nur der **Gmail/Outlook-OAuth-Postfach-Sync** (M096/M097: Inbox-View, Threading) → Entscheidung offen.
- **Konsequenz 2 — External A6 steigt in der Priorität:** Domain-Warm-up/Reputation ist bei Massen-Kampagnen (Tagesbudget 10K) kritisch — SPF/DKIM/DMARC + Warm-up ab Tag 1 zwingend.
## Entscheidung #5 — KI-Tiefe (P13) entschieden (2026-06-11)
- **Sprach-zu-Automation (M086): bleibt v1 — EXKLUSIV im Automation-Kontext.** Wird als Feature des Flow-Editors gebaut (direkte DB-Existenzprüfungen, kein RAG), NICHT als HiveMind-Fähigkeit. Architektur-Vorgabe: keine Kopplung an HiveMind, damit v2-HiveMind die Automation nie blockiert oder übernimmt.
- **HiveMind/RAG (M087): → v2 — v1 baut die Andock-Adapter:** (a) Outbox-Index-Events (existiert via P11-Indexer), (b) `RetrievalProvider`-Interface im KI-Unterbau, (c) Bestätigungs-Grenze („KI schreibt nie ohne User-OK") entsteht v1 via M086 und wird von HiveMind geerbt. REQ-ki-hivemind + REQ-ki-rag-embeddings → v2.
- **Whisper: → v2** (REQ-ki-whisper). „Cool, aber aktuell nicht nötig."
- **Unterbau bleibt v1:** M083 Gateway, M084 Multi-Provider-Fallback, M085 Promptfoo, M088 Token-Limits (Pay-as-you-go-Abrechnung weiterhin per Inversion → P20/v2; lokales Credits-Konto bleibt).
- **Folge-Entscheidung:** P11-Suche bleibt Keyword-only (Meilisearch); pgvector/Hybrid-RRF/HiveMind entfällt nach AD-26 bzw. ruht als v3-Kandidat. REQ-suche-hybrid ist entsprechend auf Meilisearch gedünnt.
## Entscheidung #6 — Keep-Entscheidungen (2026-06-11)
- **Team-Chat (M110–M114): bleibt v1** — „ultra wichtig". WebSocket-Layer (AD-9) damit ebenfalls v1.
- **HR-Hub (M133–M140): bleibt v1 komplett** — „genau wie HR".
- **Booking + Kalender-Sync (M118–M120, M126–M129): bleiben v1** („und ähnliches" → Signatur M130–M132 vermutlich auch — Bestätigung ausstehend).
- **Legacy-Provider (M153–M156): bleibt v1.** ⚠ Offen: Rücksprache mit Partner zu **pauschalem Pricing** — falls pauschal, dünnt M156 (Metering nur als Datensammlung, keine Aufschlags-Abrechnung; Seat-Quota-Logik vereinfacht).
- **Konsequenz Externals:** Google-OAuth-Verifizierung (A2) bleibt im Sprint relevant (Kalender-Lesepfad braucht Calendar-Scope!), Legacy-Provider-Live (A5) bleibt, PandaDoc (B4) bleibt (falls Signatur bestätigt).
## Entscheidung #7 — Kommunikation & Billing-Modell (2026-06-11)
- **Mail-Inbox/Postfach-Sync → v2:** M096-OAuth-Teil, M097 (Inbox/Threading/Auto-Verknüpfung), M098-Provider-Versand, M099-Teile → v2. **Bleibt v1:** Sende-Domain-Verifikation (aus M096 herausgelöst), Mailjet-Versand, Bounce/Sperrliste (Marketing-Anteil), Inbound-Adresse→Lead. **Empfohlen (klein, ~½ MS): BCC-Logging-Brücke** (`crm@tenant…` als BCC → Mail wird am Kontakt protokolliert, nutzt Inbound-Infrastruktur, kein Google-OAuth). → **Google-Verifizierung (A2) nur noch für Kalender-Scopes nötig, Gmail-Scopes raus.**
- **Telefonie bleibt v1** (AirCall M106–M109, Anruf-Trigger für Automation). ⚠ **~~inkl. HalloPetra~~ überholt durch #10:** HalloPetra (M105) → v2 (Phase 33). AirCall bleibt v1.
- **Marketing bleibt voll** (Re-Bestätigung von #4).
- **Legacy-Provider: einheitliches Billing** — keine Büro-/Monteur-**Seat**-Unterscheidung mehr (M154 kollabiert; Interpretation „Seats" vom User rückbestätigen lassen — NICHT die SHK-Seeds!). Varianten-Entscheidung (pro Nutzer einheitlich / pauschal pro Mandant / Größenstaffel) liegt beim Partner-Gespräch. M156-Aufschlags-Billing entfällt; Verbrauchs-Counter + Fair-Use-Drossel bleiben als Kostenschutz.
## Entscheidung #8 — Abschluss der Streich-Session (2026-06-11)
- **Signatur (M130–M132): bleibt v1** (bestätigt — war Teil von „Booking, Kalender und ähnliches").
- **Onboarding-Wizard-UI (M157): → v2.** Seeds (M158) + Demo-Daten (M160) bleiben; Branchen-Framework (M159) v1 nur SHK. Signup → Auto-SHK-Seed ohne Wizard.
- **Billing-Modell final: „Abo-Baukasten"** — Basis-Preis pro Nutzer (keine Seat-Typen) + Feature-Module als zubuchbare Legacy-Provider-Positionen. **M154-Recut:** Seat-Typ-Modell ersetzt durch Entitlement-Schicht = Feature-Flag-Engine (P1) × `packages/entitlements` × daten-getriebene Legacy-Provider-Items (M153). **v1 = Mechanik** (Admin stellt Tenant-Abos in P19 zusammen), **v2 = Self-Service-Baukasten-UI** (Kunde toggelt Features mit Preis-Vorschau). **Kostenmatrix** = Business-Aufgabe mit Partner, blockt Bau nicht (AD-15). Zähler + Drossel bleiben v1; Extra-Usage-Abrechnung wird separat besprochen (offen, blockt nicht).
## Entscheidung #9 — Konnektor-Pflicht + Legacy-Plan-Referenz (2026-06-11)
- **Konnektor-Pflicht pro Feature (v1, hart):** Jedes Modul ist eigenständig enable-/disable-bar und plan-gebunden schaltbar. Wird **neuer Integration-Contract in P1** („Entitlement-Gate-Pflicht": Modul registriert Gate, Sidebar/Routes/Actions prüfen `tenantHasModule()`), Pflicht-Checkpunkt jeder Modul-Phase. Mechanik: Boilerplate-Flag-Engine (hat bereits `plan-tier`-Targeting!) × `packages/entitlements` × Legacy-Provider-Items.
- **Legacy-Plan-Namen gefunden:** **Core / Swarm / Colony** (D006, 29€/49€/Contact-Sales pro Seat) in `~/Documents/GitHub/archive/hivegrid-cloud/app/config/pricing-plans.ts`. Datei enthält komplette Konnektor-Blaupause: 14 gegatete Module, 6 Quota-Dimensionen (inkl. aiTokensPerMonth), 6 Plan-Flags. **→ Als Source-Spec für den P20-Recut (M154→Abo-Baukasten) übernehmen**; Struktur portieren, Inhalte (Preise/Tiers vs. À-la-carte) = Kostenmatrix-Gespräch mit Partner.
## Entscheidung #10 — Feature-Tiefe-Runde (2026-06-11)
**→ v2:** Public-API (M161–163) · Help-Center+Help-Desk (M172–175; Minimal-FAQ + Feedback→Admin-Inbox bleiben) · Dashboard Custom-Widgets+Export (M149, M150; 7 Standard-Widgets bleiben) · Plattform-Lead-Pipeline (M040) + Flag-Massen-Statistik (M033) · HR-Drittanbieter-Onboarding Memberspot/Boobora (M138) · HalloPetra (M105; **AirCall bleibt v1**) · Kalender: **Outlook → v2, Google bidirektional v1** (halbiert Verifizierungs-Risiko)
**Gedünnt (Modul bleibt):** Sales-Analytik → Basis-KPIs (Forecast/Stage-Conversion-Tiefe v2) · Booking: eine Zuteilungs-Strategie („Erster der frei ist"), Round-Robin/Endkunde-wählt v2
**Explizit BEHALTEN (User):** Mitarbeiter-Surveys (HR) · Conditional Logic (Forms) · Chat komplett (inkl. Threads/Reactions/Pins) · CRM komplett (inkl. Bulk-Merge-Tool) · Marketing inkl. A/B (Option A bestätigt)
**Offen:** DSGVO-Auskunft (M166) — Detail-Erklärung angefordert, Entscheidung ausstehend.
**Bilanz nach #10: v1 ≈ 147 Milestones** (−13 ganze + Dünnungen) ≈ 2,45 MS/Dev/Tag — erstmals echter Puffer.
## FINALER SCHNITT (alle Entscheidungen getroffen)
**→ v2 (committed, sequenziert):** Mobile-PWA-Ausbau (PWA-Recut, M167–171; Expo/Capacitor verworfen — AD-17) · Customer-Portal (M141–146) · HiveMind/RAG (M087) + Whisper + pgvector/Hybrid-Suche · Postfach-Sync (M096-OAuth/M097/M098; Domain-Verifikation bleibt) · Onboarding-Wizard-UI (M157) · Self-Service-Abo-Baukasten-UI · AlephAlpha-Provider · Pay-as-you-go-Abrechnung
**Bleibt v1 (User-Entscheidung):** komplette Kern-Kette P1–P10 · Suche (Keyword) + Dashboard · Automation VOLL · KI-Unterbau + Sprach-zu-Automation (exklusiv Automation) · **Marketing voll** · **Telefonie (AirCall) voll** ~~(inkl. HalloPetra)~~ *(überholt durch #10: HalloPetra/M105 → v2, Phase 33)* · **Team-Chat voll** · **HR voll** · Booking + Kalender + Forms + **Signatur** · Legacy-Provider (Abo-Baukasten-Mechanik) · Plattform-Admin · Seeds + Demo-Daten
**Bilanz: v1 ≈ 160 Milestones** (–16 vs. 176) ≈ 2,7 MS/Dev/Tag — weiterhin straff; Gates + neue Notfall-Leiter zwingend. Verbleibende harte Externals: **KWP, Google (nur noch Calendar-Scopes), Legacy-Provider-Live, PandaDoc/DocuSign, AirCall/HalloPetra, Mailjet-Domain-Warm-up.**
---
## Laufende Bilanz
| | v1-Milestones | v1-Requirements | W4-Last (Dev C) |
|---|---:|---:|---|
| Start | 176 | 109 | P16-Rest + P18 + P21(15) |
| nach Cut #1+#2 | **165** | **103** | P16-Rest + P21(10) |
## Externals-Änderungen
- A3 Apple Developer: ✅ vorhanden (User-Info 2026-06-11)
- A4 Google Play, B7 FCM/APNs: → v2-Vorbereitung, nicht sprint-kritisch
## Noch zu diskutieren (🟢-Kandidaten aus der Gesamtliste)
- [ ] Team-Chat (P15-Hälfte, 5 MS) — Quiply existiert
- [ ] HR-Hub (P17, 8 MS)
- [ ] Marketing (P14-Hälfte, 5 MS)
- [ ] Public-API + Help-Center/Desk (P21, 7 MS)
- [ ] Booking / Signatur / Kalender-Sync (P16-Teile, 10 MS)
- [ ] Billing/Legacy-Provider + Onboarding-Wizard (P20-Teile, ~7 MS)
- [ ] USP-Tiefe P12/P13 (RAG/HiveMind/Whisper dünnen?)
## Entscheidung #11 — Boilerplate-Recheck-Runde (2026-06-12)
Basis: historischer Sweep über die inzwischen entfernten Boilerplate-Mapping-Reports + Code-Stichproben. Erkenntnis: Boilerplate-HIGH-Coverage-Milestones (Auth, Billing, i18n, Mail, Worker, Impersonation) NICHT cutten — fast geschenkt. Geschnitten/gedünnt werden die teuren Spec-Deltas.
**→ v2 (5 ganze Milestones):**
- **M027 API-Keys & Tarif-Gates** — Public-API ist v2; Keys ohne Endpoints sinnlos. Boilerplate-`ApiKey`-Modell + Routen bleiben ungenutzt im Code liegen (Vorbereitung gratis). Lead-Push von Fremd-Websites läuft über M047-Quellen-Token, nicht über API-Keys.
- **M038 + M039 (getrennte AdminUser-Identität/AdminRBAC)** — v1 = Boilerplate-Modell (User-Extension + MFA-Step-up). **Auflagen in M034:** TOTP-Pflicht hart · Admin-User bekommen **keinen Tenant-Workspace** (Boilerplate-Default abschalten!) · Host-Routing `admin.hivegrid.de` (Code routet bisher `/admin`-Pfad) · **Cookie-Domain-Trennung** App↔Admin.
- **M117 Notification-Bündelung/Quiet-Hours/Push-Limits** — bewusst v2 (User-Entscheidung). v1: Sofort-Zustellung + Center (M115) + Kategorie-An/Aus (M116).
- **M029 Sprach-Wechsler/Fallback** — v1 = **DE-only**. Hart: i18n-Pflicht-Wiring (M003) + `verify:i18n`-CI-Gate unantastbar — alles i18n-ready, v2 = Locales + Wechsler andocken ohne Refactoring.
**Gedünnt (Modul bleibt):**
- **M028:** DE-only-Defaults (Auflösungskette/Timezone-Prefs → v2)
- **M054:** Datei-Versionierung + Office-/Video-Previews + Resume-Upload → v2; **HEIC→JPG-Konvertierung bleibt Pflicht** (iPhone-Fotos der Monteure!), Bild-/PDF-Preview bleibt
- **M055:** OCR/Inhalts-Volltext → v2; Dateiname+Tags via Meilisearch + Archiv-Flag bleiben
- **M147:** 3 feste Rollen-Layouts (GF/Büro/Monteur) statt Drag&Drop-Grid (react-grid-layout wäre Neueinkauf); Widget-Registry bleibt (Inversion `M064→M147` braucht sie)
- **M152:** fixe Default-Retention + direkter CSV/PDF-Export; konfigurierbare Policy/Legal-Hold/Saved-Views → v2
- **M035:** Boilerplate-KPIs (Tenants/User/MRR); Churn/ARPU/Health-Kacheln → v2
**Beifang — Doku-Drift korrigiert:** EXTERNALS-C5 + P18-Note listeten Portal/Forms/Booking/Help/API als Subdomains — `INTEGRATION-CONTRACTS.md` §6 (Quelle) definiert sie als **Pfade unter `app.hivegrid.de`**; einzige zweite Subdomain ist `admin.hivegrid.de`. Ferner stale Stellen aus #5 gefixt (ROADMAP-P11-Übersicht „pgvector-Hybrid", REQ-suche-Texte).
**Bilanz nach #11: v1 = 141 MS / 93 Reqs / v2 = 35 MS** ≈ 2,35 MS/Dev/Tag (effektiv ~2,3 mit Dünnungen).
---
## ✅ PROPAGIERT (2026-06-12)
Alle 10 Entscheidungs-Blöcke in einem Batch propagiert: ROADMAP.md (P18 deferred, P21 umbenannt, 9 Phasen umgeschnitten, Konnektor-SC in P1, Recut-Notes M36→Expo + M154→Abo-Baukasten) · REQUIREMENTS.md (15 REQs → v2, 94 v1, Traceability/Verteilung neu) · PHASE-SOURCES.md (v2-Sektion 30 MS, Register 40→31, Konnektor-Contract) · SPRINT-4W.md (Rewrite: 146 MS, neue Notfall-Leiter, Externals) · EXTERNALS-CHECKLISTE.md (A2 nur Calendar, A3 ✓, 6 Einträge → v2, E6 AVV neu) · PROJECT.md (AD-5 sequenziert, AD-6/7 gelockt, AD-17/18 revidiert) · Report-PDF neu.
**Verifiziert:** 146 v1 + 30 v2 = 176 ✓ · Traceability 94 ✓ · Inversions-Register 31/31 deckungsgleich, 0 unaufgelöst, 0 stale ✓
## ✅ PROPAGIERT Batch #11 (2026-06-12, Boilerplate-Recheck)
M027/M029/M038/M039/M117 → v2 (v1 = 141, v2 = 35) · Dünnungen M028/M035/M054/M055/M147/M152 als Notes in PHASE-SOURCES/ROADMAP/REQUIREMENTS · REQ-auth-api-keys → v2 (93 v1-Reqs) · URL-Schema-Drift C5/P18 bereinigt · stale pgvector-Reste gefixt.
## Entscheidung #12 — Abschluss-Runde (2026-06-12)
**P10 KWP-Integration KOMPLETT → v2 (−8 MS: M074, M089–M095; −3 Reqs).** Auslöser: **Kalender-Realität** — KWP-Mail (an Noah) bestätigt: API-Zugang kommt erst ~**19.07.**, v1-Launch ist ~10.07. Das W3-Gate „KWP-Kette E2E" wäre nie haltbar gewesen; Mock-Bau gegen Doku = Schema-Drift-Risiko. **KWP bleibt USP und wird ERSTES v2-Modul** (Geerkens hat den Sync ~2–3 Wochen nach Launch). Sofort-Aktionen (kosten nichts, beschleunigen v2): (a) **Callback-URL an KWP melden**: `https://app.hivegrid.de/integrations/kwp/oauth/callback` (+ Staging intern; eine feste URL, Tenant im `state`), (b) **kwp-bnWin.net auf 8.1 N3** bei Geerkens-IT, (c) Andockpunkte bleiben v1 (Apps-Engine P5, Extension-Points Auftrag/Abnahme/Material). v1-Kern-Kette endet bei Auftrag; Doppelerfassung für ~2–3 Wochen akzeptiert.
**Dünnungen:**
- **M160:** KI-Walkthrough → v2 („hat nichts in v1 zu suchen"; gehört zum Wizard M157 = eh v2). Demo-Daten-Seed bleibt (Knopf in Settings statt Wizard-Schritt), einfaches Löschen statt Multi-Step-Bulk.
- **M122:** personalisierte Links (Tracking/Ablauf/Limit) + JS-Snippet → v2; öffentliche URL + QR + iFrame-Embed bleiben.
- **M070:** Lagerist-Sicht + Material-Ausgangs-Doku → v2; Material-Listen am Auftrag bleiben (KWP-Daten folgen mit v2-P10). **Noah-Frage auf E-Liste:** gehört der Lager-Arbeitsplatz zum Validierungs-Versprechen?
- **M030:** nur Hell/Dunkel-Toggle — **kein System-Modus** (User-Entscheidung; weniger Testfläche). Capacitor-Teil stirbt durch Mobile-Cut.
**Explizit voll behalten:** M129 (Booking-Verwaltung inkl. Verschiebung/Re-Assignment/No-Show — „lassen wir so, wie er vorher war").
**Bilanz nach #12: v1 = 133 MS / 90 Reqs / v2 = 43 MS** ≈ 2,2 MS/Dev/Tag. Notfall-Leiter: „NIEMALS opfern" = P1–P9. W4 massiv entlastet (Dev A frei für E2E-Härtung).
## Entscheidung #13 — Modell-Pivot: Projekt-zentrisch (2026-06-13)
Auslöser: Davids (UX) konsolidiertes CRM/Pipeline-Briefing wird zur Bau-Grundlage gemacht — Raffael richtet die Planung daran aus (statt David einzunormen). **Voll adoptiert.** Anker: `.planning/ENTITY-MODEL.md`. Neu: **AD-20**; **AD-2** + **AD-11** revidiert.
- **E1 — Architektur (voll adoptiert):** Deal + Auftrag verschmelzen zu EINEM `Projekt`-Kern; Pipelines = frei konfigurierbare Views; „Deal"/„Auftrag" = Pipeline-Typen, keine eigenen Entitäten. Ein Projekt = genau eine Pipeline; `Status` pipeline-intern (kein globaler Projektstatus). Admin steuert pro Pipeline: Zugriff, Feld-Sichtbarkeit, Pflichtfelder/Status, Statuswerte (Pipeline-Feld-Config-Layer). Betrifft P6–P9, ENTITY-MODEL, SCREEN-MAP (Sales-Kanban + Projekt-Kanban → ein konfigurierbarer Kanban).
- **E2 — Abnahme bleibt v1:** als Checklisten/Protokoll-Sub-Area am Projekt (Mängel = Checkliste), nicht eigenes Modul. Eigenschaften bleiben (rechtlich bindend, immutable, 6 J., Touch-Signatur, offline). **→ v2-Backlog:** Materialbedarf, Zeiterfassung, Leistungspositionen, Baustelle, Supporttickets.
- **E3 — Rechnung = neues Sub-Entity v1** am Projekt (Liste/Anlegen/Verknüpfen). *Einziger echter v1-Scope-Zuwachs durch den Pivot.*
- **E4 — Lead-Flow:** Lead/LeadInput → Projekt (Datenpunkt `Weiterverarbeitungsfreigabe` Ja/Nein/Unklar). Das bisherige Lead→Contact-Promotions-Modal (REQ-crm-lead-promotion) entfällt; Kontakt wird separat verknüpft.
- **Kontaktmodell:** `Kontakt` = Oberbegriff mit `Kontakttyp` (Privatperson/Organisation), `Kontaktstatus` (Kontakt/Kunde/Bestandskunde), `Kontaktart` (Haupt-/Sekundärkontakt als Rolle/Relation). Zwei Listen (Unternehmen/Organisationen + Kontakte).
- **KWP:** unverändert v2; v1 nur Feld-Halter/Extension-Point (kein Sync-UI).
**MS/Reqs-Bilanz (neu gezählt 16.06. — R-REFIT):** Reqs **= 90 v1 unverändert** — REQ-crm-lead-promotion entfällt (−1), REQ-rechnung-sub-entity NEU (+1), Sales/Projekt-Reqs zu „Projekt & Pipelines" konsolidiert (Netto 0). Milestones **= 176** (133 v1 / 43 v2) — die P6–P9-Milestones (M01–M04) sind **inhaltlich** projekt-zentrisch re-gemappt (Deal+Project → ein `Projekt`-Kern; Rechnung-Sub-Entity ergänzt; Lead→Projekt statt Promotion), die Milestone-Bezeichner bleiben als Datei-Referenz erhalten — keine Stück-Zahl-Änderung, nur Re-Map (Detail in PHASE-SOURCES.md P8/P9).
**Status (15.06.):** ✅ ER-Modell **APPROVED & LOCKED** — `ENTITY-MODEL.md` (Kern auf Projekt-zentrisch umgeschrieben, übrige Domänen erhalten), `entity-model.dbml` (kanonisch) + `entity-model.svg` (Diagramm) + `ENTITY-MODELL-ERKLAERUNG.pdf` (Laienfassung). Decisions (PROJECT/ARCHITECTURE-DECISIONS AD-20), ROADMAP (P6–P9), STATE propagiert. Scratch gelöscht. **Offen:** Detail-Re-Fit von REQUIREMENTS/PHASE-SOURCES/SCREEN-MAP gegen das gelockte Modell (+ MS/Reqs-Neuzählung).
## Entscheidung #14 — Mobile: PWA-only in v1 UND v2 (2026-06-16)
**Auslöser (User):** „Wir bauen in v1 und v2 nur die PWA. Noch keine Expo-Shenanigans — erstmal nur PWA." → der Mobile-Tech-Teil von Cut #1 (Expo in v2) wird zurückgenommen; es gibt **keinen nativen Client** im gesamten v1+v2-Scope.
- **Verworfen:** Expo/React-Native, Capacitor, native iOS/Android-App, App-Store-Einreichung (Apple + Google), TestFlight/interner Track, APNs/FCM-Push, Store-Compliance/Store-Metadaten/Store-Badges.
- **Bleibt/wird:** installierbare **PWA** — v1 mobile-first + Offline (P9); v2-P7 = **PWA-Ausbau** (Web-App-Manifest/Add-to-Homescreen, Service-Worker-Offline-Härtung, **Web-Push via VAPID**, Force-Update via SW-Versionierung). Der P1-Push-Kanal-Stub wird in v2 als Web-Push aktiviert.
- **M36 / M167–M171:** Recut auf PWA (kein EAS-Build, keine Native-Module, keine Store-Compliance).
- **Tickets:** VA-P27a/b + VD-3 → **PWA-Ausbau** umgewidmet; App-Store-Block (VEXT-4, VJ-1, App-Store-Teil von VD-6 / EXT-13 / VJ-3) → **v3-Backlog** (aus Cycle raus, `v3`-Label). Billing-„App-Store-konform"-Auflage (Apple 3.1.3) entfällt — Self-Service-Plan-Wechsel direkt im Web-Checkout.
- **Externals:** A3 Apple, A4 Google Play, B7 FCM/APNs, E5 App-Store-Metadaten → **v3 statt v2** (kein App-Store in v1/v2).
- **AD-Wirkung:** **AD-17** auf „PWA-only (v1+v2), kein nativer Client; native → frühestens v3" gesetzt; Scope-Muster-Note (AD-13/16/17/18) in ARCHITECTURE-DECISIONS angepasst.
- **Native → v3:** als Backlog vermerkt, nicht beauftragt.
@@ -1,206 +0,0 @@
---
pdf_options:
format: A4
margin: 14mm
css: |-
body { font-size: 10px; font-family: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif; }
h1 { font-size: 18px; } h2 { font-size: 14px; border-bottom: 2px solid #f5a623; padding-bottom: 3px; margin-top: 20px; break-after: avoid; page-break-after: avoid; }
h3 { font-size: 11.5px; margin-top: 14px; break-after: avoid; page-break-after: avoid; }
table { font-size: 8.5px; border-collapse: separate; border-spacing: 0; width: 100%; border-top: 1px solid #ccc; border-left: 1px solid #ccc; }
thead { display: table-header-group; }
tr { break-inside: avoid !important; page-break-inside: avoid !important; }
td, th { break-inside: avoid !important; page-break-inside: avoid !important; border-right: 1px solid #ccc; border-bottom: 1px solid #ccc; padding: 3px 5px; text-align: left; vertical-align: top; }
th { background: #fff7e8; }
li { break-inside: avoid; page-break-inside: avoid; }
p { orphans: 3; widows: 3; }
code { background: #f4f4f4; padding: 1px 3px; font-size: 8px; }
.pagebreak { page-break-after: always; }
---
# SCREEN-MAP — HiveGrid 2.0 v1 (präzise Bau-Liste für David)
**Stand:** 12.06.2026 (nach Scope-Schnitt #12 + Infra-Wechsel) · **Quelle:** 36 Specs (requirements-pur) + TIMELINE-Deadlines + Playbook-Archetypen
**Regeln:** (1) Screens beschreiben WAS angezeigt wird — Layout/Anordnung ist Davids Freiheit. (2) Hot-Swap: kein Screen blockt den Dev-Bau; Deadlines = Demo-/Politur-Termine. (3) Pro Screen vor Übergabe: Reconciliation-Checkliste (Playbook §6a) — jedes Feld hat eine Datenquelle, jeder Button eine Aktion, 4 Zustände designt (leer/laden/Fehler/keine Berechtigung).
**Legende:** `[A2]` = aus Archetyp komponiert (Stunden) · **BESPOKE** = Sonder-UI (Tage) · 🌐 = öffentlich (höchster Polish) · 📱 = Monteur-mobile-first + offline
> 🔴 **MODELL-PIVOT (AD-20) — §2/§3/§4 nachgezogen 2026-06-16 (ENTITY-MODEL.md LOCKED):** Projekt-zentrisch. **Sales-Kanban + Projekt-Kanban → EIN konfigurierbarer Pipeline-Kanban** (Pipeline = View; „Deal"/„Auftrag" = Pipeline-Typen `typ_hint` sales/auftrag/custom, KEINE eigenen Entitäten). **Projekt-Detail** mit Sub-Areas (Kontakte, Termine, **Rechnungen [v1 NEU]**, Checklisten, Aufgaben, Aktivitäten, Dokumente). **KEIN Won-Handoff** (Projekt wechselt nur die Pipeline, kein zweiter Datensatz). **Lead → Projekt** bei Weiterverarbeitungsfreigabe (Lead-Promotion-Modal mit 4 Optionen entfällt; Kontakt separat verknüpft). **Abnahme** bleibt als immutable Checklisten/Protokoll-Sub-Area am Projekt (Mängel = Checkliste). Neuer **Pipeline-Config-Admin-Screen** (Zugriff/Feld-Sichtbarkeit inkl. **Field-Level-Rechte je Rolle/Gruppe/User** `PipelineFieldVisibility`/Pflichtfelder/Statuswerte je Pipeline). Kontaktmodell: Kontakttyp (Privatperson/**Organisation** — nicht „Unternehmen")/Kontaktstatus (Kontakt/Kunde/Bestandskunde)/Kontaktart=Rolle. **KWP komplett v2** (auch kein Feld-Halter v1). Die §2–§4-Tabellen sind nachgezogen; David finalisiert sein PDF gegen `.planning/ENTITY-MODEL.md`.
---
## §0 BASELINE — Sprint D0 (Fertig: So 21.06.) — blockt ~70 % aller Screens
### 0.1 App-Shell (Archetyp A1) — wird von JEDEM Screen konsumiert
| Komponente | Muss enthalten |
|---|---|
| **Sidebar** | Modul-Navigation mit Icons + Labels · **Konnektor-Gating-Zustand** (Modul ausgeblendet/gesperrt je `tenantHasModule()`) · Sektionen: Arbeit (Dashboard, Kontakte, Leads, **Projekte** (eine Liste/Kanban über alle Pipelines, Pipeline-Switcher im Header), Plantafel, Aufgaben, Dateien, Kalender, Buchungen, Formulare, Chat, Telefonie, Marketing, HR) + Verwaltung (Settings, Admin) · Collapse-Zustand · aktiver Eintrag · Mobile: Drawer/Bottom-Nav-Variante 📱 |
| **Topbar** | Tenant-Switcher (Dropdown, Liste mit zuletzt-genutzt, Suchfeld ab 5 Tenants) · **Cmd+K-Suchfeld-Trigger** · Notification-Bell mit Unread-Badge · User-Menü (Profil, Settings, Hell/Dunkel-Toggle, Logout) |
| **Breadcrumb** | Pfad bis Entität (z. B. Projekte → Pipeline Heizung (Sales-Sicht) → P-2026-0042) |
| **Status-Banner-System** | Tenant-Status-Banner: `past_due` / `frozen` / `deletion_pending` / `suspended` — je eigener Text + Action-Button · stapelbar mit System-Hinweisen |
| **Toast/Inline-Feedback** | Erfolg / **Klartext-Fehler mit Lösungs-Knopf** (Bauprinzip A.1!) / Warnung |
### 0.2 Archetypen A2–A7 — einmal designen, überall komponieren
| # | Kit | Muss enthalten |
|---|---|---|
| A2 | **List-View-Kit** | Filterbar (Multi-Select, Datum-Range, Toggle-Chips) · Tabelle mit sortierbaren Headern · Karten-Alternative · Bulk-Select + Bulk-Action-Bar · Pagination (50/Seite) · Spalten-Konfiguration · CSV-Export-Button · Suchfeld · Archiviert-Toggle · Leerzustand mit CTA |
| A3 | **Detail-View-Kit** | Header mit Titel + Quick-Actions (Anrufen, Email, Termin, Task, Notiz) · Inline-Edit-Feld (Klick → Edit → Save/Cancel) · Related-Panels (verknüpfte Entitäten gruppiert) · **Activity-Stream-Komponente** (chronologisch, Typ-Icons, Filter) · Custom-Felder-Sektion (typ-abhängige Eingaben) · Tags-Zeile · Sub-Tabs |
| A4 | **Form/Input-Kit** | Alle 12 Feldtypen: Text, Textarea (Markdown), Zahl, Währung, Datum, Datum-Range, Select, Multi-Select, Boolean, Email, Telefon, Datei · Validierungs-Zustände + Klartext-Fehler · Auto-Complete-Picker (Kontakt/User/Entity) · Pflichtfeld-Markierung |
| A5 | **Modal/Wizard-Kit** | Einfacher Dialog · mehrstufiger Wizard mit Progress · Bestätigungs-Dialog (mit Confirm-Phrase-Variante für destruktive Aktionen) · Side-Panel/Drawer |
| A6 | **Settings/Connection-Kit** | Settings-Seitenlayout mit Sektionen · Toggle-Zeile mit Klartext-Beschreibung · **Connection-Card** (App-Logo, Status-Ampel grün/gelb/rot/grau, Klartext-Status, letzte-Sync-Zeit, Buttons Verbinden/Trennen/Re-Sync) · Key/Secret-Eingabe mit Reveal |
| A7 | **Zustands-Kit** | Leer (Illustration + CTA) · Laden (Skeleton) · Fehler (Klartext + Lösungs-Knopf) · Keine-Berechtigung · Offline-Hinweis 📱 |
### 0.3 Basis-Primitives
Buttons (primär/sekundär/destruktiv/ghost) · Badges + Status-Pills · Tags (farbig) · Avatare + Avatar-Stapel · Tabs · Dropdown-Menü · Date/Time-Picker · Tooltip · KPI-Kachel (Wert, Label, Trend-Pfeil, Vergleich) · Chart-Basis (Linie, Balken, Donut) · Drawer · Markdown-Editor + -Renderer · Datei-Dropzone mit Upload-Progress · Unterschriften-Feld (Touch) 📱 · Emoji-Picker · Mention-Highlight
---
## §1 AUTH-SCREENS (P2) — Fertig: So 21.06. (mit D0)
| Screen [Route] | Inhalt | Typ |
|---|---|---|
| Signup [`/signup`] | Email, Passwort (Stärke-Anzeige), Firmenname, Vor-/Nachname, Telefon, USt-ID, AGB/DSGVO/AVV-Checkboxen → erzeugt Tenant + Auto-SHK-Seed (kein Wizard!) | [A4] |
| Login [`/login`] | Email, Passwort, mCaptcha ab 3. Fehlversuch, Magic-Link-Alternative | [A4] |
| 2FA-Eingabe | 6-stelliger TOTP-Code, Trust-Device-Checkbox | [A4/A5] |
| Passwort vergessen [`/forgot-password`] | Email-Eingabe → Magic-Link | [A4] |
| Tenant-Auswahl | Tenant-Liste mit zuletzt-genutzt, Suchfeld | [A2] |
| Session-Verwaltung [`/settings/security`] | Aktive Sessions (Gerät, Browser, IP, Standort, letzte Aktivität) + Abmelden je Session + „überall abmelden" · Trust-Device-Liste mit Revoke | [A2/A6] |
| Profil [`/settings/profile`] | Name, Avatar, Telefon, Passwort ändern, 2FA einrichten (QR), Hell/Dunkel-Toggle. *(Sprache: fest DE — kein Wechsler v1)* | [A6] |
| Rollen-Editor [`/admin/roles`] | Rollen-Liste (Name, User-Anzahl) · Editor: Name, Beschreibung, Permission-Bundles + Advanced-Einzelrechte · 6 SHK-Rollen vorgeseedet | [A2+A6] |
| Gruppen [`/admin/groups`] | Gruppen-Liste mit Mitgliederzahl, Bulk-Add/Remove | [A2] |
| Mitarbeiter [`/admin/users`] | User-Liste (Name, Email, Rolle, Status, 2FA) · Einladungs-Modal (Email, Rolle, Gruppen, Nachricht) · Einladungs-Status-Liste · Deaktivieren mit **Reassign-Workflow** (offene Verknüpfungen anzeigen, Bulk-Übertragung) | [A2+A5] |
| Konto löschen [`/settings/account`] | Multi-Step: Erklärung → optional Daten-Export → Passwort+2FA → Countdown-Bestätigung | [A5] |
---
## §2 CRM-CLUSTER (P6/P7) — Fertig: Mi 24.06. → Noah-Demo #1
| Screen [Route] | Inhalt | Typ |
|---|---|---|
| Kontakt-Liste [`/contacts`] | Avatar+Name, Organisation, Kontaktstatus (Kontakt/Kunde/Bestandskunde), Email, Telefon, Tags, Verantwortlicher, letzte Activity · Filter: Verantwortlicher, Kontakttyp (Privatperson/Organisation), Kontaktstatus, Tags (UND/ODER), Organisation, Datum · Bulk: Tag/Zuweisen/Archiv/CSV | [A2] |
| Organisationen-Liste [`/contacts/organizations`] | Name, org_merkmal, Branche, Kontakt-Anzahl, Verantwortlicher, letzte Activity · *(Kontakt mit Kontakttyp=organisation; Label „Organisation", NICHT „Unternehmen")* | [A2] |
| **Kontakt-Detail** [`/contacts/:id`] | Stammdaten inline-editierbar · verknüpfte Kontakte/Organisationen mit **Kontaktart=Rolle** (Haupt-/Sekundärkontakt) · Tags · **Projekte**-Panel (alle verknüpften Projekte über ProjektKontakt, Pipeline-Sicht erkennbar)/Dateien/Tasks-Panels · Custom-Felder · Notizen (Markdown) · **Activity-Stream** (inkl. BCC-gelogde Mails + Anrufe!) · Quick-Actions: Anrufen (AirCall), Email (mailto), Termin, Task, Tag | [A3] — **das Muster-Template für alle Detail-Views** |
| Organisation-Detail [`/contacts/organizations/:id`] | Analog Kontakt + Kontakt-Verknüpfungen mit Primär-Markierung + Kontaktart (Rolle der Relation) | [A3] |
| **Lead-Inbox** [`/leads`] | Tabelle/Karten: Name, Email/Telefon, **Quelle**, Status, **Weiterverarbeitungsfreigabe (ja/nein/unklar)**, Verantwortlicher, Eingegangen, 80-Zeichen-Vorschau · Marker: „Mögliches Duplikat", „Spam-Verdacht" · Quick-Actions inline: Zuweisen, Status, **„Zu Projekt"** (Freigabe ja), Spam · Toggle „Spam ausblenden" | [A2 + Triage-Akzente] |
| Lead-Detail [`/leads/:id`] | Stammdaten · Quellen-Detail (Formular-Name/IP bzw. Inbound-Mail) · Spam-Score mit Begründung · **Match-Hinweise** (existierende Kontakte gleiche Email/Telefon, zum separaten Verknüpfen) · Re-Submission-Verlauf · Status-Wechsler (new/qualified/converted/lost/spam) · **Weiterverarbeitungsfreigabe-Schalter** | [A3] |
| **Lead → Projekt** (Konvertierung) | Bei `Weiterverarbeitungsfreigabe=ja`: Aktion „Zu Projekt" → erzeugt **Projekt** (`konvertiert_aus_lead_id`), Lead-Daten vorausgefüllt, Ziel-Pipeline + Start-Status wählbar, **Kontakt separat verknüpfen** (existierenden zuordnen über Match-Hinweise ODER neu anlegen) · Mängel-Banner bei fehlendem Namen · *(KEIN 4-Optionen-Promotion-Modal mehr — Kontakt-Anlage entkoppelt)* | [A5] — Kern-Moment der Kette! |
| Lead-Statistiken [`/leads/statistics`] | KPI-Kacheln: Eingegangen, Konversion Lead→Projekt, Reaktionszeit, Spam-Quote · Aufschlüsselung nach Quelle/Verantwortlichem · Trend-Chart mit Vorperioden-Vergleich | [A2+KPI-Kit] |
| Custom-Felder [`/admin/custom-fields`] | Felder je Entity-Ziel (projekt/kontakt/lead/rechnung), Typ, Nutzungs-Anzahl, Quelle (SHK-Template/eigen), Sortierung, Archiv · *(pro Pipeline via PipelineFieldConfig schaltbar)* | [A2] |
| Tag-Verwaltung [`/admin/tags`] | Name, Farbe, Verknüpfungs-Anzahl, Merge-Funktion | [A2] |
| Duplikat-Tool [`/admin/duplicates`] | Duplikat-Paare mit Match-Kriterium · **Side-by-Side-Merge** mit Feld-für-Feld-Auswahl | [A5 + Side-by-Side] |
| Quellen-Verwaltung [`/admin/lead-sources`] | Quellen mit Typ, 30-Tage-Lead-Count, Status + **Webhook-URL mit Token** (für Fremd-Website-Leads) | [A2/A6] |
| Anti-Spam-Settings [`/admin/lead-anti-spam`] | Limits pro Quelle/IP, Disposable-Domain-Check, Honeypot, Quarantäne-Modus | [A6] |
### Dazu im selben Paket (P3/P4/P5-Oberflächen — Archetyp-Compose, Bau läuft schon):
| Screen | Inhalt | Typ |
|---|---|---|
| Audit-Viewer [`/admin/audit`] | Zeit, Actor (+Kind-Marker: User/Automation/KI/Admin), Aktion, Subjekt, **deutscher Summary-Text** · Filter: Zeitraum, Actor, Kategorie, Subjekt-Typ · Detail-Drawer mit Diff-Ansicht · Export-Button (CSV/NDJSON, Zweck-Pflichtfeld). *(Kein Retention-Editor/Legal-Hold/Saved-Views — v2)* | [A2+Drawer] |
| Notification-Center [Topbar-Drawer + `/notifications`] | Einträge: Titel, Body, Actor, Zeit, Read-Status · Tabs Alle/Ungelesen · Mark-read/unread, Klick→Deeplink · Bulk | [A2] |
| Notification-Settings [`/settings/notifications`] | Event-Typen nach Modul gruppiert, je **In-App/Email-Toggle** · Master-Toggle „alle Emails aus". *(Keine Quiet-Hours/Bündelung/Push — v2)* | [A6] |
| Files-Browser [`/files`] | Tabelle/Grid-Umschalter: Name, Größe, Datum, Tags, verknüpfte Entität, Thumbnail · Filter: Entität, MIME-Gruppe, Tags, Verantwortlicher · Bulk: Tag/Verknüpfen/Archiv/ZIP. *(Keine Versions-Spalte — v2)* | [A2] |
| Upload-View + Datei-Dropzone | Drag&Drop, Multi-Datei-Queue mit Fortschritt je Datei, Fehler+Retry · **HEIC-Hinweis: „wird zu JPG konvertiert"** | [A4] |
| File-Detail [`/files/:id`] | Stammdaten, **Vorschau (Bild/PDF; HEIC→JPG)**, Tags, Notizen, verknüpfte Entitäten mit Rolle, Activity · Download, Ersetzen, Archiv. *(Kein Versionsverlauf — v2)* | [A3] |
| Task-Liste [`/tasks`] | Titel, Prioritäts-Marker, Fälligkeit (überfällig rot), verknüpfte Entität, Assignee, Status, Quelle · Presets: Meine/Erstellt/Alle · Bulk | [A2] — **als wiederverwendbare Komponente bauen** (P12/P14/P16 betten sie ein!) |
| Task-Detail + Anlage-Modal | Titel, Beschreibung (Markdown), Status/Priorität/Fälligkeit inline, Assignee (Person/Gruppe), Verknüpfung, Watcher, Kommentare, Quelle (manuell/Chat/Form/Automation) | [A3+A5] |
| Integrations-Katalog [`/admin/integrations`] | App-Karten nach Kategorie (ERP/Kommunikation/Kalender/Signatur/Payment/KI) · je: Logo, Beschreibung, Status-Ampel, aktive Connections | [A6] |
| Connection-Setup-Wizard | Voraussetzungen-Check → Credential-Formular (auto-generiert) → Health-Check → Initial-Sync-Option · Sync-History-Liste mit Klartext-Zusammenfassung je Lauf | [A5+A6] |
<div class="pagebreak"></div>
## §3 PAKET Fr 26.06. — Kanban, Form-Builder, Kampagnen-Editor, HR
| Screen [Route] | Inhalt | Typ |
|---|---|---|
| **Pipeline-Kanban (Sales-Sicht)** [`/projects?pipeline=…`] | EIN Projekt-Kanban, Pipeline = View (`typ_hint=sales`). Spalten je Status (PipelineStage): Name, Projekt-Anzahl, Aggregat-Volumen, Win-% · Karten: Titel, Volumen (**field-level-gegated via PipelineFieldVisibility, z.B. nur Vertrieb!**), Avatar, Termin-Datum, max. 3 Tags, Stuck-Marker · **Drag&Drop** zwischen Status · **Verloren-Status → Begründung-Pflicht** · *(KEIN Won-Handoff/„Projekt anlegen?"-Dialog — Projekt wechselt zum Gewinn nur in die Auftrags-Pipeline, kein zweiter Datensatz)* · Filter + „nur meine" | **BESPOKE** |
| Projekt-Liste [`/projects/list`] | Nummer (P-…), Projektname, Pipeline, Status, Volumen (gegated), Kontakt+Organisation, Termin-Datum · Cross-Pipeline mit Pipeline-Filter | [A2] |
| Projekt-Detail (Sales-Sicht) [`/projects/:id`] | Ein Projekt-Detail (gleicher Datensatz wie Auftrags-Sicht, §4). Stammdaten inline · **Status-Visualisierung klickbar** (pipeline-interne Statuswerte) · Lead-Herkunft-Hinweis (`konvertiert_aus_lead_id`) · Status-Historie mit Verweildauer · Gewonnen/Verloren-Banner mit **24h-Rückgängig** · Sub-Areas Kontakte/Termine/**Rechnungen**/Aktivität/Dateien/Tasks/Formulare · **„Angebot zur Signatur senden"-Button** | [A3+Status-Bar] |
| **Pipeline-Config** [`/admin/pipelines`] | Pipelines-Liste (typ_hint sales/auftrag/custom) · Editor: Statuswerte (PipelineStage) mit Drag&Drop, je Name, Art (offen/gewonnen/verloren), Win-%, Farbe · **Zugriff (PipelineAccess: wer sieht/bearbeitet je Rolle/User/Gruppe)** · **Feld-Config (PipelineFieldConfig: sichtbar/pflicht je Feld+Status)** · **Field-Level-Rechte (PipelineFieldVisibility: kann_sehen/kann_bearbeiten je Rolle/Gruppe/User — z.B. Volumen nur Vertrieb)** · Verloren-Gründe als Checklisten-Werte/Status-Metadaten | [A2+A6] **— v1-Pflicht-Feature (Entsch. 16.06.)** |
| **Form-Builder-Canvas** [`/forms/:id/edit`] | Feld-Palette (12 Typen) · Canvas mit Drag&Drop-Feldliste · Feld-Konfiguration (Label, Pflicht, Optionen) · **Conditional-Logic-Editor** („zeige Feld X wenn Y = Z") · Live-Vorschau · Publish-Toggle · Sharing: **öffentliche URL + QR-Code + iFrame-Code** *(personalisierte Links/JS-Snippet — v2)* · Post-Submit-Actions (Lead/**Projekt**/Task anlegen, Email, Webhook, Automation-Trigger) mit Field-Mapping | **BESPOKE** (schwerste UI nach Flow-Editor) |
| 🌐 Öffentliches Formular [`/f/{tenant}/{slug}`] | Gerenderte Felder, Conditional Logic live, mCaptcha, Submit → Erfolgs-Text oder Redirect · Tenant-Logo | **BESPOKE-Public** |
| Submissions [`/forms/:id/submissions`] | Tabelle der Antworten, Spalten = Felder, Filter, CSV, Detail mit Action-Log + PDF-Export | [A2/A3] |
| **Kampagnen-Editor** [`/email-marketing/campaigns/new`] | Schritte: Basis (Name, Sender, Betreff, Preheader) → **Inhalt** (Rich-Text + Personalisierungs-Tokens, Bild-Upload, Pflicht-Footer mit Impressum + Unsubscribe) → Empfänger (Segment-Wahl, **Vorschau mit Ausschluss-Aufschlüsselung**: Abgemeldet/Bounce/Suppression) → Test-Versand (max. 5 Adressen) → Zeitpunkt (sofort/geplant) → **Bestätigung mit Klartext-Checkliste** (Domain verifiziert? Unsubscribe? Impressum?) — Versand blockiert bei rotem Check | **BESPOKE** |
| Kampagnen-Liste + -Detail | Liste: Name, Status, Empfänger, Versanddatum, Stats · Detail: KPI-Header (Zugestellt/Geöffnet/Geklickt/Bounces/Abmeldungen in %), **Klick-Map** (URLs mit Counts), Pro-Empfänger-Tabelle, **A/B-Varianten-Vergleich** | [A2/A3+KPI] |
| Segmente [`/email-marketing/segments`] | Filter-Baum lesbar dargestellt, Live-Empfänger-Anzahl, Sample-Vorschau (50), dynamisch/statisch | [A2+Filter-Builder] |
| Sender + Suppression | Sender: From-Name/-Email, Domain-DKIM-Status, Default-Marker · Suppression-Liste: Adresse, Grund (Bounce/Beschwerde/manuell) | [A2/A6] |
| 🌐 Unsubscribe-Page [`/unsubscribe/{token}`] | Klartext, Bestätigungs-Button, optionale Grund-Auswahl, Erfolgs-Meldung | [A4-Public] |
| HR-Hub-Start [`/hr`] | Angepinnte Announcements, offene Bestätigungen, ausstehende Anträge, Team heute (Urlaub/krank), Geburtstage, Quick-Links | [Compose aus KPI+Listen] |
| Announcements + Detail | Feed mit Ungelesen-Filter · Detail: Markdown, Anhänge, Reaktionen, Kommentare (1 Ebene), **Bestätigungs-Button + Read-Receipt-Tabelle** (nur Autor/HR) | [A2/A3] |
| Urlaub & Krankmeldung [`/hr/leave`] | Tabs: Meine / Genehmigungen / Team · Antrag (M05-Form): Zeitraum, Art, Genehmiger · Genehmiger-Sicht: Approve/Reject/Rückfrage + **Konflikt-Hinweise** (Plantafel!) · Krankmeldung: Start, Rückkehr, **AU-Upload (verschlüsselt)** · Admin-Kalender-Monatssicht + KPI-Kacheln | [A2+A4+A5] |
| Lohnabrechnungen [`/hr/payslips`] | Eigene: Liste nach Periode + PDF-Viewer · Admin: alle MA, Einzel-/Bulk-Upload mit **Auto-Match-Vorschau** | [A2] |
| MA-Anträge [`/hr/requests`] | Template-Wahl (Spesen, Hardware, Schulung, Zeugnis), M05-Form, Genehmiger, Kommentar-Stream (interne Notizen verborgen), Entscheidung | [A2/A3] |
| Passwort-Safe [`/hr/password-safe`] | Vault-Liste → Eintrags-Liste (Titel, Tags — **keine Werte!**) → Detail: Reveal-Button je Wert (audit-geloggt!), Copy mit 30s-Auto-Clear, Access-Verwaltung | [A2/A3+Reveal] |
| Surveys [`/hr/surveys`] | Teilnahme: Items (Text/Rating/NPS/Choice/Boolean) · Auswertung: Häufigkeits-Charts, Durchschnitte, Textantworten · Admin-Editor mit Audience + Sichtbarkeit | [A4+Charts] |
| MA-Verzeichnis + Standorte | Karten/Tabelle: Avatar, Name, Position, Team, Standort, Click-to-Call/Mail/Chat · Standorte mit Karte | [A2] |
### Plattform-Admin (`admin.hivegrid.de` — eigene Shell, interner Polish reicht):
| Screen | Inhalt | Typ |
|---|---|---|
| Admin-Dashboard | **Basis-KPIs: Tenants, aktive User, MRR** + System-Health-Ampel + Queue-Status. *(Churn/ARPU/Sales-Pipeline — v2)* | [KPI] |
| Tenant-Liste + Detail | Liste: Name, Slug, Status, Plan, MRR, User-Anzahl · Detail: Stammdaten, Status-Wechsler, **Abo-Zusammenstellung (Feature-Konnektoren togglen + Legacy-Provider-Positionen — Abo-Baukasten!)**, Trial-Verlängerung, Notizen (Markdown, gepinnt), **Impersonate mit Begründungs-Pflicht** | [A2/A3+A6] |
| Manuelle Tenant-Anlage | Name, Slug, Branche, Admin-Email, Initial-Module, Trial-Dauer, Demo-Daten-Häkchen, Begründung | [A4] |
| User-Liste + Detail | Email, Name, Tenants, 2FA-Status, Sessions · Ops: 2FA-Reset, Session-Revoke, Deaktivieren | [A2/A3] |
| Feature-Flags [`/admin/feature-flags`] | Flag-Liste (Key, Status, Targeting), Filter-Editor (plan-tier!), Tenant-Override mit Ablauf. *(Massen-Statistik — v2)* | [A2+A6] |
| Health + Worker-Queues | Service-Ampeln (Web/API/Worker), DB/Redis, Storage · BullMQ-Queues: Active/Waiting/Failed je Queue, Job-Detail mit Error-Stack, Retry/Pause | [A2+KPI] |
| Support-Inbox | Tickets: Betreff, Tenant, Status, Priorität, Zugewiesen · Detail: Konversation, Antwort (Markdown), interne Notiz · **speist sich aus Feedback-Widget!** | [A2/A3] |
| Admin-Audit | Cross-Tenant-AuditLog mit Filter + Export | [A2] |
*(Entfällt v1: AdminUser-/AdminRole-Verwaltung, Plattform-Lead-Pipeline + Deal-Kanban, KWP-Sync-Status — alles v2.)*
<div class="pagebreak"></div>
## §4 PAKET Mi 01.07. — Plantafel + Chat
| Screen [Route] | Inhalt | Typ |
|---|---|---|
| 📱 **Plantafel** [`/projects/plantafel`] | Desktop: Y = Mitarbeiter, X = Zeit (Tag/Woche/Monat) · Einträge: Projekt-Titel, Status-Farbe, Adresse-Kurzform · **Drag&Drop verschieben/resizen** · **Konflikt-Indikatoren** (Doppelbelegung, Urlaub/krank aus HR!) · MA-Filter, Projekt-Filter · **Monteur-Mobil-Modus: „Meine Termine heute"** — Liste mit Adresse + Navigations-Link, Tap-Statuswechsel (bestätigt→unterwegs→fertig), **offline-fähig** + „Meine Woche" kompakt | **BESPOKE** (höchste Priorität nach Flow-Editor) |
| Projekt-Kanban (Auftrags-Sicht) + Liste [`/projects?pipeline=…`] | Derselbe Projekt-Kanban (Pipeline `typ_hint=auftrag`), Karten zusätzlich: Mitglieder-Avatare (PL hervorgehoben), Zeitraum, Mängel-Marker · Status-Wechsel mit **Abnahme-Pflicht-Block** | [Kanban-Reuse] |
| 📱 Projekt-Detail [`/projects/:id`] | EIN Projekt-Datensatz (gleiche Route/Entität wie Sales-Sicht §3). Stammdaten, Lead-Herkunft-Hinweis (`konvertiert_aus_lead_id`), PL + Mitglieder (ProjektMitglied) mit Rollen, Tabs: Übersicht/Mitglieder/Tasks/Termine/**Rechnungen**/Dateien/Formulare/**Abnahmen**/Aktivität (inkl. früherer Sales-Status-Historie — derselbe Datensatz, kein read-only Fremd-Objekt) · **Mobil-Modus: Stammdaten + heutige Tasks + Abnahme-Button + One-Tap-Foto-Upload** · *(kein KWP-Felder-Tab — KWP komplett v2)* | [A3 + 📱-Variante] |
| 📱 **Abnahme-Workflow** [`/projects/:id/acceptance/new`] | SHK-Abnahme-Formular (Datum, Anwesende, Druckprobe ja/nein+Wert, Funktionsprüfung, Zählerstände, Dokumente-Checkliste, **Mängel-Repeater mit Foto je Mangel**, Bemerkungen) → Mängel-Klassifizierung (kritisch/klein/kosmetisch) → **Touch-Unterschriften Kunde + Monteur** → PDF + Auto-Email · **offline-fähig, Sync bei Verbindung** | **BESPOKE-Mobile** |
| **Chat** [`/chat`] | Channel-Index: Name, Avatar, Snippet (80 Z.), Unread-Badge, Mention-Marker, Pin/Mute, Projekt-Stage bei Projekt-Chats · **Channel-Detail:** Verlauf mit Datums-Separatoren, Nachricht = Avatar+Name+Zeit, Markdown-Body, **Reactions** (Emoji+Count), **Thread-Indikator**, Anhänge inline, Edited-Marker, „X von Y gelesen" · Composer: Markdown, Emoji, @-Mention, Anhang, Entwurf-Autosave · **Tipp-Indikator** · Thread-Detail-Ansicht · Pinned-Übersicht (max 50) · Mentions-Aggregat · Cross-Channel-Suche · Neuer Channel/DM-Modal · Channel-Settings (Mitglieder, Archiv) · Admin: DM-Audit mit Begründungs-Pflicht-Banner | **BESPOKE** |
## §5 PAKET Fr 03.07. — Flow-Editor, Dashboard, Booking, Kalender
| Screen [Route] | Inhalt | Typ |
|---|---|---|
| **Flow-/Node-Editor** [`/automations/:id/edit`] | Graph-Canvas: Knoten + Kanten, **Knoten-Katalog nach Modul** (Trigger: CRM/Sales/Projekte/Email/Forms/Kalender/Zeit/Webhook · Aktionen: CRM/Notification/HTTP/Task/If-Else/Delay/Loop) · Konfigurations-Panel je Knoten mit **Klartext-Label** · Mini-Map, Zoom, Undo/Redo · **Dry-Run-Vorschau:** „trifft X Datensätze, sendet an: [Liste]" + Bestätigungs-Pflicht · **Sprach-zu-Automation:** Text-/Spracheingabe-Feld → KI baut Flow-Vorschau → User bestätigt (nie Auto-Aktivierung!) · Loop-Guard-Warnmodal mit Abhängigkeits-Graph | **BESPOKE — schwerste UI der App, ab 22.06. täglich 1h** |
| Automation-Liste + Executions | Liste: Name, Trigger, Status, Läufe (30d) · Execution-Detail: **Step-by-Step-Verlauf mit Klartext je Schritt**, Dauer, **24h-Rückgängig-Button**, Retry | [A2/A3] |
| Template-Katalog [`/automations/templates`] | SHK-Vorlagen nach Kategorie mit Beschreibung + Use-Case, „Verwenden"-Button | [A2] |
| **Dashboard** [`/dashboard`] | **3 feste Rollen-Layouts** (kein Drag&Drop!): **GF:** Begrüßung, Sales-KPIs, Umsatz-Forecast (einfach), Projekt-KPIs, Auslastung, offene Mängel, Team-heute · **Büro:** Begrüßung, Projekt-KPIs, meine Tasks, Anrufe heute, HR-Anträge · **Monteur 📱:** meine Termine heute, meine Projekte, meine Tasks · Widgets: KPI-Kachel, Liste, Trend-Chart · Edit = nur Widget-Filter/Zeitraum konfigurieren | [KPI+Widget-Compose] |
| **Cmd+K-Suche** [global] | Modal: Live-Suche (300ms debounce), Treffer gruppiert nach Entity-Typ mit Icon, Titel, Kontext-Snippet mit **Match-Highlight**, Tastatur-Navigation · Leer-Zustand: letzte Suchen · Vollbild-Variante [`/search`] mit Filter-Sidebar (Typ, Datum, Verantwortlicher, Tags) + Trefferzahl | **BESPOKE** (klein) |
| 🌐 **Booking-Page** [`/b/{tenant}/{slug}`] | Slot-Picker (Kalender-Grid mit freien Slots, timezone-aware), Intake-Formular (M05), mCaptcha, Bestätigung + **Add-to-Calendar (.ics)** · Tenant-Logo · iFrame-Embed-Variante | **BESPOKE-Public** (höchster Polish!) |
| Buchungen intern [`/bookings`] | Liste: Termin, Endkunde, Page, Status, Mitarbeiter · Detail: Daten, Form-Antworten, Kalender-Status · Ops: **stattgefunden/No-Show markieren, Storno mit Begründung + Auto-Mail, Verschieben mit Slot-Picker, Mitarbeiter-Re-Assignment** (M129 voll!) | [A2/A3] |
| Booking-Page-Editor + Verfügbarkeit | Grunddaten, Dauer, Mitarbeiter-Auswahl (eine Zuteilungs-Strategie: „erster freier"), Bestätigungs-Mail-Template, Intake-Form-Wahl, Embed-Code · Verfügbarkeit: Wochenregel-Tabelle + Ausnahme-Daten | [A6+A4] |
| Kalender [`/calendar`] | Monats-/Wochen-Grid mit Terminen aus Google-Sync + HiveGrid-Quellen (Booking, Plantafel) · Verbindungs-Settings: Google-Connect-Card, Kalender-Auswahl, Sync-Richtung, Konflikt-Log *(kein Outlook — v2)* | **BESPOKE** (mittel) |
| Signatur-Wizard [im Projekt] | PDF-Upload → Unterzeichner (Name, Email, Reihenfolge) → Provider (PandaDoc) → Senden · Status-Tracking je Unterzeichner (entwurf/gesendet/angesehen/signiert/abgelehnt) + Erinnerung + Widerruf | [A5+A6] |
## §6 PAKET Mo 06.07. — KI, Telefonie-Reste, Billing, DSGVO (Compose)
| Screen | Inhalt | Typ |
|---|---|---|
| KI-Settings [`/admin/ai`] | Use-Case-Toggles, Modell-Wahl (Mistral), Token-Limit, **EU-Datenresidenz-Klartext** | [A6] |
| AI-Credits [`/admin/usage/ai`] | Saldo, Verbrauch je Use-Case (Donut), Verlauf, Top-User, **80%-Warnbanner**, Hochrechnung | [KPI+Charts] |
| AirCall-Setup + Anrufe | Connect-Card + **User-Binding** (AirCall-User ↔ HiveGrid-User mit Auto-Match) · Anruf-Liste: Nummer, Richtung, Dauer, gematchter Kontakt, Notiz-Snippet · Anruf-Detail: Match-Override, Notiz-Editor (Markdown), Aufnahme-Link · Click-to-Call-Button + eingehender-Anruf-Notification | [A6+A2/A3] |
| Sende-Domain [`/settings/integrations/email`] | Domain-Eingabe, **DNS-Records (DKIM/SPF/DMARC) mit Copy-Button**, Verifikations-Status-Ampel, 5-Min-Prüf-Indikator · **BCC-Logging:** Toggle + angezeigte BCC-Adresse + Klartext „Mails erscheinen am Kontakt" *(kein Postfach/Inbox/Compose — v2!)* | [A6] |
| Abo-Übersicht [`/admin/subscription`] | Basis-Plan + **gebuchte Feature-Module als Positionsliste mit Preisen** · Status/Trial-Countdown · Verbrauch: Automation-Läufe, AI-Tokens, Speicher mit Quota-Balken · Legacy-Provider-Portal-Embed (Rechnungen, Zahlungsmethode) · Pausieren/Kündigen *(kein Self-Service-Modul-Toggle — Admin macht das, v2)* | [A6+KPI] |
| Demo-Daten [`/admin/onboarding/demo-data`] | **Settings-Knopf „Beispieldaten anlegen"** (25 Datensätze, Klartext-Liste was kommt) · Demo-Liste mit Zähler + Lösch-Funktion · „Demo ausblenden"-Filter erscheint in allen Listen *(kein Wizard, kein KI-Walkthrough — v2)* | [A6] |
| Erste-Schritte-Checkliste [`/onboarding/checklist`] | Items mit Status-Häkchen, Klartext, CTA-Link je Item (KWP verbinden → v2-Item ausgeblendet), manuell abhakbar, ausblendbar | [A2] |
| Privacy-Hub [`/admin/privacy`] | Export: Job-Liste mit Status/Progress/Download (72h-Link) · **Tenant-Löschung: Multi-Step** (Erklärung 30-Tage-Grace → Export-Angebot → Legacy-Provider-Hinweis → Passwort+2FA → **Slug als Bestätigungs-Phrase**) + Grace-Countdown mit Abbruch · Subprozessoren-Tabelle (Name, Land, EU-Marker, Zweck, DPA-Link) · AVV: aktuelle Version als PDF + Akzeptanz-Historie | [A2+A5] |
| User-Daten-Export [`/settings/account/data-export`] | Klartext was exportiert wird, Start-Button, Job-Status mit Download | [A6] |
| **Feedback-Widget** [global, klein] | Schwebender Button → Mini-Form (Kategorie, Text, Screenshot-Häkchen) → landet in Admin-Support-Inbox | [A5-klein] |
---
## §7 Zähl-Übersicht & Diskussionspunkte
**~95 v1-Screens** = **~12 BESPOKE** (Flow-Editor, Form-Builder + Public-Form, Plantafel, Abnahme, Chat, Sales-Kanban, Kampagnen-Editor, Booking-Page, Kalender, Cmd+K, Dashboard-Compose) + **~83 Archetyp-Composes** (Stunden-Arbeit nach D0).
**Offene Punkte (Raffael entscheiden):**
1. **Dashboard-Rollen-Layouts:** Spec definiert 7 Presets (auch Vertriebsleiter, Vertriebler, PL, Marketing) — beschlossen sind 3 (GF/Büro/Monteur). Weitere Presets sind nur Widget-Listen (~0 Aufwand) — bei Zeit via Beschleunigungs-Leiter nachschieben oder v2?
2. **KI-Lead-Zusammenfassung** (Widget im Kontakt/Projekt-Detail, on-demand): nicht in den 5 v1-KI-Milestones — v2 oder Beschleunigungs-Kandidat?
3. **Notification-Test-Tool** (Admin sendet Test-Notification): Mini-Screen, hilft beim Demo-Vorbereiten — drin lassen?
---
*Quellen: 36 Specs `_bmad-output/specs/` · Scope-Schnitte #1–#12 (`SCOPE-V1-CUTS.md`) · Archetypen (`DESIGNER-FIRST-PLAYBOOK.md`) · Deadlines (`TIMELINE.md`). Entfallene Screens (Portal, Mobile-PWA, Help-Center, Wizard, Postfach-Inbox, KWP-UI, AdminUser-Verwaltung, Quiet-Hours, Datei-Versionen) sind bewusst NICHT gelistet — v2-Planung erzeugt ihre eigene Map.*
@@ -1,134 +0,0 @@
---
pdf_options:
format: A4
margin: 16mm
css: |-
body { font-size: 10.5px; font-family: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif; }
h1 { font-size: 19px; } h2 { font-size: 14px; border-bottom: 2px solid #f5a623; padding-bottom: 3px; }
table { font-size: 9.5px; border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ccc; padding: 3px 5px; text-align: left; vertical-align: top; }
th { background: #fff7e8; }
code, pre { background: #f4f4f4; font-size: 9px; }
pre { padding: 8px; }
---
# 4-Wochen-Sprint-Plan — HiveGrid 2.0 v1 (nach Scope-Schnitt)
**Stand:** 2026-06-12 (ersetzt Fassung vom 10.06.) · **Frist:** fix, 4 Wochen (20 Arbeitstage) · **Team:** Dev A, Dev B, Dev C (je eigene Claude/GSD-Instanz) + Designer
**Scope:** **v1 = 133 Milestones / 90 Requirements** (Scope-Schnitte #1–#12, Historie: `SCOPE-V1-CUTS.md`; v2 = 43 MS committed-deferred, **KWP = erstes v2-Modul**)
**Velocity:** 133 / 3 Devs / 20 Tage ≈ **2,2 MS/Dev/Tag** (effektiv ~2,1 mit den 10 Dünnungen) — komfortabler Puffer.
---
## 1. Tag-1-Pflichten (kalendergebunden — KI kann das nicht beschleunigen)
| # | Was | Blockt | Status / Vorlauf |
|---|---|---|---|
| A1 | **KWP:** Callback-URL zurückmelden (`https://app.hivegrid.de/integrations/kwp/oauth/callback`) + **bnWin.net auf 8.1 N3** bei Geerkens-IT | v2-P10 (erstes v2-Modul) | ✅ entschärft — Zugang lt. KWP-Mail ~**19.07.** (nach Launch); kein Sprint-Risiko mehr, nur Vorbereitung |
| A2 | **Google Cloud OAuth-App: nur noch Calendar-API-Scope** beantragen | P16 Kalender | 🟠 Verifizierung Tage–Wochen; Gmail-Scopes durch Postfach-Cut NICHT mehr nötig |
| A5 | **Legacy-Provider-Konto + Live-Verifizierung** | P20 | 🟠 Tage; Test-Mode reicht für Dev |
| A6 | **Sende-Domain: SPF/DKIM/DMARC für Mailjet + Warm-up** | P1/P2/P14 — **Marketing-Kampagnen brauchen Reputation!** | 🔴 sofort, Warm-up braucht Laufzeit |
| B2 | **AirCall**-Konto + Sandbox + Webhooks | P15 | 🟡 Tage |
| B4 | **PandaDoc** (Standard) Konto + Sandbox; DocuSign optional | P16 Signatur | 🟡 Tage |
| B5 | **Hetzner-Projekt `HiveGrid`** (Infra-ADR-009): Object-Storage-Bucket (S3) + Token · **Mistral**-Key (LLM) · DEK-Master-Key in Coolify-Secrets (AD-8 revidiert — kein Cloud-KMS) | P4/P5/P13/P17 | 🟢 Stunden (Infra-Repo-Muster) |
| B6 | **Mistral**-API-Key (AlephAlpha → v2) | P13 Fallback | 🟡 kurz |
| B10 | **Subframe**-Lizenzen Designer + Devs | Designer ab W1 | 🔴 sofort |
| C1–C5 | Eigene Infra: Meilisearch (bis Ende W2) · mCaptcha (`infra/mcaptcha/`, Ende W1) · Hosting/Staging (Mitte W1) · Postgres/Redis/PgBouncer · Domains+Wildcard-TLS | CI/Gates | Ops parallel W1–W2 |
| E1 | **Noah: 4 Freitags-Slots** blocken | Gates | sofort terminieren |
| E2 | ~~KWP-Ansprechpartner identifizieren~~ ✅ läuft (KWP-Mail an Noah, 12.06.) · **NEU: Noah fragen — gehört der Lagerist-Arbeitsplatz (M070) zum Validierungs-Versprechen?** | A1 / v2-Planung | erledigt / bei Demo #1 |
| E3 | Echte SHK-Beispieldaten (Pipelines, Felder, Rollen) für Seeds | bis W2 | |
| **E6** | **AVV-Vertragsvorlage + DSGVO-Auskunfts-Vorlage vom Anwalt** | Launch (Auftragsverarbeiter-Pflicht!) | 🟠 diese Woche beauftragen |
**Erledigt/entfallen:** Apple-Konto ✅ vorhanden · Google Play, FCM/APNs, Microsoft Entra, HalloPetra, Memberspot/Boobora → v2-Vorbereitung, nicht sprint-kritisch. **AD-6 (Mailjet) + AD-7 (mCaptcha) gelockt** — Boilerplate-verdrahtet.
## 2. Arbeitsweise
- **1 Phase = 1 Branch/Worktree = 1 Dev**; tägliche Integration auf `main`; CI ist der Sheriff (Smoke, Visual-Reg inkl. **Mobile-Viewport**, Hot-Swap-Drill, i18n-Lint).
- **Konnektor-Pflicht (NEU):** Jede Modul-Phase registriert ihr Entitlement-Gate (`tenantHasModule()`) — Merge-Checkpunkt wie Sidebar-/Audit-Wiring.
- Pro Phase: `/gsd-plan-phase N` (liest PHASE-SOURCES inkl. Scope-Schnitt-Notes + Retro-Integrationen) → kurzes Review → `/gsd-execute-phase N`.
- Designer läuft 1–2 Phasen voraus (D0-Archetypen → CRM → Bespoke: Kanban, Plantafel, Flow-Editor, Form-Builder). Monteur-Screens **mobile-first** (PWA ersetzt native App in v1).
## 3. Wochenplan (133 MS auf 3 Tracks)
### Woche 1 — Fundament & Identität *(Ziel: P1 ✓, P2 ✓, P4 ≥ 50 %)*
| Wer | Mo–Mi | Do–Fr |
|---|---|---|
| **Alle 3** | **P1 in 3 Strängen:** A: Ist-Stand + EU-Sterilisation (inkl. GA/ConvertKit raus) + Contracts/URL-Schemata · B: Service-Kerne (Audit/notify/i18n/**Flag-Engine+Konnektor-Muster**) · C: Hot-Swap-Maschine + Walking-Skeleton + PWA-Manifest | A+B: **P2** (Auth/RLS/RBAC + Subscription-Stub; API-Keys → v2) · C: **P4** (Files/Tasks, polymorphe EntityLink, HEIC→JPG) |
| Designer | **D0:** System + App-Shell + Archetypen + Zustände | CRM-Screens briefen |
**Gate Fr W1:** Hot-Swap-Drill grün · **RLS-Cross-Tenant-Beweis** · Konnektor-Muster am Skeleton demonstriert.
### Woche 2 — Plattform + CRM *(Ziel: P3, P4, P5, P6 ✓; P19 ≥ 80 %)*
| Wer | Mo–Mi | Do–Fr |
|---|---|---|
| Dev A | **P5** Apps-Engine (Vertrag für 5 Phasen!) | **P6** CRM (mit B) |
| Dev B | P4 fertig → **P3** Querschnitts-Oberflächen (5, DE-only) | **P6** CRM (mit A) |
| Dev C | **P19** Plattform-Admin (7, inkl. Abo-Zusammenstellung; Boilerplate-Identitätsmodell + admin.hivegrid.de-Host-Routing) | **P17** HR (7) Start |
| Designer | CRM-Cluster (Liste/Detail/Modal) | Bespoke: Kanban, Plantafel; Flow-Editor briefen |
**Gate Fr W2:** CRM klickbar (**Noah-Demo #1**) · Konnektoren an P3–P6-Modulen aktiv.
### Woche 3 — Kern-Kette + Kommunikation *(Ziel: P7, P8, P9, P14, P15 ✓; P17 ✓; P20 ≥ 80 %)*
| Wer | Mo–Mi | Do–Fr |
|---|---|---|
| Dev A *(kritischer Pfad)* | **P7** Lead (4) → **P8** Sales (7) | **P9** Projekte (6, Plantafel offline!) |
| Dev B | **P14** Email & Marketing (6, inkl. BCC-Brücke + Kampagnen) | **P15** Telefonie & Chat (9) |
| Dev C | **P17** fertig → **P20** Billing (8, Abo-Baukasten-Recut!) | **P16** Start (15 — größte Phase) |
| Designer | Plantafel + Kanban liefern; Form-Builder, Kampagnen-Editor | Booking-Pages (public!), Wizard entfällt |
**Gate Fr W3:** Kette **Lead → Sales → Auftrag** E2E (**Noah-Demo #2**) · P14-Kampagne an Test-Segment versendet.
### Woche 4 — USP, Härtung, Launch *(Do = Freeze, Fr = Go/No-Go)*
| Wer | Mo–Mi | Do–Fr |
|---|---|---|
| Dev A | **P11** Suche/Dashboard (5) → E2E-Härtung der Kette (Lead→Auftrag), Lasttest, Bug-Bash | E2E-Integration + Launch-Stützen (KWP entfällt — v2) |
| Dev B | **P12** Automation (8, voll!) → **P13** KI (5) | USP-Härtung (Promptfoo, Guards, Sprach-zu-Automation) |
| Dev C | **P16** fertig (Kalender nur Google!) → **P21** (2 + Feedback-Widget + FAQ) | Launch-Checkliste, DSGVO-E2E, AVV-Check |
| Designer | Politur extern sichtbarer Flächen (Booking public, Marketing-Mails) | Visual-Reg-Baselines final |
**Do W4: Feature-Freeze. Fr W4: Voll-Walkthrough mit Noah (#3) → Go/No-Go Big-Bang.**
## 4. Engstellen (ehrlich)
1. **W4 trägt P11–P13 + P16-Rest (~20 MS auf A+B+C)** — durch den P10-Wegfall (#12) deutlich entspannt; Dev A gewinnt 2–3 Tage für E2E-Härtung/Bug-Bash. Der KWP-Recut wandert komplett in die v2-Planung (API-Zugang ~19.07.).
2. **P16 bleibt die größte Phase (15)** — Dev C hat sie über W3-Do bis W4-Mi. Form-Builder-Design muss Ende W2 vorliegen.
3. **Marketing-Zustellbarkeit:** Kampagnen ohne Domain-Reputation = Spam-Ordner. Warm-up (A6) läuft ab Tag 1, erste echte Kampagne frühestens W3.
4. **Google-Calendar-Verifizierung** kann W4 reißen → Kalender-Feature ggf. im Testmodus launchen (interne Workspace-Konten), Verifizierung läuft parallel.
## 5. Notfall-Leiter (NEU — nur wenn ein Gate reißt; vorab beschlossen)
```
NIEMALS opfern: P1–P9 (Kette; P10 KWP = v2 seit #12) · P12 Automation · Marketing-Kern · Konnektor-Pflicht
Sprosse 4 (zuerst): A/B-Tests (M103-Teil) · Sales-Tiefen-Analytik · Chat-Polish (Threads/Reactions/Pins)
Sprosse 3: Signatur (M130–132) → PandaDoc manuell, Status händisch
Sprosse 2: Booking + Kalender (M118–120, M126–129) → Terminanfragen via Formular
Sprosse 1 (letzte): HR-Komfort (M137 Bekanntmachungen, M139 Berichte/Surveys) — Urlaub/Krank/Plantafel-Konflikt bleiben
```
Alle Sprossen sind durch Dependency-Inversion sauber abtrennbar; Chat-Kern und HR-Kern fallen NIE (User-Priorität „ultra wichtig").
## 5b. Beschleunigungs-Leiter (Gegenstück — wenn wir SCHNELLER sind)
Vorab beschlossen wie die Notfall-Leiter; Detail in `TIMELINE.md`. Kurzform:
```
Sprosse 1: nächste eigene Phase sofort ziehen (9:00-Sync)
Sprosse 2: Track-übergreifend aushelfen (kritischer Pfad: P16, P8/P9)
Sprosse 3: Puffer ≥3 Tage → Launch-Vorzieh-Prüfung mit Noah (Legacy-Provider live + Staging-Abnahme)
Sprosse 4: v2-Vorzieher: (a) KWP-Recut-Vorarbeit (Doku, kein Mock-E2E) → (b) Self-Service-Abo-UI → (c) Postfach-Sync
Pflicht: pro gewonnener Woche ≥1 Tag Härtung (Bug-Bash/Lasttest/Security)
NIEMALS: Cut-Rückholung in Eigenregie · Goldrand an internen Screens · Gates verschieben (außer Sprosse 3)
```
## 6. Gates
| Gate | Beweis | Bei Riss |
|---|---|---|
| Fr W1 | Hot-Swap grün + RLS-Beweis + Konnektor-Demo | Sprosse 4 |
| Fr W2 | CRM klickbar (Noah #1) | Sprosse 3–4 |
| Fr W3 | Kette E2E (Noah #2) + Test-Kampagne | Sprosse 2–3 |
| Do W4 | Feature-Freeze | — |
| Fr W4 | Voll-Walkthrough (Noah #3) → **Go/No-Go Big-Bang** | Launch = Kern + Fast-Follow-Liste |
---
*HiveGrid ist Multi-Kunden-SaaS; Geerkens = erster Kunde + Investor. Nichts hartkodieren — alle Seeds/Flows generisch pro Mandant. v2 startet direkt nach Launch mit eigener Planung (30 MS + Mobile-PWA-Ausbau — PWA-only, kein nativer Client/Store, AD-17).*
@@ -28,10 +28,10 @@ css: |-
> ⛔ **KI→MCP-Pivot ([[AD-26]], 2026-06-22):** **R-P13** (KI-Layer), **D-P13**, **EXT-11** (Mistral-Key) und Milestones **M083–M088** entfallen. **R-P12b** ist das letzte v1-Glied der Raffael-Kette; Sprach→Automation ist gestrichen. In v2 ersetzt **[[VR-MCP]]/[[VD-MCP]]** den alten P25-HiveMind/RAG-Slot.
<p class="lead">Jedes Ticket an seinem Start-Tag · ID · Wer · Fenster (Start→Ziel) · Aufgabe · 149 Sprint-Tickets (v1: 107 · v2: 42) + 2 v3-Backlog</p>
<p class="lead">Jedes Ticket an seinem Start-Tag · ID · Wer · Fenster (Start→Ziel) · Aufgabe · 150 Sprint-Tickets (v1: 106 · v2: 44) + 2 v3-Backlog</p>
<p class="meta">Generiert aus Plane (Single Source) · Arbeitsrhythmus Mo–So ≥8 h · „bis" = Ziel-/Fertig-Datum (Mehrtages-Tickets laufen bis dahin) · rot = Meilenstein/Gate-Tag · <span style="color:#b91c1c">rote Ticket-ID</span> = Block 2 (Partner-API offen, agil). Neu erzeugen: <code>python3 .planning/plane-sync/gen_dayplan.py</code></p>
## Woche 1 · Di 16.–Fr 19.06. — Fundament & Identität · 40 Tickets
## Woche 1 · Di 16.–Fr 19.06. — Fundament & Identität · 39 Tickets
*→ Gate W1 (Fr 19.06.)*
### Di 16.06. · 23 Ticket(s)
@@ -60,7 +60,7 @@ css: |-
| R-P1a | Raffael | 17.06. | P1 EU-Sterilisation + Contracts + URL-Schemata |
| R-P1c | Raffael | 17.06. | P1 Hot-Swap-Maschine + Walking-Skeleton + PWA |
| R-REFIT | Raffael | 21.06. | ER-Modell-Re-Fit P6–P9 (Requirements/Screen-Map/Phase-Sources) |
### Mi 17.06. · 7 Ticket(s)
### Mi 17.06. · 6 Ticket(s)
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
@@ -68,7 +68,6 @@ css: |-
| H-TXT | Haris | 17.06. | Website-Texte schreiben |
| J-CONTENT | Dejan | 17.06. | Content/Texte einbauen |
| J-LAW | Dejan | 18.06. | Rechtstexte einbauen (Anwalt) |
| J-QA | Dejan | 18.06. | QA + Lead-Routing-Test |
| N-TXTABN | Dejan/Haris | 17.06. | Website-Texte abnehmen |
| R-P1b | Raffael | 18.06. | P1 Service-Kerne (Audit/notify/i18n/Flags) + Konnektor-Muster |
### Do 18.06. · 7 Ticket(s)
@@ -78,7 +77,7 @@ css: |-
| AK-P4a | Akeshan | 19.06. | P4 Files (chunked Upload, HEIC→JPG, ClamAV) |
| D-D0b | David | 20.06. | D0 Archetypen A2–A7 + Zustands-Kit + Primitives |
| D-FLOW | David | 03.07. | Flow-/Node-Editor (Bespoke, Langläufer ab 18.06.) |
| H-INBOUND | Haris | 19.06. | Lead-Sheet + Inbound-Prozess (<24h) |
| H-INBOUND | Haris | 19.06. | Nativer Lead-Inbound-Prozess (<24h) |
| H-PITCH | Haris | 19.06. | Pitch-Deck + Gesprächsskript |
| J-LIVE | Dejan | 18.06. | WEBSITE LIVE |
| R-P2a | Raffael | 19.06. | P2 Mandant + Auth (Email/PW/HIBP) + Sessions + TOTP |
@@ -234,7 +233,7 @@ css: |-
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| AK-P20 | Akeshan | 08.07. | P20 Billing (Legacy-Provider Abo-Baukasten) + Onboarding + Branding |
| AK-P20 | Akeshan | 08.07. | P20 Billing-Grundlagen + Onboarding + Branding |
| D-P20 | David | 08.07. | Screens P20 — Billing/Onboarding/Branding (ex-D-REST) |
<h3 class="gate">Do 09.07. · 3 Ticket(s)</h3>
@@ -251,14 +250,14 @@ css: |-
|---|---|---|---|
| N-GONOGO | Dejan/Haris | 10.07. | Voll-Walkthrough + Go/No-Go |
## v2-Woche 1 · Mo 13.–So 19.07. — Public-API / Postfach / Abo / MCP · 11 Tickets
## v2-Woche 1 · Mo 13.–So 19.07. — Public-API / Postfach / Abo / MCP · 13 Tickets
*→ Webinar Nr. 1 (Di/Mi 14./15.07.)*
### Mo 13.07. · 7 Ticket(s)
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VA-P23 | Akeshan | 17.07. | Postfach-Sync: Gmail/Outlook OAuth + Inbox + Threading + Versand (M096-098) |
| VA-P24a | Akeshan | 15.07. | Self-Service-Abo-Baukasten-UI (M28-Delta) |
| VA-P24a | Raffael | 15.07. | Self-Service-Abo-Baukasten-UI (M28-Delta) |
| VD-P22 | David | 17.07. | Screens P22 — Public-API-Keys (ex-VD-5) |
| VD-P23 | David | 17.07. | Screens P23 — Postfach-Inbox (ex-VD-1) |
| VD-P24 | David | 15.07. | Screens P24 — Abo-Baukasten + Wizard (ex-VD-1) |
@@ -269,10 +268,12 @@ css: |-
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VR-P22b | Raffael | 17.07. | Public-API: API-Key-Auth/Scopes/Rate-Limit (M162/M027) + Webhooks (M163) |
### Do 16.07. · 1 Ticket(s)
### Do 16.07. · 3 Ticket(s)
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VA-P26a | Akeshan | 05.08. | Customer-Portal: Auth/Magic-Link + Projekt-Sicht + Status-Mails (M141/142) ⭐ · retimiert, Start 16.07. |
| R-LEADS | Raffael | 31.07. | Native Plattform-Leads (M040a) + Migration/Cutover + `lead-inbox`-Decommission |
| VD-MCP | David | 20.07. | Screens MCP — MCP-Connection-Verwaltung + Scope/Audit |
### Sa 18.07. · 2 Ticket(s)
@@ -281,24 +282,16 @@ css: |-
| VA-P24b | Akeshan | 20.07. | Onboarding-Wizard-UI (M157) |
| VR-MCP | Raffael | 20.07. | MCP-Server: Read-Ressourcen + bestätigungspflichtige Action-Tools |
## v2-Woche 2 · Mo 20.–So 26.07. — KWP / Portal / Mobile · 15 Tickets
*→ KWP-Sync-E2E mit Geerkens (Fr 24.07.)*
### Mo 20.07. · 7 Ticket(s)
## v2-Woche 2 · Mo 20.–So 26.07. — KWP / Portal / Mobile · 10 geplant + 3 On Hold
*→ KWP Read-only-Inbound-E2E erst downstream nach `VR-P32c/d` und kontrollierter `VN-1`-Freigabe.*
### Mo 20.07. · 4 Ticket(s)
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VA-P26a | Akeshan | 21.07. | Customer-Portal: Auth/Magic-Link + Projekt-Sicht + Status-Mails (M141/142) ⭐ |
| VD-P26 | David | 22.07. | Screens P26 — Customer-Portal |
| VD-P27 | David | 22.07. | Screens P27 — Mobile-PWA-Shell (PWA-only) |
| VD-P32 | David | 22.07. | Screens P32 — KWP-Setup (ex-VD-5) |
| VEXT-1 •B2 | Raffael | 20.07. | KWP-API-Zugang nutzen + Recut-Detailplanung gegen API-Doku |
| VN-1 •B2 | Dejan/Haris | 23.07. | KWP-Test-Instanz/Testdaten bereitstellen |
| VR-P32a •B2 | Raffael | 22.07. | KWP: Connector + Health + Push-Queue (M089/090/091) |
### Di 21.07. · 1 Ticket(s)
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VA-P26b | Akeshan | 22.07. | Customer-Portal: Upload/Reklamation + Subunternehmer/Skalierung/DSGVO (M143-146) ⭐ |
| VR-P32a •B2 | Raffael | 22.07. | KWP: Read-only Connector + Health (M089/090); M091 geparkt |
### Mi 22.07. · 1 Ticket(s)
| Ticket | Wer | bis | Aufgabe |
@@ -310,22 +303,29 @@ css: |-
|---|---|---|---|
| VA-P27a | Akeshan | 25.07. | Mobile-PWA-Ausbau: Installierbarkeit + Service-Worker-Offline + Web-Push/Kamera (M167/168) |
| VD-P29 | David | 27.07. | Screens P29 — Help-Center |
<h3 class="gate">Fr 24.07. · 3 Ticket(s)</h3>
<h3 class="gate">Fr 24.07. · 2 Ticket(s)</h3>
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VH-1 | Haris | 31.07. | KWP-Sync als Verkaufsargument + weitere Onboardings/Conversions |
| VN-2 •B2 | Dejan/Haris | 24.07. | KWP-Sync-E2E-Verprobung mit Geerkens |
| VR-P32c •B2 | Raffael | 26.07. | KWP: Plantafel-Sync + Doku-Archiv + Task-ERP-Sync (M094/095/074) |
| VR-P32d •B2 | Raffael | 26.07. | KWP: Read-only Projekt-Upsert + Pipeline-Routing |
### Sa 25.07. · 1 Ticket(s)
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VA-P27b | Akeshan | 27.07. | Mobile-PWA-Ausbau: mobile Navigation + Offline-Sync + PWA-Härtung (M169/170/171) |
## v2-Woche 3 · Mo 27.–Fr 31.07. — Admin / Help / Dashboard · 16 Tickets
*→ v2 KOMPLETT LIVE (Fr 31.07.)*
### On Hold · 3 Ticket(s) · ohne Datum/Cycle, nicht Teil des W2-Tagesplans
| Ticket | Wer | Blocker | Aufgabe |
|---|---|---|---|
| VN-1 •B2 | Dejan/Haris | Geerkens-Freigabe + minimal berechtigter BNWIN-Benutzer | Kontrollierten KWP-Read-only-Testzugang/Testdaten bereitstellen |
| VN-2 •B2 | Dejan/Haris | `VR-P32c/d` + `VN-1` | KWP Read-only-Inbound-Live-E2E mit Geerkens |
| VH-1 | Haris | `VN-2` | KWP-Sync erst nach belegtem Live-E2E als Verkaufsargument verwenden |
## v2-Woche 3 · Mo 27.–Fr 31.07. — Admin / Help / Dashboard · 15 Tickets
*→ ursprüngliches Wochengate; Customer-Portal folgt nach `VA-P26b`/`VA-P26c`.*
### Mo 27.07. · 4 Ticket(s)
| Ticket | Wer | bis | Aufgabe |
@@ -345,7 +345,7 @@ css: |-
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VA-P28b | Akeshan | 31.07. | Flag-Massen-Statistik (M033) + interne Lead-Pipeline (M040) |
| VA-P28b | Akeshan | 31.07. | Flag-Massen-Statistik (M033) + Lead-Deal-Ausbau (M040b) |
| VA-P30a | Akeshan | 30.07. | Dashboard-Deluxe: Custom-Widgets + Export (M149/150) |
| VA-P34 •B2 | Akeshan | 31.07. | HR-Drittanbieter-Onboarding Memberspot/Boobora (M138) |
| VD-P30 | David | 30.07. | Screens P30 — Dashboard-Deluxe |
@@ -357,12 +357,23 @@ css: |-
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VA-P30b | Akeshan | 31.07. | Querschnitt: Notif-Bündelung/Quiet-Hours (M117) + Sprach-Wechsler/EN (M029) |
<h3 class="gate">Fr 31.07. · 1 Ticket(s)</h3>
## v2-Carry-over ab 01.08. · 1 Ticket
*Retimierte Arbeit außerhalb des ursprünglichen Drei-Wochen-Fensters.*
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VJ-3 | Dejan | 31.07. | Website-Update: Portal/Mobile-PWA/KWP als Features live |
| VA-P26b | Akeshan | offen | Customer-Portal: Upload/Reklamation + Subunternehmer/Skalierung/DSGVO (M143-146) ⭐ · frühestens ab 06.08. nach VA-P26a |
## Termin offen / Backlog · 3 Tickets
*Bewusst nicht auf ein Datum gelegt; Abhängigkeiten zuerst erfüllen.*
| Ticket | Wer | bis | Aufgabe |
|---|---|---|---|
| VA-P26c | Akeshan | offen | Customer-Portal: Paket-Gates + Self-Service-Custom-Domain ⭐ |
| VD-P26 | David | offen | Screens P26 — Customer-Portal |
| VJ-3 | Dejan | offen | Website-Update: Portal/Mobile-PWA/KWP als Features live · Portal nach VA-P26b/VA-P26c |
## v3-Backlog (zurückgestellt — NICHT im Sprint) · 2
*PWA-only (AD-17): native App + App-Store erst v3. Diese Tickets sind keinem Cycle zugeordnet.*
@@ -375,7 +386,7 @@ css: |-
<h2 class="idx">Ticket-Index — alle 152 Tickets (nach Track)</h2>
*Zum Nachschlagen, je Track nach Start sortiert. •B2 = Block 2 (Partner-API offen, agil).*
### Raffael · 40 Tickets
### Raffael · 43 Tickets
| Ticket | Start | bis | v | Aufgabe |
|---|---|---|---|---|
@@ -410,17 +421,20 @@ css: |-
| VEXT-5 | 13.07. | 19.07. | v2 | Gmail-Restricted-Scope-Verifizierung nachhalten |
| VR-P22a | 13.07. | 15.07. | v2 | Public-API: OpenAPI + Read-Endpoints (M161) |
| VR-P22b | 15.07. | 17.07. | v2 | Public-API: API-Key-Auth/Scopes/Rate-Limit (M162/M027) + Webhooks (M163) |
| R-LEADS | 16.07. | 31.07. | v2 | Native Plattform-Leads (M040a) + Migration/Cutover + `lead-inbox`-Decommission |
| VR-MCP | 18.07. | 20.07. | v2 | MCP-Server: Read-Ressourcen + bestätigungspflichtige Action-Tools |
| VEXT-1 •B2 | 20.07. | 20.07. | v2 | KWP-API-Zugang nutzen + Recut-Detailplanung gegen API-Doku |
| VR-P32a •B2 | 20.07. | 22.07. | v2 | KWP: Connector + Health + Push-Queue (M089/090/091) |
| VEXT-6 •B2 | — | — | v2+ | KWP Write-/Auftrag-Create-Capability nachhalten · On Hold |
| VR-P32a •B2 | 20.07. | 22.07. | v2 | KWP: Read-only Connector + Health (M089/090); M091 geparkt |
| VR-P32b •B2 | 22.07. | 24.07. | v2 | KWP: Contract-Sentinel + Konflikt 'KWP gewinnt' (M092/093) |
| VR-P32c •B2 | 24.07. | 26.07. | v2 | KWP: Plantafel-Sync + Doku-Archiv + Task-ERP-Sync (M094/095/074) |
| VR-P32d •B2 | 24.07. | 26.07. | v2 | KWP: Read-only Projekt-Upsert + Pipeline-Routing |
| VEXT-2 •B2 | 27.07. | 29.07. | v2 | HalloPetra-Spec erheben (API-Vertrag) |
| VR-P28a | 27.07. | 29.07. | v2 | AdminUser-Welt + AdminRBAC (M038/039) |
| VR-P31 | 29.07. | 31.07. | v2 | DSGVO-Vollausbau: AVV/Subprozessoren/Auskunft (M166) |
| VR-P33 •B2 | 29.07. | 31.07. | v2 | Telefonie-Erweiterung HalloPetra (M105) |
### Akeshan · 32 Tickets
### Akeshan · 33 Tickets
| Ticket | Start | bis | v | Aufgabe |
|---|---|---|---|---|
@@ -441,18 +455,19 @@ css: |-
| AK-P16b | 04.07. | 05.07. | v1 | P16 Booking (Slots + Verfügbarkeit + Storno) |
| AK-P16c | 05.07. | 06.07. | v1 | P16 Form-Builder (Editor + Submission + Actions) |
| AK-P16d | 06.07. | 07.07. | v1 | P16 Angebot/Signatur (Self-hosted SES; PandaDoc optional BYOK) |
| AK-P20 | 08.07. | 08.07. | v1 | P20 Billing (Legacy-Provider Abo-Baukasten) + Onboarding + Branding |
| AK-P20 | 08.07. | 08.07. | v1 | P20 Billing-Grundlagen + Onboarding + Branding |
| AK-P21 | 09.07. | 09.07. | v1 | P21 DSGVO (Export + Lösch-Workflow) + Feedback-Widget |
| VA-P23 | 13.07. | 17.07. | v2 | Postfach-Sync: Gmail/Outlook OAuth + Inbox + Threading + Versand (M096-098) |
| VA-P24a | 13.07. | 15.07. | v2 | Self-Service-Abo-Baukasten-UI (M28-Delta) |
| VA-P24b | 18.07. | 20.07. | v2 | Onboarding-Wizard-UI (M157) |
| VA-P26a | 20.07. | 21.07. | v2 | Customer-Portal: Auth/Magic-Link + Projekt-Sicht + Status-Mails (M141/142) ⭐ |
| VA-P26b | 21.07. | 22.07. | v2 | Customer-Portal: Upload/Reklamation + Subunternehmer/Skalierung/DSGVO (M143-146) ⭐ |
| VA-P26a | 16.07. | 05.08. | v2 | Customer-Portal: Auth/Magic-Link + Projekt-Sicht + Status-Mails (M141/142) ⭐ |
| VA-P26b | 06.08. | offen | v2 | Customer-Portal: Upload/Reklamation + Subunternehmer/Skalierung/DSGVO (M143-146) ⭐ |
| VA-P26c | offen | offen | v2 | Customer-Portal: Paket-Gates + Self-Service-Custom-Domain ⭐ |
| VA-P27a | 23.07. | 25.07. | v2 | Mobile-PWA-Ausbau: Installierbarkeit + Service-Worker-Offline + Web-Push/Kamera (M167/168) |
| VA-P27b | 25.07. | 27.07. | v2 | Mobile-PWA-Ausbau: mobile Navigation + Offline-Sync + PWA-Härtung (M169/170/171) |
| VEXT-3 •B2 | 27.07. | 29.07. | v2 | Memberspot/Boobora-Spec erheben (HR-Drittanbieter) |
| VA-P29 | 28.07. | 30.07. | v2 | Help-Center + Help-Desk (M172-175) |
| VA-P28b | 29.07. | 31.07. | v2 | Flag-Massen-Statistik (M033) + interne Lead-Pipeline (M040) |
| VA-P28b | 29.07. | 31.07. | v2 | Flag-Massen-Statistik (M033) + Lead-Deal-Ausbau (M040b) |
| VA-P30a | 29.07. | 30.07. | v2 | Dashboard-Deluxe: Custom-Widgets + Export (M149/150) |
| VA-P34 •B2 | 29.07. | 31.07. | v2 | HR-Drittanbieter-Onboarding Memberspot/Boobora (M138) |
| VA-P30b | 30.07. | 31.07. | v2 | Querschnitt: Notif-Bündelung/Quiet-Hours (M117) + Sprach-Wechsler/EN (M029) |
@@ -494,7 +509,7 @@ css: |-
| VD-P23 | 13.07. | 17.07. | v2 | Screens P23 — Postfach-Inbox (ex-VD-1) |
| VD-P24 | 13.07. | 15.07. | v2 | Screens P24 — Abo-Baukasten + Wizard (ex-VD-1) |
| VD-MCP | 16.07. | 20.07. | v2 | Screens MCP — MCP-Connection-Verwaltung + Scope/Audit |
| VD-P26 | 20.07. | 22.07. | v2 | Screens P26 — Customer-Portal |
| VD-P26 | offen | offen | v2 | Screens P26 — Customer-Portal |
| VD-P27 | 20.07. | 22.07. | v2 | Screens P27 — Mobile-PWA-Shell (PWA-only) |
| VD-P32 | 20.07. | 22.07. | v2 | Screens P32 — KWP-Setup (ex-VD-5) |
| VD-P29 | 23.07. | 27.07. | v2 | Screens P29 — Help-Center |
@@ -503,7 +518,7 @@ css: |-
| VD-P30 | 29.07. | 30.07. | v2 | Screens P30 — Dashboard-Deluxe |
| VD-P31 | 29.07. | 31.07. | v2 | Screens P31 — DSGVO-Vollausbau |
### Dejan · 13 Tickets
### Dejan · 12 Tickets
| Ticket | Start | bis | v | Aufgabe |
|---|---|---|---|---|
@@ -512,23 +527,22 @@ css: |-
| J-STRUKTUR | 16.06. | 17.06. | v1 | Seitenstruktur + Davids Screens einbauen |
| J-CONTENT | 17.06. | 17.06. | v1 | Content/Texte einbauen |
| J-LAW | 17.06. | 18.06. | v1 | Rechtstexte einbauen (Anwalt) |
| J-QA | 17.06. | 18.06. | v1 | QA + Lead-Routing-Test |
| J-LIVE | 18.06. | 18.06. | v1 | WEBSITE LIVE |
| J-SEO | 20.06. | 26.06. | v1 | SEO + Conversion + Pricing-Seite vorbereiten |
| J-WEBINAR | 29.06. | 03.07. | v1 | Webinar-Landing + Anmelde-Flow |
| J-WEBTECH | 04.07. | 10.07. | v1 | Webinar-Technik (Plattform/Aufzeichnung) |
| J-LAUNCHUPD | 06.07. | 10.07. | v1 | Launch-Update Website |
| VJ-2 | 28.07. | 28.07. | v2 | Help-Center-Inhalte einpflegen |
| VJ-3 | 31.07. | 31.07. | v2 | Website-Update: Portal/Mobile-PWA/KWP als Features live |
| VJ-3 | offen | offen | v2 | Website-Update: Portal/Mobile-PWA/KWP als Features live |
### Haris · 12 Tickets
### Haris · 12 Tickets · davon 1 On Hold
| Ticket | Start | bis | v | Aufgabe |
|---|---|---|---|---|
| H-LISTE | 16.06. | 17.06. | v1 | Zielkundenliste SHK (KWP-Nutzer-Fokus) |
| H-PAIN | 16.06. | 17.06. | v1 | Painpoint-Gespräch mit Noah |
| H-TXT | 17.06. | 17.06. | v1 | Website-Texte schreiben |
| H-INBOUND | 18.06. | 19.06. | v1 | Lead-Sheet + Inbound-Prozess (<24h) |
| H-INBOUND | 18.06. | 19.06. | v1 | Nativer Lead-Inbound-Prozess (<24h) |
| H-PITCH | 18.06. | 19.06. | v1 | Pitch-Deck + Gesprächsskript |
| H-CALLS | 23.06. | 26.06. | v1 | Erste Discovery-Calls |
| H-FOUND | 25.06. | 26.06. | v1 | Founding-Member-Angebot strukturieren |
@@ -536,9 +550,9 @@ css: |-
| H-DEMO | 30.06. | 03.07. | v1 | Klick-Demos + echte Produkt-Demos |
| H-WEBINAR | 06.07. | 10.07. | v1 | Webinar-Einladungen + Moderation |
| H-FOLLOW | 09.07. | 10.07. | v1 | Trial-Follow-ups + Bilanz |
| VH-1 | 24.07. | 31.07. | v2 | KWP-Sync als Verkaufsargument + weitere Onboardings/Conversions |
| VH-1 | — | — | v2 | KWP-Sync nach `VN-2` als Verkaufsargument verwenden · On Hold |
### Dejan/Haris (Noah-Zulieferungen) · 11 Tickets
### Dejan/Haris (Noah-Zulieferungen) · 11 Tickets · davon 2 On Hold
| Ticket | Start | bis | v | Aufgabe |
|---|---|---|---|---|
@@ -551,5 +565,5 @@ css: |-
| N-DEMO1 | 26.06. | 26.06. | v1 | Demo 1 abnehmen (CRM klickbar) |
| N-DEMO2 | 03.07. | 03.07. | v1 | Demo 2 abnehmen (Kette E2E) |
| N-GONOGO | 10.07. | 10.07. | v1 | Voll-Walkthrough + Go/No-Go |
| VN-1 •B2 | 20.07. | 23.07. | v2 | KWP-Test-Instanz/Testdaten bereitstellen |
| VN-2 •B2 | 24.07. | 24.07. | v2 | KWP-Sync-E2E-Verprobung mit Geerkens |
| VN-1 •B2 | — | — | v2 | Kontrollierten KWP-Read-only-Testzugang/Testdaten bereitstellen · On Hold |
| VN-2 •B2 | — | — | v2 | KWP Read-only-Inbound-Live-E2E mit Geerkens · On Hold nach VR-P32c/d |
@@ -1,95 +0,0 @@
---
gsd_state_version: 1.0
milestone: v1.0
milestone_name: milestone
status: planning
stopped_at: context exhaustion at 75% (2026-07-05)
last_updated: "2026-07-05T23:26:34.479Z"
last_activity: 2026-06-15 — **ER-Modell festgezogen (AD-20, Projekt-zentrisch, David approved).** Kern ENTITY-MODEL.md neu (Domänen 5–8 → eine „Projekt-zentrischer CRM-Kern", Rest erhalten); entity-model.dbml kanonisiert + entity-model.svg + ENTITY-MODEL.pdf neu gerendert. Scratch gelöscht (ruecksprache-Entwurf, Whiteboard-Bild, projekt-zentrisch-Render-Artefakte, MODELL-PIVOT-Anker). Alle Anker-Verweise → ENTITY-MODEL.md umgebogen.
progress:
percent: 0
---
# Project State
## Project Reference
See: .planning/PROJECT.md (updated 2026-06-07)
**Core value:** Jeder SHK-Betrieb (Mandant) wickelt die komplette Wertschöpfungskette — Lead → Sales → Auftrag → KWP-Sync — inklusive visueller KI-Automation in einem einzigen, DSGVO-konformen EU-System ab.
**Current focus:** Phase 1 — Fundament & Walking-Skeleton
## Current Position
Phase: 1 of 21 (Fundament & Walking-Skeleton)
Plan: 0 of TBD in current phase
Status: Ready to plan (P1–P5 unberührt vom Pivot); ER-Modell ✅ APPROVED & LOCKED (ENTITY-MODEL.md/.dbml/.svg + ENTITY-MODELL-ERKLAERUNG.pdf); offen: Detail-Re-Fit P6–P9 (Requirements/Phase-Sources/Screen-Map) gegen das gelockte Modell
Last activity: 2026-06-15 — **ER-Modell festgezogen (AD-20, Projekt-zentrisch, David approved).** Kern ENTITY-MODEL.md neu (Domänen 5–8 → eine „Projekt-zentrischer CRM-Kern", Rest erhalten); entity-model.dbml kanonisiert + entity-model.svg + ENTITY-MODEL.pdf neu gerendert. Scratch gelöscht (ruecksprache-Entwurf, Whiteboard-Bild, projekt-zentrisch-Render-Artefakte, MODELL-PIVOT-Anker). Alle Anker-Verweise → ENTITY-MODEL.md umgebogen.
Progress: [░░░░░░░░░░] 0%
## Performance Metrics
**Velocity:**
- Total plans completed: 0
- Average duration: — min
- Total execution time: 0.0 hours
**By Phase:**
| Phase | Plans | Total | Avg/Plan |
|-------|-------|-------|----------|
| - | - | - | - |
**Recent Trend:**
- Last 5 plans: —
- Trend: —
*Updated after each plan completion*
## Accumulated Context
### Decisions
Decisions are logged in PROJECT.md Key Decisions table (AD-1..AD-19 + KWP-Recut).
Bau-relevante Leitentscheidungen für den aktuellen Stand:
- AD-11: Bau-Reihenfolge Fundament-Kern → SHK-Kernpfad → Breite (steuert die Phasenfolge 1→21).
- Phase-0-Pflichten: Codebase lauffähig halten, EU-Sterilisation + 4 Querschnitts-Neubauten gehen jedem Fachmodul voraus (= Phase 1).
- AD-1/AD-2: RLS-Baseline + typisierte Tabellen (Entity-Builder raus) sind ab Phase 2/6 bauliche Vorgabe.
- AD-19: Big-Bang-Go-Live — kein phasiertes Produktiv-Schalten; Validierung pro Modul über Noah/Geerkens-Klick-Pfad.
- Roadmap-Revision: Querschnitts-Oberflächen (P3, Audit-Viewer/Notif-Center/Sprach-UX) + Files/Tasks (P4) getrennt; Automation (P12) und KI (P13) eigenständig; Kommunikation in Email/Marketing (P14), Telefonie/Chat (P15), Kalender/Booking/Forms/Signatur (P16); HR (P17) + Portal (P18); Plattform/Launch in Admin (P19), Billing/Onboarding/Branding (P20), Public-API/DSGVO/Mobile/Help (P21). Kommunikations-Phasen hängen an Apps-Engine (P5) + CRM (P6), nicht an Automation/KI.
- Dependency-Audit 2026-06-10: Die Service-Kerne Audit/i18n/Flags/Notifications (M001/M003/M006/M011) liegen in Phase 1 — der gesamte Auth-Block (P2) setzt sie voraus (entspricht BMAD-Block-1-Ordnung).
- **Dependency-Inversion-Prinzip (verbindlich):** Spätere Module integrieren sich rückwirkend in frühere Oberflächen — keine unaufgelösten Vorwärts-Abhängigkeiten. PHASE-SOURCES.md führt das Ownership-Register (welche Phase welche Retro-Integration MIT einplanen muss), die Extension-Point-Pflichten der frühen Phasen (notify()-Kanäle, EntityLink, `lead.qualified`-Events, Subscription-Stub, VM-Slots) und das maschinenlesbare Audit-Register. Audit-Kontrakt: Vorwärts-Refs MINUS Register = leer. M049 (Auto-Projekt) wurde als einziger echter Entity-Move nach P8 verschoben.
### Pending Todos
Keine.
### Blockers/Concerns
- **KWP-Recut (Phase 10):** M089–M095 müssen VOR Umsetzung neu geschnitten werden. Offizielle KWP-API → kwpsync.exe (M089) entfällt; M19-Spec beschreibt noch die obsolete Windows-Client-Variante. KWP als `DataConnection type='rest-api'`, Backend-Sync ohne eigene UI.
- **AD-6 (EU-Email-Provider) offen — DRINGLICHKEIT ERHÖHT:** Der Notification-Service-Kern (M011) liegt jetzt in Phase 1; der Email-Kanal braucht mindestens die Provider-Abstraktion ab P1 und die Entscheidung (Tendenz Mailjet) spätestens vor Phase 2 (Einladungs-Mails). Betrifft außerdem Phase 3 (Versand-Pipeline) und Phase 14 (Email/Marketing).
- **AD-7 (Captcha/Bot-Schutz) offen:** Tendenz Friendly Captcha / mCaptcha, nicht gelockt. Betrifft Phase 2 (Login) und Phase 16 (Forms/Booking).
- **AD-5 (Meilisearch self-hosted):** Self-hosted-Such-Infra ist Voraussetzung für Phase 11 (Globale Suche) — Infra vor Modulbau bereitstellen. Search-Registry (P1) ab Tag 1 befüllen, damit P11 nur noch den Engine-Anschluss braucht.
- **ADR-Text vs. Repo-Realität (Phase 1):** ADR/Intel sagt „Repo ist Docs-only" — real ist die Boilerplate seit 2026-06-04 als Codebase eingezogen. Beim Planen von Phase 1 zuerst Ist-Stand erheben, bereits Erledigtes (Boilerplate-Einzug, ggf. Teile der EU-Sterilisation) nicht neu planen.
- **Spec-Status:** Alle 36 Modul-Specs sind `detail-spec-draft`. Vor jedem Modulbau: Noah-Verifizierung, Index-/Migrations-SQL, SHK-Defaults finalisieren, Subframe-UI-Designs.
## Deferred Items
Items acknowledged and carried forward from previous milestone close:
| Category | Item | Status | Deferred At |
|----------|------|--------|-------------|
| Modul | M11 WhatsApp (von M13/M18 referenziert, nicht spec'd) | v2 | 2026-06-07 |
| Feature | REQ-branding-tenant-phase2 (White-Label, Custom-Domain) | v2 | 2026-06-07 |
| Feature | REQ-signatur-provider Fallback (manueller PDF-Upload) | v2 | 2026-06-07 |
| Pipeline | DeepL-Übersetzungs-Pipeline (M30) | v2 | 2026-06-07 |
## Session Continuity
Last session: 2026-07-05T23:26:34.477Z
Stopped at: context exhaustion at 75% (2026-07-05)
Resume file: None
@@ -0,0 +1,29 @@
# Subframe-Flow-Inventar (UI-Nachzug-Tracking)
**Stand:** 2026-07-29 (Akeshan, 8. Update) · Quelle: Subframe-Projekt `f023064a5ca0` via MCP `list_flows`/`get_page_info`.
Der Subframe-MCP-Sync pflegt nur Components/Layouts/Theme nach `apps/web/app/ui` — **Pages/Screens
werden nie automatisch integriert**. Jeder Flow muss Screen für Screen per `get_page_info` geholt und
hinter der Loader/Action-Grenze verdrahtet werden (Regeln: `.planning/INTERIM-UI-PLAYBOOK.md`, insbes.
§App-Shell-Grenze und §Scroll-Verhalten). Diese Liste trackt, was schon drin ist und was aussteht.
| Flow (Subframe) | Seiten | Ticket/Owner | Stand |
|---|---|---|---|
| (MCP) WF-P16 Form Builder | 16 | AK-P16c / Akeshan | ✅ integriert (PR #71 + Sichtbarkeits-Fix 2026-07-10); S01B „Gefuehrter Fragen Editor" ist als `_backlog_` markiert und bewusst ausgelassen |
| (MCP) HiveGrid Workflow Engine / Automationen P12 | 36 | R-P12a/b / Raffael (UI-Nachzug Akeshan) | 🟡 Voller Delta-Nachzug integriert (2026-07-13): Editor auf Davids „V1 Vollbild minimal" gehoben (Header mit Inline-Rename/Aktiv-Switch, Dot-Grid, untere Toolbar mit Zoom/Probelauf, Modus-Toggle Bauen/Aktivität), „Picker Kachel-Filter" als Drawer, „Kontextmenue Canvas" mit Clipboard-Ops (Cut/Copy/Paste/Alles auswählen + Shortcuts) und alle 25 K-Node-Konfig-Dialoge schema-getrieben (`nodeConfigDescriptors.ts`). 5 K-Logik-Karten (Und/Oder/Switch/Filter/Wert setzen) haben kein Registry-Pendant und bleiben bewusst offen; „Auswertung"-Modus ohne Backing weggelassen. Reverse zeigt jetzt persistierte Mail-Empfängerlisten (nicht zurückziehbar). Offen: visuelle Browser-Abnahme auf Staging; Reverse-Abdeckung weiterer Action-Typen und run-now brauchen weiter den Forward-Executor. **Delta-Audit 2026-07-18 (+3 Seiten):** „K-T2 Zeitplan monatlich" (Option `monatlich` existiert bereits, `nodeConfigDescriptors.ts`) und „K-T1 Neuer Kontakt - Mit Beispiel" (Deskriptor vorhanden) sind inhaltlich gedeckt; „S01d Editor gefuellt" bleibt als Rest-Delta offen (Minimap „Übersicht", beschriftete Ja/Nein-Kanten am Canvas) — Umsetzung mit Raffael klären (R-P12-Ownership). „K-A2 E-Mail senden" wartet weiter auf R-P12c (`email.send_transactional`). |
| (MCP) (MCP) WF-P8 Pipelines | 23 | R-P8 / Raffael (UI-Nachzug Akeshan) | 🟡 Kernstrecke integriert (2026-07-11): S01 Kanban, S02 Detail, S03 Liste, S04/S07 Pipeline-Konfiguration und S06 Verlustgründe. **Delta-Nachzug 2026-07-18 (+7 Seiten):** S00 Boards-Startseite als neuer Screen `BoardsStartPage` + Route `/projects/boards` + Sidebar-Eintrag; S01a/S03a Empty-States (Filter-Banner + gestrichelte Spalten-Placeholder bzw. Empty-Karte + Paritäts-Footer); S01b 2-Spalten-Umbruch (`KanbanColumn twoColumn/wrapAfter` via Component-Sync, ab 6 Karten, Info-Pill); S02a Edit-Modus-Banner + System-Feld-Tags im Detail; S07a Error-State im Neues-Board-Dialog (Duplikat-Name client+server, Typ-Pflicht, Info-Box); M03 Karten-Kontextmenü (Öffnen/Verschieben/Board-Einstellungen). Karten auf neue `KanbanCard`-Slot-API migriert (inkl. LeadBoard), `priceLocked` an Wert-Permission. **Rest-Delta:** S00-Sperr-/„Nutzung anfragen"-Semantik (Zugriffsmodell ist deny-basiert, kein „sichtbar aber gesperrt"), Kontextmenü Undo/Duplizieren/Löschen (kein Backing), „Hängt N T"-Staleness + Start-Datum + `flagVariant`-Quelle (keine VM-Felder), Deep-Link zum Auto-Öffnen des Anlege-Dialogs. Offen: visuelle Browser-Abnahme nach Merge/Deploy. **Polish 2026-07-18 (2. PR):** Hierarchie-Konflikt aufgelöst — die P8-Wireframes (Stand 2026-07-08, kein S00, Einstieg = Kanban „zuletzt genutztes Board") sind älter als Davids Subframe-S00 „Boards-Startseite" (2026-07-15, „Wähle ein Board aus"); die neueste Aussage gewinnt: **ein** konsolidierter Sidebar-Eintrag „Boards" → `/projects/boards` (`activePaths` hält ihn auf den `/projects`-Unterrouten aktiv), das Duplikat „Projekte" entfällt — mit David rückbestätigen (Wireframes-Nachzug offen). Dazu Boards-Seite auf `PageShell`/`PageHeader` + volle Breite (`max-w-7xl`-Wrapper raus) gehoben und S01b-Umbruch-Bug behoben (`wrapAfter` = ceil(n/2) statt fix 6 — fix erzeugte bei >12 Karten überzählige Grid-Tracks mit überlappenden Karten). **Backend-Nachzug 2026-07-18 (3. PR, User-beauftragt trotz R-P8-Ownership — Querverweis in R-P8a):** Das Rest-Delta ist weitgehend abgetragen: (a) S00-Sperr-Semantik gebaut — gesperrte Boards (deny-`PipelineAccess`-Regel) erscheinen ausgegraut mit „Nutzung anfragen"; neues Modell `PipelineAccessRequest` (eigene `prisma/schema/pipelineAccessRequest.prisma`, RLS-Policy-Vertrag 292→293, Migration `20260718090000_wf_p8_pipeline_access_request`), Anfrage benachrichtigt `projects.admin`-User (M011) + Audit; Freigabe eines Users via Board-Einstellungen resolved offene Anfragen. (b) „Hängt N T"-Tag ab 7 Tagen Stage-Verweildauer (aus `ProjektStageChange`, nur offene Spalten; `STUCK_AFTER_DAYS`). (c) Kontextmenü Duplizieren (`duplicateProject`, neue HiveNumber, Kontakt-Links mitkopiert) + Archivieren (Confirm-Dialog → bestehendes `archiveProject`). **Verbleibendes Rest-Delta:** Kontextmenü-Undo (bewusst ausgelassen), Start-Datum + `flagVariant`-Quelle auf der Karte, Deep-Link zum Auto-Öffnen des Anlege-Dialogs; Schwester-Route `projects.pipelines.$pipelineId` bekommt Duplizieren/Archivieren noch nicht (Nachzug). **Baseline-Nachzug 2026-07-28 (17 → 23 Seiten, Davids Handoff `D-P8 + D-KANBAN` vom 2026-07-28):** Der Flow ist neu geschnitten — `S01b` und `S02a` sind entfallen, dafür sind 6 neue Screens dazugekommen, die vorher **kein Backing** hatten. Alle gebaut, inkl. Datenmodell: (a) **M04/M04a/M04b/M04c Pipeline-Übergabe** als **ein** Dialog mit vier Tabs (`PipelineHandoverDialog`) — neues Modell `PipelineHandover`/`PipelineHandoverItem` + `Pipeline.nachfolgePipelineId`, statusgetriggert beim Erreichen der letzten Stage, **kein** Button. **Produktentscheidung (mit User abzustimmen):** abgewählte Begleitdaten werden **nicht gelöscht**; die Übergabe ist ein explizites Paket, was das nächste Team bekommt. Die Nachfolge-Pipeline wird in den Board-Einstellungen gesetzt (kein Subframe-Screen zeigt dieses Control, M04 kann ohne es aber nicht auslösen). (b) **S02-A/N/T/F Schnellaktionsmodale** (`ProjectQuickActionDialogs`) — Notiz mit Sichtbarkeits-Gate (neues Modell `ProjektNotiz` + Permission `projects.notes.read_internal`; die flache `Activity`-Timeline kann das nicht ausdrücken), Aufgabe/Termin auf bestehende Intents, Datei über bestehenden `FileEntityLink` mit Kategorie als `linkRole`. Dazu `ProjektTermin.typ` (vor Ort/Telefon/Online), sonst wäre der Typ-Selektor ein toter Button. (c) **S05 Detail-Schablone + M05 Modal Bestandsfeld** (`PipelineFieldTemplatePage`, Route `/admin/pipelines/:id/fields`) — neues Modell `PipelineFieldGroup` + `PipelineFieldConfig.groupId/pflichtAbStageId/hinweis/istSystem/gesperrt`. (d) **S02 Detailansicht** um Quelle/Projekttyp/Promotion + Projektkontaktdaten (E-Mail/Telefon/Fax auf dem Projekt) erweitert. RLS-Vertrag 372 → 376 Policies, 3 Migrationen, alle gegen leere DB replaybar. **Neues Rest-Delta:** S05-Feldtypen Prozent/Datum+Uhrzeit/Person-Team/Adresse/Link fehlen — sie bräuLine truncated
| (MCP) WF-P2 Login und 2FA | 7 | R-P2 / Raffael | ❌ offen |
| (MCP) WF-P2 Passwort Reset | 7 | R-P2 / Raffael | ❌ offen |
| (MCP) WF-P2 Set Password | 7 | R-P2 / Raffael | ❌ offen |
| (MCP) WF-P2 Admin RBAC | 9 | R-P2 / Raffael | ❌ offen |
| (MCP) WF-P2 Signup | 3 | R-P2 / Raffael | ❌ offen |
| (MCP) WF-P2 Konto loeschen | 3 | R-P2 / Raffael | ❌ offen |
| (MCP) WF-P2 2FA Verwalten | 3 | R-P2 / Raffael | ❌ offen |
| (MCP) WF-P2 Change Password | 2 | R-P2 / Raffael | ❌ offen |
| (MCP) WF-P2 Workspace Auswahl | 2 | R-P2 / Raffael | ❌ offen |
| (MCP) WF-P2 Profil und Sicherheit | 1 | R-P2 / Raffael | ❌ offen |
Ältere Flows ohne `(MCP)`-Präfix (Login, My Profile, Company Profile, Tenant Selection, Session
Management, Delete Account, Backlog) sind Davids frühere Stände; die `(MCP)`-Flows sind die
maßgebliche Neufassung. Vor Arbeit an einem R-*-Flow Ownership mit Raffael klären (AGENTS.md
§Arbeitsmodus) — UI-Nachzug ja, Backend-Änderungen nein.
@@ -1,317 +0,0 @@
---
pdf_options:
format: A4
margin: 16mm
css: |-
body { font-size: 10.5px; font-family: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif; }
h1 { font-size: 20px; }
h2 { font-size: 15px; border-bottom: 2px solid #f5a623; padding-bottom: 4px; margin-top: 22px; break-after: avoid; page-break-after: avoid; }
h3 { font-size: 12px; break-after: avoid; page-break-after: avoid; }
table { font-size: 9.5px; border-collapse: separate; border-spacing: 0; width: 100%; border-top: 1px solid #ccc; border-left: 1px solid #ccc; }
thead { display: table-header-group; }
tr { break-inside: avoid !important; page-break-inside: avoid !important; }
td, th { break-inside: avoid !important; page-break-inside: avoid !important; border-right: 1px solid #ccc; border-bottom: 1px solid #ccc; padding: 4px 6px; text-align: left; vertical-align: top; }
th { background: #fff7e8; }
li { break-inside: avoid; page-break-inside: avoid; }
blockquote { break-inside: avoid; page-break-inside: avoid; }
p { orphans: 3; widows: 3; }
code { background: #f4f4f4; padding: 1px 3px; font-size: 9px; }
.pagebreak { page-break-after: always; }
---
# TIMELINE: HiveGrid 2.0 · 12.06. bis 31.07.2026
> ⛔ **KI→MCP-Pivot ([[AD-26]], 2026-06-22):** HiveGrid hostet kein eigenes LLM/RAG mehr → **MCP-Server**. **v1:** P13/R-P13/D-P13/EXT-11 + M083–M088 entfallen, R-P12b ist neues letztes Glied (09.07. = Härtungstag, Freeze/Launch unverändert). **v2:** „HiveMind/RAG + Whisper + pgvector" (M087) zurückgestellt → **MCP-Server [[VR-MCP]]/[[VD-MCP]]** (18.–20.07., baut auf VR-P22). Die KI-Zeilen unten sind insoweit überholt.
**Erstellt:** Fr 12.06.2026 · **v1-Sprint:** Fr 12.06. bis Fr 10.07. · **v2-Sprint:** Mo 13.07. bis Fr 31.07.
**Arbeitsrhythmus: Mo bis So, täglich mindestens 8 h.** v1 = 29 Arbeitstage, 133 Milestones / 90 Reqs, 2 Dev-Tracks, ca. 2,3 MS/Dev/Tag.
**Infra:** Hetzner + Coolify + Cloudflare (Infra-Repo ADR-009/010). Meilisearch, mCaptcha, ClamAV und Sentry laufen bereits zentral: anbinden statt aufsetzen.
> **Strategische Einordnung:** Die **v1 wird für Demo- und Launch-Zwecke vorgebaut**: Noah-Validierung, Vertriebs-Demos, erste zahlende Kunden. **Die meisten wichtigen Features passieren in v2**: KWP-Sync (USP!), Self-Service-Abo-Baukasten, Postfach-Sync, Mobile-PWA-Ausbau, Customer-Portal, HiveMind. v1 liefert die tragfähige Kette Lead → Sales → Auftrag plus Automation, Marketing, Chat und alle Andockpunkte. **v2 ist KOMPLETT (alle 43 MS) bis Fr 31.07. durchgeplant** (ca. 1,1 MS/Dev/Tag, entspannter als v1); einzige externe Anker: KWP-Zugang 20.07. und Gmail-Scope-Verifizierung (siehe Risiken). Mobile = PWA-only (kein App-Store in v1/v2, AD-17); nativer Client + App-Store → frühestens v3.
## Was passiert in v1, was in v2? (alle 21 Phasen im Überblick)
| # | Phase | v1-MS | Wer / Wann (v1) | Einordnung |
|---|---|---|---|---|
| P1 | Fundament & Walking-Skeleton | 15 | beide, 12. bis 16.06. | v1: Hot-Swap-Maschine, Service-Kerne, Konnektor-Muster |
| P2 | Identität & Mandanten | 9 | Raffael, 17. bis 19.06. | v1: Auth, RLS, RBAC. API-Keys folgen in v2 |
| P3 | Querschnitts-Oberflächen | 5 | Akeshan, 20./21.06. | v1: Audit-Viewer, Notification-Center (DE-only). Quiet-Hours in v2 |
| P4 | Files & Tasks | 7 | Akeshan, 17. bis 19.06. | v1: Upload, HEIC-zu-JPG, Tasks. Versionierung/OCR in v2 |
| P5 | Apps-Engine | 3 | Raffael, 20./21.06. | v1: Integrations-Vertrag für alle Anbindungen |
| P6 | CRM-Kern | 5 | Raffael, 22. bis 24.06. | v1 voll (Kontakte, Firmen, Custom-Felder, Duplikate) |
| P7 | Lead-Inbox | 4 | Raffael, 25./26.06. | v1 voll (Multi-Quellen-Triage, Anti-Spam) |
| P8 | Sales-Pipeline | 7 | Raffael, 27. bis 29.06. | v1: Kanban, Basis-KPIs. Analytik-Tiefe in v2 |
| P9 | Projekte & Plantafel | 6 | Raffael, 30.06. bis 02.07. | v1: Plantafel + Abnahme offline. Lagerist-Sicht in v2 |
| P10 | KWP-Integration | 0 | **v2: Raffael, 20. bis 26.07.** | **Erstes v2-Modul.** API-Zugang erst ca. 19.07. |
| P11 | Suche & Dashboard | 5 | Raffael, 04./05.07. | v1: Keyword-Suche, 3 feste Layouts. Hybrid + Custom-Widgets in v2 |
| P12 | Automation-Engine (USP) | 8 | Raffael, 06. bis 08.07. | v1 VOLL (Editor, Dry-Run, Undo, Sprach-zu-Automation) |
| P13 | KI-Layer | 5 | Raffael, 09.07. | v1: Gateway (Mistral), Limits. HiveMind/RAG/Whisper in v2 |
| P14 | Email & Marketing | 6 | Akeshan, 27. bis 29.06. | v1: Marketing VOLL + BCC-Brücke. Postfach-Sync in v2 |
| P15 | Telefonie & Chat | 9 | Akeshan, 30.06. bis 02.07. | v1 voll (AirCall + Chat). HalloPetra in v2 |
| P16 | Kalender/Booking/Forms/Signatur | 15 | Akeshan, 03. bis 07.07. | v1: Google-Kalender, Booking, Forms, Signatur. Outlook in v2 |
| P17 | HR-Hub | 7 | Akeshan, 25./26.06. | v1 voll inkl. Surveys. Memberspot in v2 |
| P18 | Customer-Portal | 0 | **v2: Akeshan, 20. bis 22.07.** | Andockpunkte liegen in v1 bereit |
| P19 | Plattform-Admin | 7 | Akeshan, 22. bis 24.06. | v1: Tenant-Verwaltung + Abo-Zusammenstellung. AdminUser-Welt in v2 |
| P20 | Billing & Onboarding | 8 | Akeshan, 08./09.07. | v1: Legacy-Provider-Abo-Baukasten (Admin). Self-Service-UI + Wizard in v2 |
| P21 | DSGVO & Launch | 2 | Akeshan, 09.07. | v1: Export + Lösch-Workflow + Feedback-Widget |
### v2-Pakete: ALLE 43 MS bis Fr 31.07. (vollumfänglich durchgeplant)
**Raffael (17 MS): Integrationen + USP-Tiefe + Sicherheit**
| Paket | MS | Wann | Einordnung |
|---|---|---|---|
| KWP-Recut + **Public-API** (M161 bis 163) + **API-Keys** (M027) | 4 | Mo 13. bis Fr 17.07. | Recut gegen API-Doku parallel zur Public-API (Read-REST, Webhooks, Tenant-Keys mit Scopes; Boilerplate-ApiKey-Modell liegt bereit) |
| **HiveMind/RAG + Whisper + pgvector** (M087) | 1 | Sa/So 18./19.07. Start | Andock-Adapter (RetrievalProvider, Outbox-Events) liegen seit v1; pgvector-Spalte + Hybrid-RRF rüsten die Suche nach (AD-5 Teil 2) |
| **KWP-Integration** (M074, M089 bis 095) | 8 | **Mo 20. bis So 26.07.** (Zugang 20.07.; E2E mit Geerkens Fr 24.07.) | **Der USP.** REST-DataConnection, Sync, Warteschlange, Konflikt „KWP gewinnt", Drift-Sentinel |
| **AdminUser-Welt** (M038/M039) | 2 | Mo 27. bis Mi 29.07. | Getrennte Admin-Identität + AdminRBAC (die v1-Auflagen-Brücke wird abgelöst) |
| **HalloPetra** (M105) + **DSGVO-Auskunft** (M166) | 2 | Mi 29. bis Fr 31.07. | TelephonyProviderInterface existiert; Auskunfts-Tooling ersetzt das manuelle Playbook |
**Akeshan (26 MS): Produkt-Flächen**
| Paket | MS | Wann | Einordnung |
|---|---|---|---|
| **Self-Service-Abo-UI** (M154-Teil) + **Postfach-Sync** (M096 bis 098) | 3 | Mo 13. bis Fr 17.07. | Kunde toggelt Module mit Preis-Vorschau (Revenue!) · Gmail/Outlook-OAuth, Inbox, Threading (Gmail ggf. Testmodus bis Google-Verifizierung, Outlook zuerst) |
| **Wizard-UI** (M157) | 1 | Sa/So 18./19.07. | Geführter Setup-Wizard ersetzt den stillen Auto-Seed |
| **Customer-Portal** (M141 bis 146) | 6 | **Mo 20. bis Mi 22.07.** | Endkunden-Sicht auf Projekte; Andockpunkte (FileEntityLink, URL-Pfad, Magic-Link-Auth) liegen seit v1 |
| **Mobile-PWA-Ausbau** (M167 bis 171) | 5 | **Do 23. bis Mo 27.07.** | M36-Recut auf PWA (kein EAS-Build, keine Native-Module, keine Store-Compliance; Expo/Capacitor verworfen, AD-17); OfflineSyncQueue aus P9 ist PWA-ready; Push via Web-Push (VAPID) · **kein App-Store (PWA-only); nativer Client → v3** |
| **Help-Center + Help-Desk** (M172 bis 175) | 4 | Di 28. bis Do 30.07. | Public-Help + Ticket-Desk; Feedback-Widget-Inbox wird zum Desk ausgebaut |
| **Dashboard-Deluxe** (M149/150) + **Querschnitt** (M117 Bündelung/Quiet-Hours, M029 Sprach-Wechsler/EN, M033, M040, M138) | 7 | Mi 29. bis Fr 31.07. | Custom-Widgets + Drag&Drop + Export · Komfort-Nachzügler |
**David (v2-Screens, jeweils 2 bis 3 Tage vor dem Bau):** Abo-UI/Wizard/Postfach-Inbox (13. bis 16.07.) → **Portal-Shell** (extern sichtbar, eigener Polish! bis 19.07.) → **Mobile-PWA-Shell** (Touch-Paradigma, Tab-Bar, installierbare PWA/Add-to-Homescreen, bis 22.07.) → Help-Center (bis 27.07.) → Politur.
**Dazu die v1-Dünnungs-Rückläufer** (kein eigener MS, fließen in die Pakete ein): Datei-Versionierung + Office/Video-Previews + OCR · konfigurierbare Audit-Retention/Legal-Hold · Lagerist-Arbeitsplatz · personalisierte Form-Links · Booking-Strategien · Outlook-Kalender · zweiter EU-LLM-Provider · KI-Walkthrough (in M157). Einplanung je beim zugehörigen Paket; was am 31.07. nicht passt, fällt als Einziges in den August (Komfort, kein Funktionsverlust).
**Bilanz: 17 + 26 = 43 MS bis Fr 31.07.** Externer Anker außerhalb unserer Kontrolle: Gmail-Restricted-Scope-Verifizierung (Wochen; Outlook + Testmodus überbrücken). *(Kein App-Store — Mobile ist PWA-only in v1/v2, AD-17; nativer Client + App-Store → frühestens v3.)*
<div class="pagebreak"></div>
## Gemeinsame Fixtermine (alle)
| Datum | Termin |
|---|---|
| täglich 9:00 (Mo bis So!) | Dev-Sync Raffael + Akeshan (15 min) · Integration auf `main` täglich · Wochenenden sind volle Arbeitstage |
| **Fr 19.06.** | **Gate W1:** Hot-Swap grün + RLS-Beweis + Konnektor-Demo |
| **Fr 26.06.** | **Gate W2 + Noah-Demo 1:** CRM klickbar |
| **Fr 03.07.** | **Gate W3 + Noah-Demo 2:** Kette Lead → Sales → Auftrag E2E |
| **Do 09.07.** | **FEATURE-FREEZE** |
| **Fr 10.07.** | **Gate W4 + Noah-Walkthrough: Go/No-Go → [LAUNCH]** |
| Di/Mi 14./15.07. | [WEBINAR] Webinar Nr. 1 |
| Fr 31.07. | [ZIEL] **v2 KOMPLETT live (alle 43 MS, inkl. KWP)** + erste Gelder eingesammelt · Gmail-Verifizierung läuft extern nach · Mobile = PWA-only (kein App-Store, AD-17) |
## Vereinte Dev-Timeline: woran Raffael + Akeshan parallel arbeiten
Parallelität funktioniert, weil die Tracks entlang des Dependency-Graphen geschnitten sind: beide Spuren hängen nur an bereits fertigen Phasen, nie aneinander.
| Zeitfenster | Raffael | Akeshan | Parallel-Logik & Übergaben |
|---|---|---|---|
| Fr 12. bis Di 16.06. | **P1** Stränge A+B: Ist-Stand-Check, EU-Sterilisation, Contracts, Service-Kerne (Audit, notify, i18n, Flags) | **P1** Strang C: Hot-Swap-Maschine (VM, Adapter, ui-mock, Visual-Reg), Walking-Skeleton, PWA, Konnektor-Muster | Ein Repo, getrennte Stränge, tägliche Integration. Ziel: Di Abend P1 fertig |
| Mi 17. bis Fr 19.06. | **P2** Auth/RLS/RBAC | **Infra live** (Staging, DBs, DNS, zentrale Dienste anbinden) + **P4** Files/Tasks | P2 und P4 hängen beide nur an P1, null Überschneidung. Übergabe: A liefert EntityLink-Tabelle (P4), R braucht sie erst in P6 |
| Sa 20. / So 21.06. | **P5** Apps-Engine | **P3** Querschnitts-Oberflächen | Unabhängig. P5 ist der Vertrag, den A ab P14 konsumiert |
| Mo 22. bis Mi 24.06. | **P6** CRM-Kern | **P19** Plattform-Admin | P19 hängt an P2+P3 (fertig), P6 an P4+P5 (fertig). Übergabe: A richtet via P19 die Demo-Tenant-Daten für Noah ein |
| Do 25. / Fr 26.06. | **P7** Lead-Inbox + **Noah-Demo 1** | **P17** HR-Hub | P17 hängt nur an P4. Gate-Demo macht R, A liefert Admin-Setup zu |
| Sa 27. bis Mo 29.06. | **P8** Sales-Pipeline | **P14** Email & Marketing | Beide brauchen P6 (seit Mi fertig). Übergabe: R liefert deal.won-Event, A braucht es nicht (nur P9) |
| Di 30.06. bis Do 02.07. | **P9** Projekte/Plantafel | **P15** Telefonie & Chat | Unabhängig. P15 hängt an P5+P6. Plantafel zeigt HR-Abwesenheiten: Schnittstelle zu P17 (fertig) |
| Fr 03.07. | **Gate W3: Kette E2E, Noah-Demo 2** | **P16-Start** (Form-Datenmodell, Kalender) | Gate-Beweis macht R, A startet parallel die größte Phase |
| Sa 04. / So 05.07. | **P11** Suche & Dashboard | **P16** (Forms, Booking) | P11 braucht P9 (fertig). Dashboard-Widgets aus P8-Aggregaten (Inversion) |
| Mo 06. bis Mi 08.07. | **P12** Automation (USP) | **P16** fertig, dann **P20** Billing | P12-Action-Registry: P16-Form-Trigger docken per Inversion an, kein Wartepunkt |
| Do 09.07. | **P13** KI-Layer, dann **FREEZE** | **P20**-Rest + **P21** DSGVO, dann **FREEZE** | Beide schließen unabhängig ab. Danach gemeinsamer Freeze-Check |
| Fr 10.07. | **Go/No-Go + [LAUNCH]** gemeinsam | Launch-Support (Deploy, Monitoring) | Noah-Walkthrough führen beide |
| ab Mo 13.07. (v2) | KWP-Recut, ab 20.07. KWP-Bau | Self-Service-Abo-UI + Postfach-Sync | Wieder dependency-frei parallel |
**Aushilfe-Regel:** Hängt einer am kritischen Pfad (A: P16-Block, R: P8/P9-Kette), zieht der andere Sprosse 2 der Beschleunigungs-Leiter und hilft track-übergreifend aus.
<div class="pagebreak"></div>
## RAFFAEL: Lead-Dev (Kern-Kette + USP + technische Externals)
| Datum | Aufgabe |
|---|---|
| **Fr 12.06.** | [MAIL] KWP-Mail beantworten (Callback-URLs `app.` + `staging-app.hivegrid.de/integrations/kwp/oauth/callback`) · bnWin.net-8.1-N3-Update an Noah/Geerkens-IT · AVV + Auskunfts-Vorlage + Website-Rechtstexte beim Anwalt · **Dev-Start P1** |
| Sa/So 13./14.06. | P1 weiter (volle Arbeitstage) |
| **Mo 15.06.** | **Externals-Paket (1 bis 2 h):** Mailjet SPF/DKIM/DMARC + Warm-up-Start · Google-Calendar-OAuth-Antrag · Legacy-Provider-Live-Verifizierung · AirCall- + PandaDoc-Sandbox · Hetzner-Projekt `HiveGrid` (S3-Bucket + Token) + Mistral-Key + DEK-Master-Key in Coolify-Secrets · Geo-IP/HIBP · Noah: 4 Freitags-Slots blocken |
| Mo/Di 15./16.06. | P1 fertigstellen (mit Akeshan), Ziel: Di Abend |
| Mi bis Fr 17. bis 19.06. | **P2** Auth / RLS / RBAC / Sessions |
| **Fr 19.06.** | **Gate W1 führen:** Hot-Swap-Drill + RLS-Cross-Tenant-Beweis + Konnektor-Demo |
| Sa/So 20./21.06. | **P5** Apps-Engine (Integrations-Vertrag für 5 Folgephasen) |
| Mo bis Mi 22. bis 24.06. | **P6** CRM-Kern |
| **Do 25.06.** | [€] **Partner-Gespräch: Kostenmatrix/Preise FIXIEREN.** Blocker für Haris! |
| Do/Fr 25./26.06. | **P7** Lead-Inbox · **Noah-Demo 1 präsentieren** (CRM) · Noah-Frage Lagerist (M070) · Mollie Payment Link für Founding-Deal an Haris |
| Sa bis Mo 27. bis 29.06. | **P8** Sales-Pipeline (Kanban, deal.won-Event) |
| **Mo 29.06.** | **v2-Vorlauf-Externals (30 min):** Web-Push VAPID-Keys · **Gmail-Restricted-Scope-Antrag** (Wochen Vorlauf!) · Microsoft-Entra-App *(kein Google Play Console / FCM/APNs — PWA-only, AD-17)* |
| Di bis Do 30.06. bis 02.07. | **P9** Projekte/Plantafel (offline!), ein Tag Puffer vor dem Gate |
| **Fr 03.07.** | **Gate W3: Kette E2E (Noah-Demo 2)** |
| Sa/So 04./05.07. | **P11** Suche & Dashboard (Keyword, feste Layouts) |
| Mo bis Mi 06. bis 08.07. | **P12** Automation-Engine (USP; Flow-Editor-Screens von David liegen bereit) |
| Do 09.07. | **P13** KI-Layer (Mistral-Gateway, Sprach-zu-Automation) · **Feature-Freeze** |
| **Fr 10.07.** | **Go/No-Go + [LAUNCH]** (Noah-Walkthrough) |
| Mo 13. bis Fr 17.07. | v2-Planung · **KWP-Recut** gegen API-Doku (kwpsync.exe NICHT bauen) · **Public-API (M161 bis 163) + API-Keys (M027)** |
| Sa/So 18./19.07. | **HiveMind/RAG + Whisper + pgvector** (M087) Start: Hybrid-Suche rüstet nach |
| **Mo 20. bis So 26.07.** | **KWP-Bau gegen echte API** (8 MS) · Fr 24.07.: Sync-E2E mit Geerkens-Testdaten |
| Mo 27. bis Mi 29.07. | **AdminUser-Welt** (M038/M039): getrennte Admin-Identität + AdminRBAC |
| Mi 29. bis Fr 31.07. | **HalloPetra** (M105) + **DSGVO-Auskunfts-Tooling** (M166) · v2-Gesamt-E2E |
| Fr 31.07. | [ZIEL] **v2 KOMPLETT live (alle 43 MS)** |
## AKESHAN: Co-Dev (Plattform + Kommunikation + Infra/Ops)
| Datum | Aufgabe |
|---|---|
| **Fr bis So 12. bis 14.06.** | **Dev-Start P1** Strang C: Hot-Swap-Maschine (VM-Konvention, Subframe-Adapter, ui-mock, Visual-Reg-Gate), Walking-Skeleton, PWA-Manifest, Konnektor-Muster |
| Mo 15.06. | P1 abschließen (mit Raffael, Ziel Di) · Coolify-Apps auf `staging-1` anlegen (Muster: Boilerplate-Apps; Registry = Gitea) |
| **Mi 17.06.** | **Infra LIVE:** Staging `staging-app`/`staging-api` auf `staging-1` (öffentlich + Härtung: nur synthetische Daten, eigene Secrets, noindex, Webhooks HMAC) · Coolify-managed Postgres/Redis · Cloudflare-DNS (`hivegrid.de`-Zone existiert) + Wildcard-TLS · **zentrale Dienste anbinden: mCaptcha + ClamAV + Meilisearch-scoped-Key. Läuft alles schon, nur ENV!** |
| Mi bis Fr 17. bis 19.06. | **P4** Files & Tasks (polymorphe EntityLink, **HEIC-zu-JPG**, Storage = Hetzner-S3) |
| **Fr 19.06.** | Gate W1 mit-demonstrieren (mCaptcha am Login live) |
| Sa/So 20./21.06. | **P3** Querschnitts-Oberflächen (Audit-Viewer, Notification-Center, DE-only) |
| Mo bis Mi 22. bis 24.06. | **P19** Plattform-Admin. Auflagen: kein Tenant-Workspace für Admins, `admin.hivegrid.de`-Host-Routing, Cookie-Trennung, TOTP-Pflicht, Abo-Zusammenstellung |
| Do/Fr 25./26.06. | **P17** HR-Hub · Noah-Demo 1: CRM-Demo-Daten via Admin einrichten |
| Sa bis Mo 27. bis 29.06. | **P14** Email & Marketing (Sende-Domain-Verifikation, BCC-Brücke, Kampagnen + A/B) |
| Di bis Do 30.06. bis 02.07. | **P15** Telefonie & Chat (AirCall, Chat komplett) |
| Fr 03.07. | **P16-Start** (Form-Builder-Datenmodell + Kalender) · Gate W3 |
| Sa bis Di 04. bis 07.07. | **P16** Kalender/Booking/Forms/Signatur (größte Phase, 4 volle Tage, Davids Screens liegen bereit) |
| Mi 08.07. | **P20** Billing (Abo-Baukasten-Recut) |
| **Do 09.07.** | P20-Rest + **P21** DSGVO/Feedback-Widget · **Feature-Freeze** |
| **Fr 10.07.** | Go/No-Go + Launch-Support (Deploy, Monitoring) |
| Mo 13. bis Fr 17.07. | v2: **Self-Service-Abo-Baukasten-UI** + **Postfach-Sync** (M096 bis 098; Outlook zuerst, Gmail ggf. Testmodus) |
| Sa/So 18./19.07. | **Onboarding-Wizard-UI** (M157, inkl. KI-Walkthrough-Rückläufer) |
| **Mo 20. bis Mi 22.07.** | **Customer-Portal** (M141 bis 146): Magic-Link-Auth, Projekt-Sicht, Upload (Andockpunkte liegen bereit) |
| **Do 23. bis Mo 27.07.** | **Mobile-PWA-Ausbau** (M167 bis 171): installierbare PWA-Shell, Web-Push (VAPID), Offline-Sync (P9-Queue ist PWA-ready); Recut auf PWA (kein EAS-Build, keine Native-Module, keine Store-Compliance, AD-17) |
| Di 28.07. | **Help-Center/Desk Start** (M172 bis 175) *(keine App-Store-Einreichung — PWA-only, AD-17; nativer Client + App-Store → v3)* |
| Di 28. bis Do 30.07. | Help-Center + Help-Desk fertig |
| Mi 29. bis Fr 31.07. | **Dashboard-Deluxe** (M149/150) + Querschnitt: M117 Bündelung/Quiet-Hours, M029 Sprach-Wechsler/EN, M033, M040, M138 |
| Fr 31.07. | [ZIEL] **v2 KOMPLETT live (alle 43 MS)** |
<div class="pagebreak"></div>
## DAVID: Designer (Screens App + Website)
Hot-Swap-Prinzip: Kein Screen blockt den Dev-Bau. Daten unten sind Demo-/Politur-Deadlines. Präzise Screen-Inhalte: `SCREEN-MAP.md`. Pro Screen vor Übergabe: Reconciliation-Checkliste (Playbook 6a).
| Datum | Aufgabe |
|---|---|
| **Fr 12.06.** | Kickoff: **Brand-/Design-Tokens** (Farben, Typo, Spacing; dienen Website UND App) · Website-Screens beginnen |
| **Sa 13.06.** | ✓ **Website-Screen-Designs an Dejan übergeben** (Landing, Features, Pricing-Teaser, Formulare) |
| Mo/Di 15./16.06. | Website-Feinschliff-Support für Dejan · parallel **D0-Start:** App-Shell + Archetypen (SCREEN-MAP §0) |
| Mi bis So 17. bis 21.06. | D0 weiter + Auth-Screens (Wochenende = volle Tage) |
| **So 21.06.** | ✓ **D0 KOMPLETT** (System + Shell + A1 bis A7 + Zustände) · ab Mo täglich 1 h Flow-Editor-Skizzen |
| **Mi 24.06.** | ✓ **CRM-Cluster** (Listen, Detail mit Activity-Stream, Promotion-Modal, Custom-Felder) → Noah-Demo 1 |
| **Fr 26.06.** | ✓ Sales-Kanban · Form-Builder-Canvas (+ Conditional-Logic) · Kampagnen-Editor · HR (Archetyp-Compose) |
| **Mi 01.07.** | ✓ Plantafel ([MOBIL] Monteur-mobile-first, Offline-Zustände!) · Chat-UI |
| **Fr 03.07.** | ✓ Flow-/Node-Editor final · Dashboard (3 feste Rollen-Layouts + Cmd+K) · [WEB] Booking-Pages (öffentlich!) · Kalender-View |
| Mo 06.07. | KI-Chat-Panel · Telefonie-Reste · Signatur-Status-Screens |
| Mo bis Do 06. bis 09.07. | **Politur extern sichtbarer Flächen** (Booking, Form-Pages, Marketing-Mails) · ✓ Visual-Reg-Baselines final (Do, vor Freeze) |
| Fr 10.07. | Launch-Tag: Standby für Hotfixes |
| Mo 13. bis Do 16.07. | **v2-Screens Welle 1:** Self-Service-Abo-UI (Akeshan braucht sie sofort!) · Onboarding-Wizard · Postfach-Inbox |
| Fr 17. bis So 19.07. | **Portal-Shell** (extern sichtbar, eigene Design-Sprache, höchster Polish!) |
| Mo 20. bis Mi 22.07. | **Mobile-PWA-Shell** (Touch-Paradigma, Tab-Bar, Offline-Zustände, installierbare PWA/Add-to-Homescreen) |
| Do 23. bis Mo 27.07. | **Help-Center** (Public-Content-Site) *(keine App-Store-Assets — PWA-only, AD-17)* |
| Di 28. bis Fr 31.07. | v2-Politur: Portal + Mobile-PWA |
## DEJAN: Website-Projekt (LIVE 17./18.06.) + Support
| Datum | Aufgabe |
|---|---|
| **Fr 12.06.** | **Scope fixieren:** Landing · Features · Pricing-Teaser · Demo-Anfrage-Formular · Webinar-Warteliste · Impressum/Datenschutz. Stack wählen, Domain/Hosting klären · **Subframe-Lizenzen kaufen** (David + beide Devs) |
| Sa/So 13./14.06. | Setup + Seitenstruktur · Davids Screens (ab Sa) einbauen |
| **Mo 15.06.** | **Content rein: Texte von Haris (Abnahme durch Noah!)** · Webinar-Plattform wählen (EU-konform: Livestorm/Zoom) |
| Di 16.06. | Build fertig · QA: responsive, Formular zu Lead-Liste an Haris, Rechtstexte (Anwalt-Paket) |
| **Mi 17.06. (Puffer Do 18.)** | [WEB] **WEBSITE LIVE** · EU-konformes Analytics · Search Console |
| Do 18.06. | Lead-Routing an Haris testen (Formular → Benachrichtigung) |
| Fr 19. bis Fr 26.06. | Pflege · SEO-Basics · Conversion-Feinschliff · Pricing-Seite vorbereiten (Preise kommen 25.06.) |
| Mo 29.06. bis Fr 03.07. | **Webinar-Landing + Anmelde-Flow** bauen (Kampagne startet 06.07.) |
| W4 06. bis 10.07. | Website-Launch-Update: finale Feature-Seiten, Pricing live, Launch-Ankündigung |
| Di/Mi 14./15.07. | [WEBINAR] Webinar-Technik (Plattform, Aufzeichnung, Follow-up-Seite) |
| Mo 20. bis Mo 27.07. | Help-Center-Inhalte einpflegen *(keine App-Store-Metadaten — Mobile ist PWA-only, AD-17; nativer Client + App-Store → v3)* |
| Fr 31.07. | Website-Update: Portal/Mobile-PWA/KWP als Features live *(keine Store-Badges — PWA-only, AD-17)* |
## HARIS: Vertrieb + Website-Texte (Ziel: [€] erste Gelder bis Ende Juli)
**Verantwortung:** Haris schreibt die Website-Texte und das gesamte Vertriebsmaterial. **Abnahme für Texte und Vertrieb: Noah.** Vor dem Schreiben: exklusives Painpoint-Gespräch mit Noah.
| Datum | Aufgabe |
|---|---|
| **Fr 12.06.** | **Zielkunden-Liste SHK** starten (Fokus: KWP-Nutzer, die haben ab Ende Juli den USP) · **Painpoint-Gespräch mit Noah terminieren** |
| **Sa/So 13./14.06.** | [CALL] **Exklusiv-Gespräch mit Noah: Painpoints aus dem SHK-Alltag** (für Website-Texte UND Vertriebs-Pitch) · danach **Website-Texte schreiben** (Landing, Features, Nutzenversprechen) |
| **Mo 15.06. früh** | ✓ **Website-Texte an Dejan übergeben, von Noah abgenommen** · Pitch + Gesprächsskript bauen (Noah-Abnahme) |
| **Do 18.06.** | Website live → **Inbound-Kanal aktiv:** Lead-Sheet aufsetzen, jede Anfrage < 24 h beantworten |
| Fr 19.06. | Pitch-Deck mit Davids D0-/Auth-Screens bestücken |
| **Di 23.06.** | [CALL] **ERSTE ANRUFE:** Discovery/Qualifizierung (Pain-Points, KWP-Nutzung, Team-Größe; noch keine Live-Demo) |
| **Do 25.06.** | Preise fix (von Raffael/Partner) → **Founding-Member-Angebot strukturieren** (Early-Bird-Jahresdeal), Noah-Abnahme |
| **Mo 30.06.** | [CALL] Klick-Demos (CRM-Stand von Noah-Demo 1) · **Founding-Deal live** via Mollie Payment Link. [€] Erste Abschlüsse VOR Launch möglich |
| Fr 03.07. | [CALL] Echte Produkt-Demos (Kette Lead → Sales → Auftrag läuft E2E) |
| Mo 06.07. | **Webinar-Einladungen** raus (mit Dejan; kleine Liste, Domain erst 3 Wochen gewärmt) |
| **Fr 10.07.** | [LAUNCH] → zahlende Onboardings (Raffael/Admin stellt Abos zusammen) |
| Di/Mi 14./15.07. | [WEBINAR] **Webinar Nr. 1 moderieren** (Raffael demonstriert) → Trial-/Kauf-Conversions |
| Fr 24.07. | Trial-Follow-ups (14 Tage nach Launch-Onboardings) |
| **Fr 31.07.** | [€] **Bilanz: Founding-Deals + Onboardings + Trial-Konversionen = erste Gelder** ✓ |
## NOAH (Geerkens, extern): was wir wann brauchen
| Datum | Was wir von Noah brauchen |
|---|---|
| Fr 12.06. | KWP-Mail-Antwort freigeben/weiterleiten · bnWin.net-Update 8.1 N3 bei Geerkens-IT anstoßen |
| **Sa/So 13./14.06.** | [CALL] **Painpoint-Gespräch mit Haris** (SHK-Alltag, was nervt an HubSpot/Zettelwirtschaft) + **Abnahme der Website-Texte** |
| Mo 15.06. | 4 Freitags-Slots bestätigen (19.06. · 26.06. · 03.07. · 10.07.) · laufend: **Abnahme Vertriebsmaterial/Pitch** |
| bis Fr 26.06. | Echte SHK-Beispieldaten (Pipelines, Custom-Felder, Rollen) · **Lagerist-Frage beantworten** (gehört der Lager-Arbeitsplatz zum Validierungs-Versprechen?) |
| Fr 26.06. / 03.07. / 10.07. | Demo 1 (CRM) · Demo 2 (Kette E2E) · **Voll-Walkthrough mit Go/No-Go** |
| ab Mo 20.07. | KWP-Test-Instanz/Testdaten für v2-P10-Verprobung |
<div class="pagebreak"></div>
## v2-Sprint gemeinsam: Mo 13.07. bis Fr 31.07. (alle 43 MS)
| Wann | Raffael (17 MS) | Akeshan (26 MS) | David |
|---|---|---|---|
| Mo 13. bis Fr 17.07. | KWP-Recut + Public-API + API-Keys (4) | Self-Service-Abo-UI + Postfach-Sync (3) | Abo-/Wizard-/Inbox-Screens |
| Sa/So 18./19.07. | HiveMind/RAG + pgvector Start (1) | Wizard-UI (1) | Portal-Shell (Polish!) |
| Mo 20. bis So 26.07. | **KWP gegen echte API (8)**, Fr 24.: Geerkens-E2E | **Portal (6)** bis Mi, dann **Mobile-PWA (5)** | Mobile-PWA-Shell, dann Help |
| Mo 27. bis Fr 31.07. | AdminUser-Welt (2) + HalloPetra + M166 (2) | Mobile-PWA-Politur · Help (4) · Dashboard-Deluxe + Querschnitt (7) | Mobile-PWA + Politur |
**Fr 31.07.: [ZIEL] v2 KOMPLETT LIVE: alle 43 MS gebaut und deployt.** Extern läuft nach (außerhalb unserer Kontrolle): Gmail-Restricted-Scope-Verifizierung (Outlook-Postfach + Gmail-Testmodus überbrücken). *(Kein App-Store — Mobile ist PWA-only in v1/v2, AD-17; nativer Client + App-Store → frühestens v3.)*
## Beschleunigungs-Leiter: wenn wir SCHNELLER sind (vorab beschlossen, kein Meeting nötig)
**Trigger:** Phase vor Slot-Ende fertig UND Gate-Kriterien grün → im 9:00-Sync die nächste Sprosse ziehen.
| Sprosse | Bedingung | Aktion |
|---|---|---|
| **1 (Standard)** | eigene Phase früher fertig | Nächste eigene Phase im Track sofort ziehen, der Plan rückt nach vorn |
| **2** | anderer Track hängt am kritischen Pfad | Track-übergreifend aushelfen (heißeste Kandidaten: Akeshans P16-Block, Raffaels P8/P9-Kette) |
| **3** | Sprint-Puffer 3+ Tage | **Launch-Vorzieh-Prüfung mit Noah:** Go/No-Go früher ansetzen. Voraussetzungen: alle v1-Phasen fertig, Legacy-Provider live, Staging-Abnahme grün. Launch ist NICHT kalendergebunden; nur Mailjet-Warm-up (Kampagnen) und Google-Verifizierung laufen auf eigener Timeline und blocken den Launch nicht |
| **4** | Launch nicht vorziehbar (Externals) | v2-Vorzieher in fester Reihenfolge: (a) KWP-Recut-Vorarbeit gegen die API-Doku (Mapping + Adapter-Gerüst, KEIN Mock-E2E) → (b) Self-Service-Abo-Baukasten-UI (Revenue ohne Admin-Handarbeit) → (c) Postfach-Sync |
**Pflicht-Anteil:** Pro gewonnener Woche mindestens 1 Tag in den Härtungs-Pool (Bug-Bash, Lasttest, Security-Pass, Visual-Reg-Abdeckung). Geschwindigkeit kauft Qualität, nicht nur Features.
| Anti-Regel | Bedeutung |
|---|---|
| Keine Cut-Rückholung in Eigenregie | Gewonnene Zeit holt NIE gestrichene/gedünnte Features zurück. Die Schnitte 1 bis 12 waren Entscheidungen, kein Zeitmangel. Rückholen nur nach neuer Entscheidungsrunde mit Raffael |
| Keine Goldrand-Politur intern | Politur-Budget gehört den extern sichtbaren Flächen (Booking, Forms, Marketing-Mails), nicht Admin/Settings |
| Gates bleiben freitags | Noah-Slots sind extern fixiert. Früher fertig heißt mehr Beweis-Tiefe am Gate, nicht Gate verschieben. Einzige Ausnahme: Sprosse 3 verlegt das finale Go/No-Go bewusst |
## Externals-Kalender (Wer macht was bis wann)
| Bis | Was | Wer |
|---|---|---|
| Fr 12.06. | KWP-Mail (beide Callback-URLs) · bnWin.net 8.1 N3 · AVV + Rechtstexte beim Anwalt | **Raffael** |
| Fr 12.06. | Subframe-Lizenzen (David + Devs) · Website-Domain/Hosting | **Dejan** |
| Sa/So 13./14.06. | Painpoint-Gespräch + Website-Texte (Noah-Abnahme) | **Haris + Noah** |
| Mo 15.06. | Mailjet-DNS + Warm-up · Google-Calendar-OAuth · Legacy-Provider-Live · AirCall/PandaDoc-Sandbox · Hetzner-Projekt + Mistral-Key · Noah-Slots | **Raffael** |
| Mi 17.06. | Staging + Postgres/Redis + DNS/Wildcard-TLS + zentrale Dienste (mCaptcha/ClamAV/Meilisearch-Key) | **Akeshan** |
| **Do 25.06.** | [€] **Kostenmatrix/Preise mit Partner fixieren. Blocker für Haris!** | **Raffael** |
| Fr 26.06. | SHK-Beispieldaten + Lagerist-Antwort | **Noah** |
| **Mo 29.06.** | **v2-Vorlauf-Externals anstoßen (Wochen Vorlauf!):** Web-Push VAPID-Keys generieren · **Gmail-Restricted-Scope-Antrag** (Verifizierung dauert Wochen!) · Microsoft-Entra-App (Outlook-Postfach + Graph) *(kein Google Play Console / FCM/APNs — PWA-only, AD-17)* | **Raffael** |
| Mo 13.07. | HalloPetra-Konto + API · Memberspot/Boobora-Zugänge | **Raffael** |
| Mo 20.07. | KWP-API-Zugang aktiv nutzen | **Raffael** |
| Mo 20.07. | Mobile-PWA-Marketing-Material + Help-Center-Inhalte beginnen *(keine App-Store-Metadaten — PWA-only, AD-17)* | **Dejan + David** |
## Risiken & Plan B
1. **Preise nicht fix am 25.06.:** Haris kann qualifizieren, aber nicht abschließen. Founding-Deals rutschen 1:1 nach hinten. Härtester Business-Blocker.
2. **Google-Calendar-Verifizierung reißt W4:** Launch im Testmodus (interne Workspace-Konten), Verifizierung parallel.
3. **Akeshans P16-Block (Sa 04. bis Di 07.07.):** größte Phase, durch 7-Tage-Woche auf 4 volle Tage entzerrt. Bei Riss: Notfall-Sprossen 2/3 (Signatur manuell, Booking via Formular). NIEMALS: P1 bis P9, Automation, Marketing-Kern, Konnektor.
4. **Davids Flow-Editor:** ab 22.06. täglich 1 h, sonst leidet die P12-Demo-Qualität (Bau blockt nie, ui-mock).
5. **Mailjet-Warm-up zu spät:** Webinar-Mails landen im Spam. Start 15.06. ist Pflicht, keine Massen-Mails vor W3.
6. **Mobile-PWA (v2, PWA-only, AD-17):** Mobile ist eine installierbare PWA (Service-Worker, Add-to-Homescreen, Web-Push via VAPID) — kein App-Store, keine Einreichung, keine Store-Compliance, kein externer Freigabe-Anker. Risiko reduziert sich auf PWA-Reichweite (iOS-Safari-PWA-Limits) und Web-Push-Support; voll in unserer Kontrolle. Nativer Client + App-Store → frühestens v3 (Backlog, nicht beauftragt).
7. **Gmail-Restricted-Scopes (v2-Postfach):** Googles Verifizierung dauert Wochen bis Monate (Security-Assessment möglich). Antrag am 29.06. stellen; bis dahin Outlook-Postfach voll + Gmail im Testmodus (interne Workspace-Konten). Kein Blocker für den 31.07., aber für die Gmail-Breite danach.
---
*Detail-Quellen: SPRINT-4W.md (Gates/Notfall-Leiter) · SCREEN-MAP.md (alle ~95 Screens präzise) · DESIGNER-FIRST-PLAYBOOK.md · EXTERNALS-CHECKLISTE.md · PHASE-SOURCES.md (v2-Backlog). Stand 12.06.2026, Schnitt 12 + Infra-Wechsel.*
@@ -0,0 +1,108 @@
---
status: awaiting_human_verify
trigger: "Investigate and fix the new generic HiveGrid HTTP 500, very likely on the HalloPetra/telephony integration settings path after PR #340 was deployed to staging."
created: 2026-08-01T22:52:09Z
updated: 2026-08-02T00:27:00Z
---
## Current Focus
hypothesis: confirmed; the live catalog backfill removes the staging module-not-found cause, and the status-preserving route boundary prevents its incorrect generic-500 presentation
test: open the tenant HalloPetra settings page once more with the original authenticated browser session
expecting: the page loads with HalloPetra API-key setup; no generic 500 appears, and a genuine unavailable-module state preserves HTTP 404
next_action: user refreshes the original authenticated workflow; all independently executable staging checks are complete
## Symptoms
expected: The tenant telephony integration page should load and allow HalloPetra API-key setup.
actual: The user sees the branded generic HiveGrid error page with HTTP 500.
errors: "HiveGrid / Fehler 500 / Etwas ist schiefgelaufen. Wir konnten deine Anfrage nicht abschließen. Bitte versuche es erneut oder kontaktiere den Support, falls das Problem weiterhin besteht."
reproduction: Exact URL/action was not provided. Recent context strongly suggests /:tenant/settings/integrations/telephony or opening/configuring HalloPetra. First establish the exact failing path from staging logs/Sentry or code evidence, then reproduce with focused tests.
started: First reported 2026-08-02, immediately after HalloPetra feature PR #340 (feature head 1643dd3ac6527621e1e95504505dadc6fdb62ff3; merge e7c6a138a77f82ffa58e768ba242301eaa99b79b) was deployed to staging. Staging health and ready endpoints are green at that revision.
## Eliminated
- hypothesis: the user's role is missing telephony permissions
evidence: all four telephony permission rows exist in staging; failure occurs earlier as module not_found
timestamp: 2026-08-01T23:01:00Z
- hypothesis: tenant RLS hides an existing telephony catalog feature
evidence: read-only staging inspection found zero telephony SubscriptionFeature rows globally, so there is no row for RLS to hide
timestamp: 2026-08-01T23:01:00Z
## Evidence
- timestamp: 2026-08-01T22:54:00Z
checked: assigned worktree, branch, working tree, required workspace paths, and forbidden US-provider imports
found: branch fix/hallopetra-500-20260802 is isolated at b6501b0e; only this debug file is untracked; package.json, apps, packages, and prisma exist; the forbidden-import scan returned no matches
implication: session isolation and structural pre-flight gates are satisfied, so baseline validation can proceed without overwriting unrelated work
- timestamp: 2026-08-01T23:01:00Z
checked: mandatory root typecheck and root test baseline at b6501b0e
found: typecheck passed; all 1,175 executed test files passed with 8,270 executed tests passing and 60 tests skipped
implication: the failure is not reproduced by the broad local baseline and is consistent with staging data/catalog drift plus an uncovered route error-normalization path
- timestamp: 2026-08-01T23:01:00Z
checked: staging web container logs for the reported request
found: the telephony loader repeatedly throws CatalogError foundation.not_found from loadTelephonyContext with status 404, i18nKey foundation.errors.notFound, and details { module: telephony }
implication: the exact failing path is the tenant telephony settings loader; the generic branded 500 is secondary incorrect error rendering, not the primary service status
- timestamp: 2026-08-01T23:01:00Z
checked: read-only staging catalog and permission rows
found: SubscriptionFeature contains zero telephony rows globally while all four telephony permission rows exist; the active public base plans starter, pro, and business each have 34 feature rows and no telephony row
implication: entitlement catalog drift, not role permission absence, makes every tenant resolve the telephony module as unavailable; a guarded forward-only catalog backfill is required
- timestamp: 2026-08-01T23:02:00Z
checked: persistent debug knowledge base and required debug-pattern references
found: no .planning/debug/knowledge-base.md exists; the common-pattern map classifies the local-versus-staging divergence as Environment/Config and the generic-500 mismatch as Error Handling
implication: there is no known-pattern shortcut; investigate catalog data flow and error normalization as two specific falsifiable mechanisms
- timestamp: 2026-08-01T23:14:00Z
checked: focused telephony route regression suite after status normalization
found: apps/web/app/routes/app.$tenant/telephony.routes.test.ts passes 6/6 tests, including loader and action CatalogError-to-404 Response cases
implication: the route boundary no longer promotes the known module-not-found condition to a generic HTTP 500
- timestamp: 2026-08-01T23:14:00Z
checked: generated Prisma client worktree drift after baseline typecheck
found: Prisma generation introduced only trailing-space diffs in Registration.ts and TenantProductConfiguration.ts; both generated files were restored exactly and no generated files remain modified
implication: verification can continue without contaminating the fix with unrelated generated output
- timestamp: 2026-08-01T23:18:00Z
checked: complete migration-history/schema parity verifier
found: the consolidated baseline audit passed and Prisma reported no difference after replaying the forward migration history with the restricted migrator role
implication: the new data migration does not introduce schema drift and is accepted by the production-shaped migration chain
- timestamp: 2026-08-01T23:24:00Z
checked: isolated PostgreSQL execution of the telephony catalog migration
found: canonical starter/pro/business plans received exactly one included telephony row; a second run remained at three rows; duplicate starter products aborted; an empty catalog succeeded with zero rows; SubscriptionProduct and SubscriptionFeature retained FORCE RLS
implication: the migration directly repairs the staging data shape while remaining idempotent, fail-closed on ambiguity, fresh-chain safe, and RLS-preserving
- timestamp: 2026-08-01T23:27:00Z
checked: permanent migration contract test and focused telephony route regression suite
found: 2 migration-contract tests and 6 route tests pass; the contract pins canonical codes, included entitlement shape, ambiguity/idempotency/empty-catalog guards, FORCE RLS preservation, and inverse SQL
implication: both root-cause mechanisms now have focused regression protection in the repository
- timestamp: 2026-08-01T23:28:00Z
checked: final root typecheck and lint after implementation
found: both commands completed successfully; Prisma regeneration produced only the two known comment-whitespace diffs, which were restored exactly
implication: the implementation is type-safe and lint-clean without generated-client contamination
- timestamp: 2026-08-01T23:28:00Z
checked: final Prisma validation, generated tenant-policy contract, and full migration-history/schema parity
found: Prisma schema is valid, the tenant policy contract passes 377/377 definitions, the consolidated migration audit passes, and Prisma reports no schema difference
implication: the bounded data migration is compatible with the production-shaped migration chain and does not alter the RLS policy contract
- timestamp: 2026-08-01T23:28:00Z
checked: final focused regressions and worktree diff hygiene
found: 2 test files pass with 8/8 tests; git diff --check passes; no generated or unrelated files remain modified
implication: self-verification is complete and only staging deployment plus original-workflow confirmation remains
- timestamp: 2026-08-01T23:52:00Z
checked: final complete root test suite after rebasing onto the current main branch
found: all 1,176 executed test files passed with 8,275 executed tests passing and 60 tests skipped
implication: the regression fix introduces no failure in the repository-wide core test surface
- timestamp: 2026-08-02T00:23:00Z
checked: fix PR, protected checks, normal merge, and automatic staging deployment
found: PR #345 merged normally with feature-head ancestry preserved; all 11 required checks passed after one unrelated Traefik filesystem timeout passed on its isolated rerun; staging deploy run 11732 succeeded on merge revision f4b78178a
implication: the reviewed fix, migration, and web boundary are deployed from the exact verified revision
- timestamp: 2026-08-02T00:25:00Z
checked: public staging web/API health and readiness plus the live database migration/catalog/RLS state
found: web and API health/readiness return HTTP 200 on exact revision f4b78178a; the migration is recorded as finished; starter, pro, and business each have exactly one included telephony feature; SubscriptionProduct and SubscriptionFeature both retain enabled and forced RLS
implication: the original missing-entitlement condition is repaired in the live environment without weakening the tenant-isolation contract
- timestamp: 2026-08-02T00:26:00Z
checked: unauthenticated telephony route boundary and post-deploy web logs
found: the protected route returns the expected login redirect rather than HTTP 500; the current web container has no new telephony CatalogError, module-not-found, or HTTP-500 log line
implication: automated staging proof is complete; only the authenticated browser-session confirmation remains
## Resolution
root_cause: PR #340 shipped the telephony gate and provider implementation without a deploy-time SubscriptionFeature row for telephony on the canonical starter, pro, and business base plans. loadTelephonyContext therefore returned foundation.not_found for every tenant. The telephony settings loader/action did not convert that server-only CatalogError into a React Router Response, so production treated it as an unhandled loader error and rendered the generic HTTP 500 page instead of preserving status 404.
fix: Added a guarded forward-only migration that inserts exactly one included telephony feature for each canonical starter/pro/business active public base plan while keeping FORCE RLS enabled and aborting on product/feature ambiguity. Added a settings-route context adapter that converts CatalogError into a status-preserving Response for loader and action paths, with focused 404 regressions.
verification: Root typecheck and lint passed. The complete root suite passed with 1,176 test files and 8,275 tests; 60 tests were skipped. Prisma validate, tenant-policy contract (377/377), and migration/schema parity passed. Focused tests passed 8/8. An isolated PostgreSQL 16 harness verified the canonical backfill, idempotency, ambiguity abort, empty-catalog no-op, and FORCE RLS retention. PR #345 passed all 11 checks and deployed successfully through run 11732. Live web/API health and readiness match revision f4b78178a; the migration, three included entitlements, and forced RLS are present. Post-deploy logs are clean. The original authenticated browser workflow still awaits user confirmation.
files_changed: [prisma/migrations/20260801231000_telephony_entitlement_catalog/migration.sql, packages/db/src/telephony-entitlement-catalog-migration.test.ts, apps/web/app/routes/app.$tenant/settings/integrations/telephony.tsx, apps/web/app/routes/app.$tenant/telephony.routes.test.ts]
@@ -1,7 +1,7 @@
# Designer-Brief · P1 — Fundament & Walking-Skeleton
**Phase:** 1/21 · **Modul:** M00/Querschnitt (logActivity · Search-Registry · Subframe-Adapter · Feature-Flags · Audit · notify · i18n) · **Owner-Dev:** Raffael (R-P1a/b) + Akeshan (AK-P1c) · **Designer:** David (D-P1, App-Shell-Baseline → blockt ~70 % aller Folge-Screens)
**Quellen:** `ROADMAP.md` §Phase 1 · `SCREEN-MAP.md` §0 (D0/App-Shell + Archetypen A2–A7) · `REQUIREMENTS.md` Querschnitt-Block + M21/M22/M30/M32-Datenmodelle · `ENTITY-MODEL.md` Cross-Cutting + Domäne 2 (Service-Kern-Teile) · `docs/INTEGRATION-CONTRACTS.md`, `docs/ARCHITECTURE-DECISIONS.md`; Service-Kern-Specs `_bmad-output/specs/M21-audit-log.md`, `M22-notifications.md`, `M30-i18n.md`, `M32-feature-flags.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Diese Phase liefert die **Archetypen-Baseline** selbst (A1 App-Shell + A2–A7 + Basis-Primitives), aus der alle Folge-Phasen komponieren.
> ⚙️ **Sonder-Hinweis (überwiegend Querschnittsdienste, kaum Fach-UI):** Phase 1 ist primär Backend/Plattform-Fundament (logActivity, Search-Registry, Subframe-Adapter, Mass-Action-Schutz, Audit-Hash-Kette, notify(), i18n-Engine, Feature-Flag-Engine + Entitlement-Gate). Es gibt **keine fachlichen Screens** — der UI-Anteil ist (1) die **App-Shell-Baseline** (§0, Single Source of Truth für alle Folge-Screens) und (2) eine **Walking-Skeleton-Beispielroute**, die das View-Model-Muster, die Sidebar-Registrierung und das Konnektor-Gating exemplarisch zeigt. David designt hier das Fundament; Fach-Screens kommen ab P2.
@@ -47,5 +47,5 @@ Sidebar mit Icon+Label-Navigationseinträgen und drei Konnektor-Zuständen (akti
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (R-P1a/b, AK-P1c) aktualisiert:
@@ -1,14 +1,15 @@
# Designer-Brief · P2 — Identität & Mandantentrennung
**Phase:** 2/21 · **Modul:** M27 (Auth / Multi-Tenancy / RBAC / Sessions) · **Owner-Dev:** Raffael (R-P2a/b) · **Designer:** David (D-P2, fällig So 21.06. mit D0-Baseline)
**Quellen:** `ROADMAP.md` §Phase 2 · `SCREEN-MAP.md` §1 AUTH-SCREENS · `REQUIREMENTS.md` Modul 27 (REQ-auth-multi-tenancy, -methoden, -rbac, -user-lifecycle) · `ENTITY-MODEL.md` Domäne 1 (Tenant/User/TenantUser/TenantRole/Permission/Group/Invitation/Session) · `_bmad-output/specs/M27-auth-multi-tenancy.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A4 Form/Input, A5 Modal/Wizard, A6 Settings, A2 Liste).
🖥️ **Interim-UI gebaut (AD-28):** Screen-Referenz in `../HiveGrid-Wireframes/Tickets/Interim-Handover/P02-Auth-RBAC.md` — David-Delta (D-P2) liegt bereits vor, dient nur dem Konsistenz-Abgleich.
> ⚙️ **Scope-Hinweis (Scope-Schnitt 12.06.):** API-Keys (M027) → v2 mit Public-API; das Boilerplate-`ApiKey`-Modell bleibt ungenutzt im Code — **kein API-Key-Screen in v1**. Magic-Link ist v1 nur als Login-Alternative (das exklusive Customer-Portal-Magic-Link gehört zu v2/P26). Sprache fest DE — **kein Sprach-Wechsler** im Profil.
## Was dieses Modul tut (Kurzfassung)
Ein Handwerksbetrieb registriert sich selbst, meldet sich sicher an und arbeitet in einem vollständig RLS-isolierten Mandanten mit rollenbasierten Rechten. Self-Service-Signup erzeugt Tenant + auto-generierten Slug (Reserved-Words geblockt) + Auto-SHK-Seed; Login mit Email+Passwort (NIST/Breach-Check) plus TOTP-2FA; serverseitige Sessions in Postgres (Geräte-Liste, Revoke, „überall abmelden") mit Redis-Cache; 6 SHK-Standard-Rollen geseedet; Admin kann Nutzer einladen (48h-Token), deaktivieren (mit Reassign-Workflow) und DSGVO-konform per PII-Anonymisierung löschen. RLS-Policies verhindern nachweisbar mandantenübergreifenden Datenzugriff (AD-1).
Ein Handwerksbetrieb registriert sich selbst, meldet sich sicher an und arbeitet in einem vollständig RLS-isolierten Mandanten mit rollenbasierten Rechten. Self-Service-Signup erzeugt Tenant + auto-generierten Slug (Reserved-Words geblockt) + Auto-SHK-Defaults; Login mit Email+Passwort (NIST/Breach-Check) plus TOTP-2FA; serverseitige Sessions in Postgres (Geräte-Liste, Revoke, „überall abmelden") mit Redis-Cache; fünf editierbare SHK-Tenant-Rollen werden angelegt und der Owner erhält ausschließlich die globale Rolle `Admin`; Admin kann Nutzer einladen (48h-Token), deaktivieren (mit Reassign-Workflow) und DSGVO-konform per PII-Anonymisierung löschen. RLS-Policies verhindern nachweisbar mandantenübergreifenden Datenzugriff (AD-1/AD-29).
## Benötigte Screens
@@ -21,7 +22,7 @@ Ein Handwerksbetrieb registriert sich selbst, meldet sich sicher an und arbeitet
| Tenant-Auswahl | Tenant-Liste mit zuletzt-genutzt, Suchfeld (Erst-Login mit ≥2 Tenants); plus Klartext-Screen „ohne Tenant" mit Funktionen „Neuen Workspace anlegen" / „Auf Einladung warten" | A2 |
| Session-Verwaltung [`/settings/security`] | Aktive Sessions (Gerät, Browser, IP, Standort, letzte Aktivität) + Abmelden je Session + „überall abmelden" · Trust-Device-Liste mit Revoke | A2/A6 |
| Profil [`/settings/profile`] | Name, Avatar, Telefon, Passwort ändern, 2FA einrichten (QR), Hell/Dunkel-Toggle (Sprache fest DE — kein Wechsler v1) | A6 |
| Rollen-Editor [`/admin/roles`] | Rollen-Liste (Name, User-Anzahl) · Editor: Name, Beschreibung, Permission-Bundles + Advanced-Einzelrechte · 6 SHK-Rollen vorgeseedet · Löschen mit Block bei zugewiesenen Usern → Ersatz-Rolle/Bulk-Reassign | A2+A6 |
| Rollen-Editor [`/admin/roles`] | Rollen-Liste (Name, User-Anzahl) · Editor: Name, Beschreibung, Permission-Bundles + Advanced-Einzelrechte · fünf editierbare SHK-Tenant-Rollen vorgeseedet; Owner ausschließlich mit globaler Rolle `Admin` · Löschen mit Block bei zugewiesenen Usern → Ersatz-Rolle/Bulk-Reassign | A2+A6 |
| Gruppen [`/admin/groups`] | Gruppen-Liste mit Mitgliederzahl, Bulk-Add/Remove | A2 |
| Mitarbeiter [`/admin/users`] | User-Liste (Name, Email, Rolle, Status, 2FA) · Einladungs-Modal (Email, Rolle, Gruppen, Nachricht) · Einladungs-Status-Liste · Deaktivieren mit **Reassign-Workflow** (offene Verknüpfungen anzeigen, Bulk-Übertragung) | A2+A5 |
| Konto löschen [`/settings/account`] | Multi-Step: Erklärung → optional Daten-Export → Passwort+2FA → Countdown-Bestätigung · Block-Edge-Case wenn einziger Tenant-Admin (Klartext + Direkt-Link zum Lösen) | A5 |
@@ -35,7 +36,7 @@ Ein Handwerksbetrieb registriert sich selbst, meldet sich sicher an und arbeitet
- [ ] TOTP-2FA (RFC 6238) mit QR-Einrichtung + Trust-Device
- [ ] Serverseitige Postgres-Sessions (Geräte-Liste, Revoke einzeln, „von allen Geräten abmelden") mit Redis-Cache (AD-4)
- [ ] RLS-Policies (USING/WITH CHECK, `SET LOCAL app.tenant_id`, App-Rolle ohne BYPASSRLS) verhindern nachweisbar Cross-Tenant-Zugriff (AD-1) — Backend, aber prägt „keine-Berechtigung"-Zustände der UI
- [ ] 6 SHK-Standard-Rollen geseedet; Rollen-/Gruppen-Verwaltung (Permission-Bundles + Advanced-Einzelrechte)
- [ ] Fünf editierbare SHK-Tenant-Rollen angelegt; Owner ausschließlich mit globaler Rolle `Admin`; Rollen-/Gruppen-Verwaltung (Permission-Bundles + Advanced-Einzelrechte)
- [ ] User-Einladung (48h-Token), Soft-Deaktivierung mit Reassign-Workflow, DSGVO-Löschung via PII-Anonymisierung ohne Audit-Trail-Verlust
- [ ] Multi-Tenant-Membership: Tenant-Auswahl-Screen + Tenant-Switcher (Topbar aus P1) + „ohne Tenant"-Screen
- [ ] *(→ v2)* ~~API-Key-Verwaltung mit Scopes/Rate-Limit~~ — wandert mit Public-API (M161–163)
@@ -54,5 +55,5 @@ Auth-Formulare mit Email/Passwort-Feldern, Passwort-Stärke-Anzeige + Breach-Kla
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (R-P2a/b) aktualisiert:
@@ -1,8 +1,9 @@
# Designer-Brief · P3 — Querschnitts-Oberflächen
**Phase:** 3/21 · **Module:** M21 (Audit-Viewer/Export) · M22 (Notification-Center/Settings) · M30 (Sprach-Settings DE) · **Owner-Dev:** Akeshan (AK-P3) · **Designer:** David (D-P3)
**Quellen:** `ROADMAP.md` §Phase 3 · `SCREEN-MAP.md` §2-Anhang (Audit-Viewer / Notification-Center / Notification-Settings) · `REQUIREMENTS.md` Modul 21/22/30 (REQ-audit-retention-export, -permissions, -notification-versand-pipeline, -i18n-outbound) · `ENTITY-MODEL.md` Domäne 2 (AuditEntry, Notification, NotificationPreference, NotificationDevice; i18n = Felder, keine Tabelle) · `_bmad-output/specs/M21-audit-log.md`, `M22-notifications.md`, `M30-i18n.md` (Oberflächen-Teile; Service-Kerne liegen in P1)
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste + Drawer, A6 Settings).
🖥️ **Interim-UI gebaut (AD-28):** lauffähige Screen-Referenz + genutzte Elemente/VM/Actions in `../HiveGrid-Wireframes/Tickets/Interim-Handover/P03-Audit-Notifications.md`. Layout bleibt frei.
> ⚙️ **Scope-Hinweis (Scope-Schnitte 11./12.06.):** v1 ist bewusst gedünnt. Audit: **kein Retention-Editor / Legal-Hold / Saved-Views** (→ v2; fixe Default-Retention). Notifications: **kein Quiet-Hours / keine Bündelung / kein Push-Kanal** (→ v2 mit M117; Push-Kanal = Stub). i18n: **v1 DE-only — kein Sprach-Wechsler, keine EN-Templates** (→ v2); die Sprach-UX beschränkt sich auf den fest-DE-Hinweis im Profil + `Contact.language`-Feld als Outbound-Steuerung (ab v2 aktiv). Die Service-Kerne (Hash-Kette, notify(), i18n-Engine) liegen schon in P1 — P3 liefert nur die Bedien-Oberflächen.
@@ -51,5 +52,5 @@ Audit-Daten-Tabelle (server-paginiert) mit Actor-Kind-Marker (visuell unterschei
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (AK-P3) aktualisiert:
@@ -1,8 +1,9 @@
# Designer-Brief · P4 — Files & Tasks
**Phase:** 4/21 · **Module:** M23 (Files) · M26 (Tasks) · **Owner-Dev:** Akeshan (AK-P4a/b) · **Designer:** David (D-P4)
**Quellen:** `ROADMAP.md` §Phase 4 · `SCREEN-MAP.md` §2-Anhang (Files-Browser / Upload-View / File-Detail / Task-Liste / Task-Detail) · `REQUIREMENTS.md` Modul 23/26 (REQ-files-datenmodell, -upload-preview, -tasks-datenmodell, -tasks-reminder-archivierung) · `ENTITY-MODEL.md` Domäne 3 (File, FileChunk, FileUploadProgress, FileEntityLink, Task, TaskWatcher) · `_bmad-output/specs/M23-files.md`, `M26-tasks.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A3 Detail, A4 Form + Dropzone, A5 Modal).
🖥️ **Interim-UI gebaut (AD-28):** lauffähige Screen-Referenz + genutzte Elemente/VM/Actions in `../HiveGrid-Wireframes/Tickets/Interim-Handover/P04-Files-Tasks.md`. Layout bleibt frei.
> ⚙️ **Scope-Hinweis (Scope-Schnitt 12.06.):** Files v1 ohne **Versionierung / Office-/Video-Previews / Resume-Upload / OCR** (→ v2) — **HEIC→JPG-Konvertierung bleibt Pflicht** (iPhone-Monteur-Fotos). Kein Versions-Verlauf-Sub-View in v1. Tasks: Kommentare als reine Notiz-Activity, Watcher minimal. **Task-Liste ist als wiederverwendbare Komponente zu bauen** — P12/P14/P16 betten sie ein, und sie erscheint eingebettet in allen Entity-Detail-Views (Kontakt/Firma/Lead/Projekt) als Tasks-Tab.
@@ -50,5 +51,5 @@ Daten-Tabelle mit Tabelle/Grid-Umschalter, Vorschau-Thumbnail, sortierbaren Spal
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (AK-P4a/b) aktualisiert:
@@ -1,10 +1,11 @@
# Designer-Brief · P5 — Apps-Engine & Integrations-Framework
**Phase:** 5/21 · **Modul:** M33a (Apps-Engine / Adapter-Layer) · **Owner-Dev:** Raffael (R-P5) · **Designer:** David (D-P5)
**Quellen:** `ROADMAP.md` §Phase 5 · `SCREEN-MAP.md` §2-Anhang (Integrations-Katalog / Connection-Setup-Wizard) · `REQUIREMENTS.md` Modul 33a (REQ-apps-engine-datenmodell, -apps-engine-lifecycle) · `ENTITY-MODEL.md` Domäne 4 (App, DataConnection, AppSyncRun, AppSyncRunLog, AppSyncItem) · `_bmad-output/specs/M33a-apps-engine.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A6 Settings/Connection-Kit + Connection-Card, A5 Modal/Wizard, A2 Liste).
🖥️ **Interim-UI gebaut (AD-28):** lauffähige Screen-Referenz + genutzte Elemente/VM/Actions in `../HiveGrid-Wireframes/Tickets/Interim-Handover/P05-Integrations.md`. Layout bleibt frei.
> ⚙️ **Recut-Hinweis (KWP → v2):** KWP wird als `DataConnection type='rest-api'` (API-Key-Connect) abgebildet — **kein `kwpsync.exe`-Windows-Client-Flow** (Scope-Schnitt #12; die alte Drei-Komponenten-Architektur aus der M33a-Spec ist NICHT zu bauen). Connection-Type `windows_client` bleibt im Daten-Modell, hat in v1 aber keinen UI-Flow. v1-Connect-Typen in der UI: **OAuth2** (Gmail, Outlook, AirCall, PandaDoc, Google Calendar) und **API-Key** (KWP, Legacy-Provider). Apps selbst werden erst in ihren Modul-Phasen (P14/P15/P16/P20) angedockt — P5 liefert das Framework + die generische Katalog-/Wizard-UI, gegen die sich alle Connections registrieren.
> ⚙️ **Recut-Hinweis (KWP → v2, aktualisiert 2026-07-12):** KWP wird als `DataConnection type='oauth2'` (Authorization Code + PKCE, Kundenkürzel + dynamische Relay-Auflösung) abgebildet — **kein `kwpsync.exe`-Windows-Client-Flow und kein KWP-API-Key-Setup**. Connection-Type `windows_client` bleibt im Daten-Modell, hat in v1 aber keinen UI-Flow. Generische Connect-Typen in der UI bleiben **OAuth2** und **API-Key**; die KWP-spezifischen Felder kommen in P32.
## Was dieses Modul tut (Kurzfassung)
@@ -23,7 +24,7 @@ Bindet externe Systeme über ein einziges, typsicheres Integrations-Framework an
## Geplante Features (muss abgedeckt sein)
- [ ] DataConnection per OAuth2-Connect-Flow (Gmail, Outlook, AirCall, PandaDoc, Google Calendar) ODER API-Key-Connect (KWP, Legacy-Provider) in der Settings-UI herstellbar
- [ ] DataConnection per OAuth2-Connect-Flow (Gmail, Outlook, AirCall, PandaDoc, Google Calendar, KWP) ODER API-Key-Connect (Legacy-Provider) in der Settings-UI herstellbar
- [ ] Type-safe Adapter-Registry: neue Connection-Typen ohne Kern-Änderung registrierbar (Build-Time-Scan von `app/integrations/`, Drift-Check → Klartext-Warnung im Plattform-Admin)
- [ ] AppSyncRun/AppSyncItem/AppSyncRunLog protokollieren Sync-Läufe mit Klartext-Summary („Sync mit KWP — 14 Aufträge gepullt, 2 fehlgeschlagen …")
- [ ] Connection-Health-Monitoring: Status active/degraded/broken/revoked/pending mit Klartext + Lösungs-Hinweisen; Health-Check-Intervalle; Recovery-Klartext
@@ -32,7 +33,7 @@ Bindet externe Systeme über ein einziges, typsicheres Integrations-Framework an
- [ ] Mehrere DataConnections pro App pro Tenant (z. B. drei Gmail-Mailboxen, mit User-Label)
- [ ] Manueller Re-Sync mit Klartext-Progress; Schema-Drift-Sentinel → degraded + Klartext; Webhook-Storm-/Anomalie-Schutz (Backend, prägt Status-UX)
- [ ] Permissions: integrations.read / .connect / .disconnect / .manual_sync / .view_logs / .admin
- [ ] *(→ v2)* ~~kwpsync.exe-Windows-Client-Setup-Flow~~ — KWP = rest-api-Connection; Community-/Template-Marketplace = Phase 2/3
- [ ] *(→ v2)* ~~kwpsync.exe-Windows-Client-Setup-Flow~~ — KWP = OAuth2/PKCE-Connection; Community-/Template-Marketplace = Phase 2/3
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
@@ -48,5 +49,5 @@ App-Katalog als Karten-Grid gruppiert nach Kategorie, je Karte App-Logo + Beschr
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (R-P5) aktualisiert:
@@ -1,10 +1,11 @@
# Designer-Brief · P6 — CRM-Kern
**Phase:** 6/21 · **Modul:** M01 · **Owner-Dev:** Raffael (R-P6) · **Designer:** David (D-CRM, fällig 24.06. → Noah-Demo #1)
**Quellen:** `ROADMAP.md` §Phase 6 · `ENTITY-MODEL.md` Domäne 5 (Projekt-zentrischer CRM-Kern) · `SCREEN-MAP.md` §2 · `_bmad-output/specs/M01-crm-kern.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A3 Detail, A5 Modal, A6 Settings).
🖥️ **Interim-UI gebaut (AD-28):** lauffähige Screen-Referenz + genutzte Elemente/VM/Actions in `../HiveGrid-Wireframes/Tickets/Interim-Handover/P06-CRM.md`. Layout bleibt frei.
> 🔴 **Pivot-Vorrang (AD-20):** Für den CRM-Kern gilt das **`ENTITY-MODEL.md`**, nicht die teils noch pre-Pivot-SCREEN-MAP. Konkret: **kein Lead-Promotion-Modal** mehr (das gehört zu P7 und ist jetzt Lead→Projekt). `Kontakt` ist Oberbegriff mit **Kontakttyp** (Privatperson/Organisation), **Kontaktstatus** (Kontakt/Kunde/Bestandskunde), **Kontaktart** (Haupt-/Sekundärkontakt = Rolle einer Relation). Zwei Listen-Einstiege: Unternehmen/Organisationen **und** Kontakte.
> 🔴 **Pivot-Vorrang (AD-20):** Für den CRM-Kern gilt das **`ENTITY-MODEL.md`**. Es gibt **kein Lead-Promotion-Modal** mehr (das gehört zu P7 und ist jetzt Lead→Projekt). `Kontakt` ist Oberbegriff mit **Kontakttyp** (Privatperson/Organisation), **Kontaktstatus** (Kontakt/Kunde/Bestandskunde), **Kontaktart** (Haupt-/Sekundärkontakt = Rolle einer Relation). Zwei Listen-Einstiege: Unternehmen/Organisationen **und** Kontakte.
## Was dieses Modul tut (Kurzfassung)
@@ -48,5 +49,5 @@ Daten-Tabelle (sortierbar, paginiert), Filter-Bar (Multi-Select Tags UND/ODER),
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (R-P6) aktualisiert:
@@ -1,10 +1,11 @@
# Designer-Brief · P7 — Lead-Inbox
**Phase:** 7/21 · **Modul:** M02 · **Owner-Dev:** Raffael (R-P7) · **Designer:** David (D-CRM, Lead-Cluster im selben Paket wie P6 → Noah-Demo #1)
**Quellen:** `ROADMAP.md` §Phase 7 (+ Pivot-Note) · `ENTITY-MODEL.md` Domäne 5 (Lead → Projekt) + Kern-Ketten-Diagramm · `SCREEN-MAP.md` §2 (CRM-Cluster) · `REQUIREMENTS.md` (REQ-lead-*) · `_bmad-output/specs/M02-lead-inbox.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A3 Detail, A5 Modal, A6 Settings, KPI-Kit).
🖥️ **Interim-UI gebaut (AD-28):** lauffähige Screen-Referenz + genutzte Elemente/VM/Actions in `../HiveGrid-Wireframes/Tickets/Interim-Handover/P07-Leads.md`. Layout bleibt frei.
> 🔴 **Pivot-Vorrang (AD-20):** Für die Lead-Welt gilt das **`ENTITY-MODEL.md`**, nicht die teils noch pre-Pivot-SCREEN-MAP. Konkret: **Das Lead-Promotion-Modal (4-Optionen-Modal) entfällt** — es wird **Lead → Projekt**. Ein Lead trägt den Datenpunkt **`weiterverarbeitung_freigabe` (ja/nein/unklar)**; bei „ja" entsteht ein `Projekt` (kein Contact-Promotion mehr), und relevante Lead-Daten werden ins Projekt vererbt (`konvertiert_projekt_id`). Der **Kontakt wird separat verknüpft** (`verknuepfter_kontakt_id` — neuer Kontakt oder bestehender), nicht in einem Promotion-Schritt verschmolzen. Status-Enum bleibt `new/qualified/converted/lost/spam`. Wo M02-Spec und SCREEN-MAP §2 noch von „promovieren zu Contact"/„4-Optionen-Modal" sprechen, ist das überholt.
> 🔴 **Pivot-Vorrang (AD-20):** Für die Lead-Welt gilt das **`ENTITY-MODEL.md`**. **Das Lead-Promotion-Modal (4-Optionen-Modal) entfällt** — es wird **Lead → Projekt**. Ein Lead trägt den Datenpunkt **`weiterverarbeitung_freigabe` (ja/nein/unklar)**; bei „ja" entsteht ein `Projekt` (kein Contact-Promotion mehr), und relevante Lead-Daten werden ins Projekt vererbt (`konvertiert_projekt_id`). Der **Kontakt wird separat verknüpft** (`verknuepfter_kontakt_id` — neuer Kontakt oder bestehender), nicht in einem Promotion-Schritt verschmolzen. Status-Enum bleibt `new/qualified/converted/lost/spam`.
## Was dieses Modul tut (Kurzfassung)
@@ -22,7 +23,7 @@ Eingehende Leads aus allen Quellen (Form-Submission, eingehende Email, AirCall-I
| Anti-Spam-Settings [`/admin/lead-anti-spam`] | Hard-Limit pro Quelle/Stunde + pro IP/Stunde · Anomalie-Detection (10x-Spike → Auto-Pause) · Auto-Mark-as-Spam-Heuristiken als Toggles (IP-Blocklist, Disposable-Domain, Honeypot, <3s-Submit) · Quarantäne-Modus vs. Vollständig-Spam-Modus · `lost`-Auto-Lösch-Frist konfigurierbar (0=nie) | A6 |
| Manueller Lead-Eintrag [`/leads/new`] | Vor-/Nachname, Email, Telefon, Message, Quelle (Default manual), Verantwortlicher (Default Self), Tags · Inline-Match-Check beim Tippen | A4 |
*(Lead-Promotion-Modal aus SCREEN-MAP §2 entfällt — ersetzt durch „Lead → Projekt". Kontakt-/Firmen-Listen, Custom-Felder-, Tag-, Duplikat-Admin → P6.)*
*(Lead-Promotion-Modal entfällt — ersetzt durch „Lead → Projekt". Kontakt-/Firmen-Listen, Custom-Felder-, Tag-, Duplikat-Admin → P6.)*
## Geplante Features (muss abgedeckt sein)
@@ -48,5 +49,5 @@ Triage-Daten-Tabelle/Karten-Umschalter (sortierbar, cursor-paginiert 50/Page), F
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (R-P7) aktualisiert:
@@ -1,10 +1,10 @@
# Designer-Brief · P8 — Projekt & Pipelines (Kern + Pipeline-Engine)
**Phase:** 8/21 · **Modul:** M03 · **Owner-Dev:** Raffael (R-P8a/b) · **Designer:** David (D-CRM, Kanban-Paket Fr 26.06.)
**Quellen:** `ROADMAP.md` §Phase 8 (+ Pivot-Note) · `ENTITY-MODEL.md` Domäne 5 (Projekt-Kern + Pipeline/Stage/FieldConfig/Access) + Kern-Ketten-Diagramm + Modellierungs-Fragen 3/4 · `SCREEN-MAP.md` §3 (Kanban, Pipeline-Editor) · `REQUIREMENTS.md` (REQ-sales-*) · `_bmad-output/specs/M03-sales-pipeline.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A3 Detail, A6 Settings, KPI-Kit); Pipeline-Kanban ist **BESPOKE**.
> 🔴 **Pivot-Vorrang (AD-20):** Für Projekt & Pipelines gilt das **`ENTITY-MODEL.md`**, nicht die teils noch pre-Pivot-SCREEN-MAP. Konkret: Es gibt **EINEN `Projekt`-Kern** (typisierte Superset-Tabelle: Deal- + Auftrags-Felder in einer Tabelle) und **konfigurierbare Pipeline-Views**. **„Deal" und „Auftrag" sind Pipeline-Typen (`Pipeline.typ_hint = sales/auftrag/custom`), KEINE eigenen Entitäten.** Es gibt **EINEN konfigurierbaren Pipeline-Kanban** statt getrenntem Sales-Kanban + Projekt-Kanban (SCREEN-MAP §3 zeigt noch „Sales-Kanban [/deals]" — überholt; Route/Wording = projekt-zentrisch). **Kein Won-Handoff** und **kein zweiter Datensatz**: ein Projekt wechselt nur die Pipeline. **`Status` ist immer pipeline-intern** (`PipelineStage.stage_kind = offen/gewonnen/verloren`); es gibt keinen globalen Projektstatus. Neu gegenüber alter Spec: der **Pipeline-Feld-Config-Layer** (`PipelineFieldConfig`: Sichtbarkeit + Pflicht je Feld pro Pipeline+Status) und **`PipelineAccess`** (wer darf Pipeline sehen/bearbeiten) — Field-Level-Sichtbarkeit (z.B. Volumen nur für Vertrieb) läuft jetzt darüber statt nur über harte `deals.read_volume_*`-Bundles. Wo M03-Spec von „Deal"/„won_handoff_project_id" spricht, ist der `Projekt`-Kern bzw. ein Pipeline-Wechsel gemeint.
> 🔴 **Pivot-Vorrang (AD-20):** Für Projekt & Pipelines gilt das **`ENTITY-MODEL.md`**. Es gibt **EINEN `Projekt`-Kern** (typisierte Superset-Tabelle: Deal- + Auftrags-Felder in einer Tabelle) und **konfigurierbare Pipeline-Views**. **„Deal" und „Auftrag" sind Pipeline-Typen (`Pipeline.typ_hint = sales/auftrag/custom`), KEINE eigenen Entitäten.** Es gibt **EINEN konfigurierbaren Pipeline-Kanban** mit projekt-zentrischen Routen. **Kein Won-Handoff** und **kein zweiter Datensatz**: ein Projekt wechselt nur die Pipeline. **`Status` ist immer pipeline-intern** (`PipelineStage.stage_kind = offen/gewonnen/verloren`); es gibt keinen globalen Projektstatus. Der **Pipeline-Feld-Config-Layer** steuert Sichtbarkeit und Pflicht je Feld pro Pipeline+Status; `PipelineAccess` steuert den Zugriff.
## Was dieses Modul tut (Kurzfassung)
@@ -21,7 +21,7 @@ Baut den `Projekt`-Kern als eine typisierte Tabelle (Superset der Felder, dazu `
| Lost-Reasons [`/admin/pipelines/lost-reasons`] | Liste: Name, Anzahl verknüpfter Projekte, Status · Add/Edit/Archive (kein Hard-Delete — Reporting) · SHK-Default 5 Reasons geseedet | A2 |
| Forecast/KPI-Quellen (Dashboard-Widgets in P11) | Datenquellen/Berechnungen: Pipeline-Forecast (Volumen × Win-%), realisierter Umsatz, KPIs pro Verantwortlichem, Stage-Conversion-Rates, Lost-Reason-Verteilung · Aggregat-Cache | (kein eigener Screen — Widgets in P11) |
*(Sales-Kanban [`/deals`] + Projekt-Kanban [`/projects`] aus SCREEN-MAP §3/§4 sind EIN Board. „Deal-Liste/Deal-Detail/Pipeline-Editor [/admin/sales/...]" → projekt-zentrische Routen oben. Plantafel + Rechnungen/Checklisten/Abnahme-Sub-Areas → P9.)*
*(Es gibt EIN Board mit projekt-zentrischen Routen. Plantafel + Rechnungen/Checklisten/Abnahme-Sub-Areas → P9.)*
## Geplante Features (muss abgedeckt sein)
@@ -47,5 +47,5 @@ Kanban-Board (Spalten = Stages, horizontal scrollbar/responsive), Drag&Drop-Kart
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (R-P8a/b) aktualisiert:
@@ -1,10 +1,10 @@
# Designer-Brief · P9 — Projekt & Pipelines (Auftrags-Features + Sub-Areas)
**Phase:** 9/21 · **Modul:** M04 · **Owner-Dev:** Raffael (R-P9a/b) · **Designer:** David (D-CRM, Plantafel-Paket Mi 01.07.)
**Quellen:** `ROADMAP.md` §Phase 9 (+ Pivot-Note) · `ENTITY-MODEL.md` Domäne 5 (Sub-Areas am Projekt: Rechnung/Termin/Checkliste/AbnahmeProtokoll/AbnahmeSignatur/ProjektMitglied/ProjektExternesFeld) + Kern-Ketten-Diagramm · `SCREEN-MAP.md` §4 (Plantafel + Abnahme-Workflow + Projekt-Detail-Sub-Areas) · `REQUIREMENTS.md` (REQ-projekt-*) · `_bmad-output/specs/M04-auftragspipeline.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Plantafel + Abnahme-Workflow sind **BESPOKE** (📱 mobile-first + offline); Sub-Area-Tabs aus A3.
> 🔴 **Pivot-Vorrang (AD-20):** Für die Auftrags-Welt gilt das **`ENTITY-MODEL.md`**, nicht die teils noch pre-Pivot-SCREEN-MAP. Konkret: **Kein separates Project-Objekt** — die Auftrags-Welt ist eine **Pipeline-View auf denselben `Projekt`-Kern** (P8). Es gibt **keinen Won-Handoff** und keinen zweiten Datensatz; ein Projekt wechselt nur die Pipeline / erhält Auftrags-Felder (deshalb auch keine read-only „Sales-Verlauf-Sektion" als Snapshot eines anderen Objekts — die Historie steckt im selben Projekt-Activity-Stream). **Rechnung ist ein NEUES Sub-Entity (v1)** am Projekt. **Abnahme = Checklisten/Protokoll-Sub-Area** am Projekt: `AbnahmeProtokoll` ist **immutable** (6 Jahre, signatur-gebunden), bindet eine **Mängel-Checkliste** (`Checkliste typ=maengel`) ein, hat **Touch-Signaturen** (Kunde + Monteur) und ist **offline-fähig**. **Material-Ausgang/Lagerist-Sicht, Zeiterfassung, Leistungspositionen, Baustelle, Supporttickets → v2** (Material-Listen am Auftrag bleiben v1). Wo M04-Spec von „AcceptanceProtocol / ProjectPipeline / source_deal_id-Snapshot" spricht, ist die Sub-Area am gemeinsamen `Projekt`-Kern gemeint.
> 🔴 **Pivot-Vorrang (AD-20):** Für die Auftrags-Welt gilt das **`ENTITY-MODEL.md`**. **Kein separates Project-Objekt** — die Auftrags-Welt ist eine **Pipeline-View auf denselben `Projekt`-Kern** (P8). Es gibt **keinen Won-Handoff** und keinen zweiten Datensatz; ein Projekt wechselt nur die Pipeline / erhält Auftrags-Felder. **Rechnung ist ein Sub-Entity (v1)** am Projekt. **Abnahme = Checklisten/Protokoll-Sub-Area** am Projekt: `AbnahmeProtokoll` ist **immutable** (6 Jahre, signatur-gebunden), bindet eine **Mängel-Checkliste** (`Checkliste typ=maengel`) ein, hat **Touch-Signaturen** (Kunde + Monteur) und ist **offline-fähig**. **Material-Ausgang/Lagerist-Sicht, Zeiterfassung, Leistungspositionen, Baustelle, Supporttickets → v2** (Material-Listen am Auftrag bleiben v1).
## Was dieses Modul tut (Kurzfassung)
@@ -49,5 +49,5 @@ Plantafel-Raster (Y=MA, X=Zeit, Zeitraum-Switcher Tag/Woche/Monat), Drag&Drop-/R
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (R-P9a/b) aktualisiert:
@@ -1,31 +1,36 @@
# Designer-Brief · P11 — Globale Suche & Dashboard
**Phase:** 11/21 · **Module:** M24 (Globale Suche) + M20 (Dashboard) · **Owner-Dev:** Raffael (R-P11a/b) · **Designer:** David (Paket Fr 03.07.)
**Quellen:** `ROADMAP.md` §Phase 11 · `ENTITY-MODEL.md` Domäne 6 (Suche & Dashboard) · `SCREEN-MAP.md` §5 (Dashboard + Cmd+K) · `REQUIREMENTS.md` (REQ-suche-*, REQ-dashboard-*) · `_bmad-output/specs/M24-globale-suche.md`, `_bmad-output/specs/M20-dashboard.md`
**Subframe:** Pflicht je Route. Cmd+K-Such-Modal ist **BESPOKE** (klein); Dashboard = KPI+Widget-Compose; Vollbild-Suche aus A2.
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Screen. Spotlight-Suche ist **BESPOKE** (klein); Dashboard = KPI+Widget-Compose.
> 🟢 **Kein Pivot-Sonderfall** (P11 ist nicht Teil der projekt-zentrischen Kern-Kette). Aber: Such-Index + Dashboard-Widgets greifen auf den **`Projekt`-Kern** zu (nicht mehr getrennte Deal-/Project-Entitäten). In M24-Spec stehen Entity-Typen `deal | project | order` — im Pivot-Modell ist das **EIN `Projekt`-Entity-Typ** (Pipeline-Typ = View, kein separater Index-Typ je Pipeline). In M20-Spec sind 7 Rollen-Default-Dashboards beschrieben — **v1 liefert nur 3 feste Rollen-Layouts (GF/Büro/Monteur)** ohne Drag&Drop (Scope-Schnitt 12.06.; User-Layout-Persistenz + Custom-Widgets + Export → v2). Die Widget-Registry bleibt voll gebaut (Inversion M064→M147). pgvector/Hybrid-Suche ist v2 — **v1 = Meilisearch-Keyword-Suche** (AD-5 sequenziert); die embedding-Spalte/EmbeddingProviderJob sind nur Andock-Halter.
> **Scope-Schnitt 2026-07-12 (verbindlich):** Keine nutzerseitige `/search`-Vollseite in v1.
> Globale Suche ist eine Spotlight-Oberfläche: Desktop-Modal per `Cmd+K`/`Ctrl+K` oder
> Header-Suchsymbol, Mobile als viewportfüllendes Overlay über das Header-Suchsymbol.
> `/search/api` bleibt ausschließlich geschützter Resource-Endpunkt. R-P11a nutzt bis zum finalen
> `D-DASH`-Delta eine AD-28-Interim-UI; `D-DASH` bleibt als `design-nachzug` offen. R-P11b ist nicht betroffen.
> 🟢 **Kein Pivot-Sonderfall** (P11 ist nicht Teil der projekt-zentrischen Kern-Kette). Aber: Such-Index + Dashboard-Widgets greifen auf den **`Projekt`-Kern** zu (nicht mehr getrennte Deal-/Project-Entitäten). Frühere M24-Typen `deal | project | order` sind im Pivot-Modell **EIN `Projekt`-Entity-Typ** (Pipeline-Typ = View). In M20 sind 7 Rollen-Default-Dashboards beschrieben — **v1 liefert nur 3 feste Rollen-Layouts (GF/Büro/Monteur)** ohne Drag&Drop (Scope-Schnitt 12.06.; User-Layout-Persistenz + Custom-Widgets + Export → v2). Die Widget-Registry bleibt voll gebaut (Inversion M064→M147). Nach AD-26 bleibt die Suche in v1/v2 **Meilisearch-Keyword-only**; pgvector, Embeddings und ein eigener KI-/RAG-Layer entfallen.
## Was dieses Modul tut (Kurzfassung)
**Suche (M24):** Eine permission-aware Keyword-Suche über alle Entitäten via Meilisearch (SearchAdapter pro Modul, Outbox-Index-Updates), bedienbar per **Cmd+K-Modal** (global, debounced, RecentSearches) und als **Vollbild-Such-View** mit Filtern. **Dashboard (M20):** 3 feste Rollen-Dashboards (GF/Büro/Monteur, SHK-Default geseedet) aus einem Widget-Katalog (Sales/Projekte/Tasks/HR/KI/Activity/Comms), live aktualisiert (SSE/WebSocket, Aggregat-Cache); Edit = nur Widget-Filter/Zeitraum (kein Drag&Drop-Grid in v1).
**Suche (M24):** Eine permission-aware Keyword-Suche über alle Entitäten via Meilisearch (SearchAdapter pro Modul, Outbox-Index-Updates), bedienbar als globale **Spotlight-Suche** mit Debounce und RecentSearches (Desktop-Modal, mobiles viewportfüllendes Overlay). **Dashboard (M20):** 3 feste Rollen-Dashboards (GF/Büro/Monteur, SHK-Default geseedet) aus einem Widget-Katalog (Sales/Projekte/Tasks/HR/KI/Activity/Comms), live aktualisiert (SSE/WebSocket, Aggregat-Cache); Edit = nur Widget-Filter/Zeitraum (kein Drag&Drop-Grid in v1).
## Benötigte Screens
| Screen [Route] | Kern-Inhalt | Archetyp |
|---|---|---|
| **Cmd+K-Such-Modal** [global] | Auto-fokussiertes Such-Eingabefeld, Live-Suche (300ms debounce) · Trefferliste **gruppiert nach Entity-Typ** mit Icon, Titel, Subtitle, **Match-Highlight-Snippet**, letzte-Aktivität (relativ) · Filter-Chips für Entity-Typ (Multi-Select: Kontakte/Projekte/Files/Tasks/Leads …) · Tastatur-Navigation (↑↓ + Enter öffnen, Cmd+Enter neuer Tab, Esc schließen) + Shortcut-Anzeige · Leer-Zustand: **RecentSearches** + Tipps · „Alle {n} Treffer zeigen" → Vollbild-Suche · Loading-Indikator | **BESPOKE** (klein) |
| Vollbild-Such-View [`/search`] | Such-Feld (aus URL-Param), volle Trefferliste (cursor-paginiert 50/Page) mit erweiterten Metadaten (Erstellt, Verantwortlicher, Tags) · **Filter-Sidebar** (Entity-Typ, Erstellt-Range, Verantwortlicher, Tags, modul-spezifische Filter z.B. Pipeline-Status, Toggle „Archivierte einbeziehen") · Trefferanzahl-Klartext („1.247 Treffer in 0,3 s") · Sortierung (Relevanz/Letzte Aktivität/Erstellt) · Klick → Ziel-Route | A2 |
| **Spotlight-Suche** [global, keine nutzerseitige Route] | Desktop als Modal, Mobile als viewportfüllendes Overlay · Auto-fokussiertes Such-Eingabefeld, Live-Suche (300ms debounce) · Trefferliste **gruppiert nach Entity-Typ** mit Icon, Titel, Subtitle, **Match-Highlight-Snippet**, letzte Aktivität (relativ) · Filter-Chips für Entity-Typ (Multi-Select: Kontakte/Projekte/Files/Tasks/Leads …) · Tastatur-Navigation (↑↓ + Enter öffnen, Cmd/Ctrl+Enter neuer Tab, Esc schließen) + Shortcut-Anzeige · Leer-Zustand: **RecentSearches** + Tipps · Loading-, Keine-Treffer- und Fehlerzustand · Klick/Enter öffnet direkt die Ziel-Route | **BESPOKE** (klein) |
| **Dashboard** [`/dashboard` bzw. `/`] | **3 feste Rollen-Layouts (kein Drag&Drop v1):** **GF** (Begrüßung, Sales-KPIs, Umsatz-Forecast einfach, Projekt-KPIs, Auslastung, offene Mängel, Team-heute) · **Büro** (Begrüßung, Projekt-KPIs, meine Tasks, Anrufe heute, HR-Anträge) · **Monteur 📱** (meine Termine heute, meine Projekte, meine Tasks) · Widgets: KPI-Kachel, Liste, Trend-Chart · Live-Update (SSE/WebSocket) mit Subtle-Animation + „Live-Updates pausieren" · Edit = **nur Widget-Filter/Zeitraum** konfigurieren · „Daten zuletzt aktualisiert vor X Min" bei veralteten Aggregaten | KPI + Widget-Compose |
| Dashboard-Switcher [im Dashboard-Header] | Verfügbare Dashboards (rollen-gematcht) auswählbar · Default-Routing nach Rolle | (Teil des Dashboard) |
*(SCREEN-MAP §5 nennt Flow-Editor/Booking/Kalender/Signatur im selben Paket — die gehören zu P12/P16, nicht in diesen Brief. Custom-Widgets/Export + Drag&Drop-Grid = v2.)*
*(Flow-Editor/Booking/Kalender/Signatur gehören zu P12/P16, nicht in diesen Brief. Custom-Widgets/Export + Drag&Drop-Grid = v2.)*
## Geplante Features (muss abgedeckt sein)
- [ ] **Meilisearch-Keyword-Suche** permission-aware über SearchAdapter (Modul-Registrierung: Kontakt/Firma/Lead/Projekt/File/Task/User); pgvector/Hybrid → v2
- [ ] **Meilisearch-Keyword-Suche** permission-aware über SearchAdapter (Modul-Registrierung: Kontakt/Firma/Lead/Projekt/File/Task/User); kein pgvector/Embedding nach AD-26
- [ ] Entity-Mutationen aktualisieren den Index über **Outbox-Pattern**; SearchIndexEntry + RecentSearch befüllt (5–10 s Index-Latenz mit Klartext-Hinweis)
- [ ] **Cmd+K-Modal** (global Hotkey, debounced, gruppierte Treffer, Match-Highlight, Tastatur-Navigation, RecentSearches) + Wechsel in Vollbild-Such-View mit Filtern
- [ ] **Spotlight-Suche** (Desktop per Cmd+K/Ctrl+K oder Header-Suchsymbol als Modal, Mobile per Header-Suchsymbol viewportfüllend; debounced, gruppierte Treffer, Match-Highlight, Tastatur-Navigation, RecentSearches)
- [ ] **Server-side Permission-Filter** in der Suche (nie durchsickern; Trefferanzahl = erlaubte Treffer; Klartext „weitere Treffer, die du nicht siehst")
- [ ] **3 feste Rollen-Dashboards** (GF/Büro/Monteur, SHK-Default geseedet) aus Widget-Katalog (Sales/Projekte/Tasks/HR/Activity/Comms/KI); Widget-Registry voll gebaut
- [ ] Dashboard-Widgets **live** (SSE/WebSocket) mit Aggregat-Cache + Lazy-Load/Skeleton; Widgets permission-gegated (Quellen-Modul-Permission), Monteur-Dashboard mobile-first
@@ -33,7 +38,7 @@
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
Such-Eingabefeld mit Auto-Fokus + Debounce, Trefferliste gruppiert nach Entity-Typ mit Typ-Icon, Match-Highlight-Snippet, Relativ-Zeit, Entity-Typ-Filter-Chips (Multi-Select), Tastatur-Navigations-Highlight + Shortcut-Leiste, RecentSearches-Liste (mit Einzel-/Alle-Löschen), „Alle Treffer zeigen"-Link, Filter-Sidebar (Entity-Typ/Date-Range/Verantwortlicher/Tags/modul-spezifisch + Archiviert-Toggle), Sortier-Auswahl, Trefferanzahl-Klartext, Pagination, KPI-Kachel (Wert/Label/Trend-Pfeil/Vergleich), Listen-Widget, Trend-Chart (Linie/Balken/Donut), Begrüßungs-Widget, Dashboard-Switcher, Widget-Filter-/Zeitraum-Konfig (kein Grid-Editor v1), „Live-Updates pausieren"-Toggle, „zuletzt aktualisiert"-Hinweis, Skeleton-Loading, Empty-/Keine-Treffer-/Fehler-/Permission-Denied-States + Embedding-Provider-Down-Banner (Klartext, alle aus M24 Block I / M20 Klartext-Hinweisen).
Such-Eingabefeld mit Auto-Fokus + Debounce, Desktop-Modal und mobiles viewportfüllendes Overlay, Trefferliste gruppiert nach Entity-Typ mit Typ-Icon, Match-Highlight-Snippet, Relativ-Zeit, Entity-Typ-Filter-Chips (Multi-Select), Tastatur-Navigations-Highlight + Shortcut-Leiste, private RecentSearches-Liste, Loading-, Empty-/Keine-Treffer-/Fehler-/Permission-Denied-States (alle aus M24 Block I / M20 Klartext-Hinweisen), KPI-Kachel (Wert/Label/Trend-Pfeil/Vergleich), Listen-Widget, Trend-Chart (Linie/Balken/Donut), Begrüßungs-Widget, Dashboard-Switcher, Widget-Filter-/Zeitraum-Konfig (kein Grid-Editor v1), „Live-Updates pausieren"-Toggle, „zuletzt aktualisiert"-Hinweis, Skeleton-Loading. Manuelle RecentSearch-Löschung bleibt bis zu einem eigenen Ticket/CR außerhalb von R-P11a.
## Davids Delta (David füllt aus)
@@ -45,5 +50,5 @@ Such-Eingabefeld mit Auto-Fokus + Debounce, Trefferliste gruppiert nach Entity-T
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (R-P11a/b) aktualisiert:
@@ -1,15 +1,18 @@
# Designer-Brief · P12 — Automation-Engine
**Phase:** 12/21 · **Modul:** M17 · **Owner-Dev:** Raffael (R-P12a/b) · **Designer:** David (D-Automation, Paket Fr 03.07.)
**Quellen:** `ROADMAP.md` §Phase 12 · `ENTITY-MODEL.md` Domäne 7 (Automation & KI) · `SCREEN-MAP.md` §5 (Flow-Editor) · `_bmad-output/specs/M17-automation-engine.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A3 Detail, A5 Modal, A6 Settings) — Flow-Editor selbst ist **Bespoke**.
> 🔴 **Schwerste UI der App (AD-16, ab 22.06. täglich 1h).** Der visuelle Flow-/Node-Editor ist die erste USP-Säule und vollständig bespoke. Klartext-First gilt überall: Knoten-Labels, Dry-Run-Ausgaben, Loop-/Rate-Warnungen und Execution-Logs sind in **verständlichem Deutsch**, nicht technisch.
> 🟡 **v1-Grenze:** KWP-Push-Action ist nur als erweiterbarer Registry-Eintrag vorgesehen (zieht mit v2-P10/P32 nach) — kein KWP-spezifisches Konfig-UI in v1. Sprach-zu-Automation rendert hier den Flow-Vorschlag; die KI-Pipeline selbst liegt in P13.
> 🟡 **v1-/AD-32-Grenze:** KWP-Push ist nur ein nicht ausführbarer Extension-Slot. Eine ausführbare Action und
> KWP-spezifisches Konfig-UI dürfen erst nach `VEXT-6` plus erneuter ausdrücklicher Produktfreigabe folgen;
> der initiale Phase-32-Scope bleibt read-only. Sprach-zu-Automation rendert hier den Flow-Vorschlag; die
> KI-Pipeline selbst liegt in P13.
## Was dieses Modul tut (Kurzfassung)
Ein visueller Graph-Editor, in dem Nutzer modulübergreifende Automationen aus einer **vollständigen Trigger-Library** (CRM, Lead, Sales, Projekte, Email, Forms, Booking, Kalender, Zeit, Webhooks) und **Action-Library** (CRM, Notifications, HTTP, Tasks, If/Else, Delay, Loop; KWP-Push registriert-erweiterbar) bauen. Jeder Flow ist als JSON-Graph persistiert, per natürlicher Sprache (DE) erstellbar, vor Aktivierung als **Dry-Run** testbar und innerhalb **24h zurückrollbar**. Schutz-Mechanismen (Loop-Guard, Rate-Limit, Idempotenz, Resume) verhindern Runaway-Automationen.
Ein visueller Graph-Editor, in dem Nutzer modulübergreifende Automationen aus einer **vollständigen Trigger-Library** (CRM, Lead, Sales, Projekte, Email, Forms, Booking, Kalender, Zeit, Webhooks) und **Action-Library** (CRM, Notifications, HTTP, Tasks, If/Else, Delay, Loop; KWP nur als nicht ausführbarer Extension-Slot) bauen. Jeder Flow ist als JSON-Graph persistiert, per natürlicher Sprache (DE) erstellbar, vor Aktivierung als **Dry-Run** testbar und innerhalb **24h zurückrollbar**. Schutz-Mechanismen (Loop-Guard, Rate-Limit, Idempotenz, Resume) verhindern Runaway-Automationen.
## Benötigte Screens
@@ -24,12 +27,12 @@ Ein visueller Graph-Editor, in dem Nutzer modulübergreifende Automationen aus e
| Template-Katalog [`/automations/templates`] | SHK-Vorlagen + Tenant-Vorlagen nach Kategorie · je Template Beschreibung + Use-Case + Nutzungs-Anzahl · „Verwenden"-Button · „Eigenes Template aus Rule anlegen" | A2 |
| Loop-/Rate-Schutz-Warnmodal | Schleifen-Erkennung mit **Abhängigkeits-Graph-Visualisierung** + „Beheben" · Anomalie-Pause-Hinweis (Klartext: „2.000-mal in 5 Min, typisch 5-10/Tag — pausiert") | A5 + Mini-Graph |
*(Trigger-/Action-Library selbst sind Daten im Knoten-Katalog, kein eigener Screen. KWP-Push-Konfig → v2.)*
*(Trigger-/Action-Library selbst sind Daten im Knoten-Katalog, kein eigener Screen. KWP-Push-Konfig nur nach `VEXT-6` + erneuter Produktfreigabe.)*
## Geplante Features (muss abgedeckt sein)
- [ ] Vollständige Trigger-Library über alle Module (CRM, Lead, Sales, Projekte, Email, Forms, Booking, Kalender, Zeit, Webhook) im Knoten-Katalog gruppiert
- [ ] Vollständige Action-Library (CRM, Notification, HTTP, Task, If/Else, Delay, Loop) + erweiterbare Registry (KWP-Push dockt v2 an)
- [ ] Vollständige Action-Library (CRM, Notification, HTTP, Task, If/Else, Delay, Loop) + erweiterbare Registry; KWP-Push bleibt bis `VEXT-6` + erneuter Produktfreigabe ohne Adapter/Handler nicht ausführbar
- [ ] Graph-Editor: Knoten hinzufügen/konfigurieren/löschen/duplizieren, Kanten erstellen/löschen, verschieben, Auto-Layout, Undo/Redo, Mini-Map
- [ ] Klartext-Knoten-Labels + Klartext-Validation-Hinweise (unverbunden, Cycle, unvollständig)
- [ ] Sprach-zu-Automation: Satz → Flow-Vorschlag mit Rückfragen, Existenz-Prüfung, Risiko-Hinweisen, Bestätigungs-Pflicht (Action-Boundary, nie Auto-Aktivierung)
@@ -54,5 +57,5 @@ Graph-Canvas (Knoten + Kanten, Pan/Zoom), Knoten-Katalog-Panel (gruppiert/filter
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (R-P12a/b) aktualisiert:
@@ -1,7 +1,7 @@
# Designer-Brief · P14 — Email & Marketing
**Phase:** 14/21 · **Module:** M09 (Email-Brücke) / M10 (Marketing) · **Owner-Dev:** Akeshan (AK-P14a/b) · **Designer:** David (D-Marketing, Kampagnen-Editor Paket Fr 26.06., Sende-Domain Paket Mo 06.07.)
**Quellen:** `ROADMAP.md` §Phase 14 · `ENTITY-MODEL.md` Domäne 8 (Kommunikation) · `SCREEN-MAP.md` §3 (Kampagnen-Editor) + §6 (Sende-Domain) · `_bmad-output/specs/M09-email-inbox.md` (nur Sende-Domain/Inbound/BCC) · `_bmad-output/specs/M10-email-marketing.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A3 Detail, A6 Settings, A4 Public). Kampagnen-Editor + Unsubscribe-Page sind **Bespoke**.
> 🟡 **v1-Grenze (Scope-Schnitt 11.06.):** **Postfach-Sync ist v2** (→ P23) — kein OAuth-Mailbox-Connect, keine Inbox-View, keine Compose-Oberfläche, kein Thread-View in v1. Aus M09 bleiben in v1 nur: **Sende-Domain-Verifikation** (DKIM/SPF/DMARC), **Tenant-Inbound-Adresse** (Lead-Eingang) und die **BCC-Logging-Brücke**. Mails (Automation/Marketing/transaktional) erscheinen im Activity-Stream am Kontakt (P6).
@@ -53,5 +53,5 @@ DNS-Record-Karten mit Copy-Button, Status-Ampel (Connection-Card-Stil), Toggle-Z
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (AK-P14a/b) aktualisiert:
@@ -1,7 +1,7 @@
# Designer-Brief · P15 — Telefonie & Team-Chat
**Phase:** 15/21 · **Module:** M12 (Telefonie) / M13 (Team-Chat) · **Owner-Dev:** Akeshan (AK-P15a/b) · **Designer:** David (D-Chat Paket Mi 01.07., D-Telefonie Paket Mo 06.07.)
**Quellen:** `ROADMAP.md` §Phase 15 · `ENTITY-MODEL.md` Domäne 8 (Kommunikation) · `SCREEN-MAP.md` §4 (Chat-UI) + §6 (AirCall-Setup/Anrufe) · `_bmad-output/specs/M12-telefonie.md` · `_bmad-output/specs/M13-team-chat.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A3 Detail, A5 Modal, A6 Connection). Chat-UI ist **Bespoke**.
> 🟡 **v1-Grenze (Scope-Schnitt 11.06.):** **HalloPetra (M105) ist v2** (→ P33) — v1 baut nur den **AirCall-Adapter** hinter dem `TelephonyProviderInterface` (Referenz-Implementierung). Whisper-Notiz-Diktat ist v2 (Notiz-Editor = Markdown-Tippen in v1).
@@ -61,5 +61,5 @@ Channel-Listen-Einträge (Snippet, Unread-Badge, Mention-Marker, Pin-/Mute-/Typ-
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (AK-P15a/b) aktualisiert:
@@ -1,7 +1,7 @@
# Designer-Brief · P16 — Kalender, Booking, Forms & Signatur
**Phase:** 16/21 · **Module:** M25 / M06 / M05 / M07 · **Owner-Dev:** Akeshan (AK-P16a–d) · **Designer:** David
**Quellen:** `ROADMAP.md` §Phase 16 · `ENTITY-MODEL.md` Domäne 9 (Kalender/Booking/Forms/Signatur) · `SCREEN-MAP.md` §3 (Form-Builder) + §5 (Booking/Kalender/Signatur) + §6 (Signatur) · `_bmad-output/specs/M25-calendar-sync.md`, `M06-booking.md`, `M05-form-builder.md`, `M07-angebot-signatur.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A3 Detail, A4 Form/Input, A5 Modal/Wizard, A6 Settings/Connection, A7 Zustände); zusätzlich BESPOKE für Form-Builder-Canvas, Booking-Page (öffentlich), Kalender.
> 🟡 **Vier Module, vier Screen-Gruppen — bewusst gebündelt:** Termin- und Dokument-Workflows. Bitte je Gruppe (1) Kalender-Sync, (2) Booking, (3) Form-Builder, (4) Angebots-Signatur getrennt halten. **v1-Schnitte (verbindlich):** Kalender-Sync nur **Google** (Outlook-Adapter → v2, Interface bleibt provider-agnostisch); Booking nur **eine** Zuteilungs-Strategie „Erster der frei ist" (Round-Robin/Provider-Wahl → v2); Form-Sharing = **URL + QR + iFrame** (personalisierte Links / JS-Snippet → v2); Signatur über **gehärteten SES-Eigenbau als Default** (Fern-Link/OTP + Touch vor Ort + PAdES + Completion-Certificate), **PandaDoc nur optionaler BYOK-Adapter**. Pivot-Hinweis: Signatur hängt am **`Projekt`**-Kern (nicht „Deal") — `ProjektSignatureDocument`/`ProjektSignatureSigner`; der Signatur-Einstieg lebt im Projekt-Detail (P8/P9). Die Task-Komponente aus P4 wird hier eingebettet, nicht neu gebaut.
@@ -57,5 +57,5 @@ Kalender-Grid (Monat/Woche, Quell-farbige Termine), Connection-Card mit Status-A
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (AK-P16a–d) aktualisiert:
@@ -1,8 +1,9 @@
# Designer-Brief · P17 — HR-Hub
**Phase:** 17/21 · **Modul:** M14 · **Owner-Dev:** Akeshan (AK-P17a/b) · **Designer:** David
**Quellen:** `ROADMAP.md` §Phase 17 · `ENTITY-MODEL.md` Domäne 10 (HR-Hub) · `SCREEN-MAP.md` §3 (HR-Compose-Block) · `_bmad-output/specs/M14-hr-hub.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A3 Detail, A4 Form/Input, A5 Modal, A6 Settings, A7 Zustände); Reuse: M05-Form-Renderer (Urlaub/Krank/Requests), KPI-Kacheln + Charts.
🖥️ **Interim-UI gebaut (AD-28):** lauffähige Screen-Referenz + genutzte Elemente/VM/Actions in `../HiveGrid-Wireframes/Tickets/Interim-Handover/P17-HR.md`. Layout bleibt frei.
> 🟡 **Sehr breites Modul, sensible Daten — strenge Permission-Gates.** Quiply-Komplett-Ablösung. Trennung beachten: **MA-Sicht** (eigener Bereich, eigene Daten) vs. **HR-Admin-Sicht** (`/admin/hr/...`, alle MA). Sensible Tabellen (Lohnabrechnung, Krank-AU, Passwort-Safe, Personaldokumente) haben **zusätzlich** zum RLS einen App-Permission-Layer — Werte werden nie automatisch angezeigt (Reveal + Audit-Log). Urlaub/Krank/Requests laufen über **M05-Form-Templates** — den Form-Renderer aus P16 hier wiederverwenden, nicht neu bauen. Surveys bleiben v1; Memberspot/Boobora-Onboarding-Drittanbieter → v2.
@@ -57,5 +58,5 @@ KPI-Kacheln (heute krank / im Urlaub / pendente Genehmigungen / offene AU), Card
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (AK-P17a/b) aktualisiert:
@@ -1,7 +1,7 @@
# Designer-Brief · P19 — Plattform-Admin
**Phase:** 19/21 · **Modul:** M37 (+ M32 Feature-Flag-UI) · **Owner-Dev:** Akeshan (AK-P19) · **Designer:** David
**Quellen:** `ROADMAP.md` §Phase 19 · `ENTITY-MODEL.md` Domäne 11 (Plattform-Admin) + Domäne 12 (Abo-Baukasten, für Abo-Zusammenstellung) · `SCREEN-MAP.md` §3 (Plattform-Admin-Block) · `_bmad-output/specs/M37-plattform-admin.md`, `M32-feature-flags.md` (Admin-UI-Teile)
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. **Eigene Admin-Shell** (nicht App-Shell A1) — getrennte Sidebar/Topbar auf `admin.hivegrid.de`; interner Polish reicht (kein 🌐-Niveau). Archetypen-Reuse: A2 Liste, A3 Detail, A4 Form, A5 Modal, A6 Settings, KPI/Charts.
> 🟡 **Getrennte Welt — eigene Shell, kein App-Reuse der Sidebar.** Läuft auf `admin.hivegrid.de` mit Host-Routing, **Cookie-Domain-Trennung** zu app.hivegrid.de, TOTP-Pflicht + MFA-Step-up. **v1-Schnitt (verbindlich):** Die **getrennte AdminUser-Identität / AdminRBAC-Parallelwelt** (M038/M039) ist **v2** — v1 nutzt das Boilerplate-User-Modell als Extension + `admin-mfa-gate`. Es gibt **keine** AdminUser-/AdminRole-Verwaltungs-Screens in v1, **keine** Plattform-Lead-Pipeline/Deal-Kanban (unser eigenes Sales-Tool → v2), **keine** Feature-Flag-Massen-Statistik (→ v2). Admin-Dashboard zeigt Basis-KPIs (Tenants/User/MRR), Churn/ARPU → v2. **Neu v1:** Admin stellt Tenant-Abos zusammen (Feature-Konnektoren togglen + Legacy-Provider-Positionen — **Abo-Baukasten-Mechanik**; Self-Service-UI dafür → v2). KWP-Sync-Status-Screen entfällt v1 (KWP ist erstes v2-Modul).
@@ -53,5 +53,5 @@ Eigene Admin-Sidebar + -Topbar (getrennt von A1), KPI-Kacheln mit Drill-Down + Z
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (AK-P19) aktualisiert:
@@ -1,46 +1,58 @@
# Designer-Brief · P20 — Billing, Onboarding & Branding
**Phase:** 20/21 · **Module:** M28 / M29 / M31 · **Owner-Dev:** Akeshan (AK-P20) · **Designer:** David
**Quellen:** `ROADMAP.md` §Phase 20 · `ENTITY-MODEL.md` Domäne 12 (Billing/Abo-Baukasten) + Domäne 13 (Onboarding, Branding) · `SCREEN-MAP.md` §6 (Billing/Onboarding-Compose) · `_bmad-output/specs/M28-subscriptions-billing.md` (⚠ M154-Recut), `M29-onboarding.md` (Wizard-UI → v2), `M31-branding.md` · Legacy-Referenz: `archive/hivegrid-cloud/app/config/pricing-plans.ts`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A6 Settings, KPI/Charts, A5 Modal).
> 🟡 **Drei kleine v1-Module gebündelt — wichtige Schnitte (verbindlich):**
> - **Billing = Abo-Baukasten (M154-Recut):** Basis-Preis pro Nutzer + Feature-Module als daten-getriebene Positionen. **KEINE Seat-Typen** (kein „Büro vs. Monteur"-Seat-Modell). In-App **keine** Pricing-/Upgrade-/Plan-Wechsel-UI (Apple-Compliance LP-8) — nur Read-Only-Übersicht + Verweis nach `hivegrid.de`/Account-Manager. Verbrauchs-Zähler + Drossel aktiv, Aufschlags-Abrechnung → v2.
> - **Billing = Lago/Mollie/HiveGrid-Recut (AD-27):** Plans + Seats und Feature-Entitlements liegen lokal in HiveGrid; Lago liefert Billing-/Invoice-State, Mollie nur Payment-State. In-App **keine** Pricing-/Upgrade-/Plan-Wechsel-UI — nur Read-Only-Übersicht + Verweis nach `hivegrid.de`/Account-Manager. Verbrauchs-Zähler sind Limit-Transparenz, kein Usage-Billing.
> - **Onboarding:** v1 = **Auto-SHK-Provisionierung** (Seeds M158 beim Signup, ohne Wizard). Der **Onboarding-Wizard-UI ist v2** — bitte KEINEN mehrstufigen Setup-Wizard designen. KI-Walkthrough → v2. v1-Screens: Demo-Daten-Verwaltung + Erste-Schritte-Checkliste.
> - **Branding:** v1 = nur **Hell/Dunkel-Toggle** (bewusst nur 2 Optionen, **kein** System-Modus). Logo/Farben/White-Label → v2; keine `/admin/branding`-Route v1. Toggle lebt im Profil/User-Menü (P2/D0).
> - **Branding:** Der Light/Dark-Unterbau bleibt erhalten, der Toggle ist vorerst deaktiviert (`DARK_MODE_IN_APP=false`, PR #81). Logo/Farben/White-Label bleiben ausserhalb v1.
## Was dieses Modul tut (Kurzfassung)
Ein neuer Betrieb kommt vom Self-Service-Signup per Auto-SHK-Provisionierung ins Produkt, läuft auf Legacy-Provider-Billing als Abo-Baukasten (Basis pro Nutzer + Feature-Module als Positionen, Trial mit Dunning + Frozen-Modus), kann optional Demo-Daten anlegen/löschen, sieht eine Erste-Schritte-Checkliste und schaltet flash-frei zwischen Hell und Dunkel um.
Ein neuer Betrieb kommt vom Self-Service-Signup per Auto-SHK-Provisionierung ins Produkt, nutzt HiveGrid-Entitlements mit Lago-/Mollie-Status, kann optional Demo-Daten anlegen/löschen und sieht eine Erste-Schritte-Checkliste. Der Light/Dark-Toggle bleibt vorerst ausgeschaltet.
## Benötigte Screens
| Screen [Route] | Kern-Inhalt | Archetyp |
|---|---|---|
| Abo-Übersicht [`/admin/subscription`] | Basis-Plan + **gebuchte Feature-Module als Positionsliste mit Preisen** · Status/Trial-Countdown · **KEIN Upgrade-Button** (Hinweis-Box „Plan-Wechsel über Account-Manager / hivegrid.de", extern) · Pausieren (Frozen) + Kündigen-Button | A6 + KPI |
| Verbrauchs-Übersicht [`/admin/usage`] | Quota-Balken je Metrik: Automation-Läufe, AI-Tokens, Speicher · aktueller Verbrauch vs. inklusiv · Klartext bei Limit-Erreichen | KPI + Charts |
| AI-Credits-Detail [`/admin/usage/ai-credits`] | Saldo, Verbrauch je Use-Case (Donut), Verlauf, 80%-Warnbanner, Hochrechnung, Aufgebraucht-Klartext (Verweis extern) | KPI + Charts |
| Rechnungen/Zahlung [`/admin/billing`] | **Legacy-Provider-Customer-Portal-Embed** (Rechnungs-History/PDF, Zahlungsmethode, Steuer-/USt-Daten) | A6 |
| Demo-Daten [`/admin/onboarding/demo-data`] | **Settings-Knopf „Beispieldaten anlegen"** (~25 Datensätze, Klartext-Liste was kommt) · Demo-Liste mit Zähler + Lösch-Funktion (Multi-Step-Confirm) · „Demo ausblenden"-Filter erscheint in allen Listen *(kein Wizard, kein KI-Walkthrough — v2)* | A6 |
| Erste-Schritte-Checkliste [`/onboarding/checklist`] | Items mit Status-Häkchen (auto-erkannt), Klartext + Beschreibung, CTA-Link je Item, manuell abhakbar, dauerhaft ausblendbar, Glückwunsch bei 100% (KWP-Item ausgeblendet — v2) · auch als Dashboard-Widget (P11) | A2 |
| Status-Banner-System (Shell) | Tenant-Status-Banner: Trial-Ende-3-Tage / `past_due` (Zahlung fehlgeschlagen + „Zahlungsmethode aktualisieren") / `frozen` (pausiert + „Reaktivieren") / `deletion_pending` — je eigener Klartext + Action-Button · Read-Only-Toast bei blockiertem Schreib-Button | in A1-Shell integriert (D0) |
| Hell/Dunkel-Toggle [im Profil / User-Menü] | Zwei Optionen Hell / Dunkel, sofortige Anwendung ohne Reload, flash-frei (SSR-Cookie) *(kein System-Modus v1)* | A6 (Teil von Profil-Settings P2) |
| Abo-Übersicht [`/:tenant/settings/subscription`] | Plan + Seats + gebuchte Feature-Module · Status/Trial-Countdown · **KEIN Upgrade-Button** (Hinweis „Plan-Wechsel über Account-Manager / hivegrid.de") · Kündigen, falls fachlich freigegeben | A6 + KPI |
| Verbrauchs-Übersicht [`/:tenant/settings/usage`] | Quota-Balken für Automation-Läufe und Speicher · aktueller Verbrauch vs. inklusiv · Klartext bei Limit-Erreichen, ohne Usage-Billing-Sprache | KPI + Charts |
| Rechnungen/Zahlung [`/:tenant/settings/billing`] | Lago-Invoice-Status, Mollie-Payment-Status, Download-/Kontaktzustand und Klartext-Hilfe | A6 |
| Demo-Daten [`/:tenant/settings/onboarding/demo-data`] | **Settings-Knopf „Beispieldaten anlegen"** (~25 Datensätze, Klartext-Liste was kommt) · Demo-Zähler + Lösch-Funktion · „Demo ausblenden"-Filter *(kein Wizard, kein KI-Walkthrough)* | A6 |
| Erste-Schritte-Checkliste [`/:tenant/onboarding/checklist`] | Items mit Status-Häkchen (auto-erkannt), Klartext + Beschreibung, CTA-Link je Item, manuell abhakbar, dauerhaft ausblendbar, Glückwunsch bei 100% · auch als Dashboard-Widget | A2 |
| Status-Banner-System (Shell) | Tenant-Status-Banner: Trial-Ende-3-Tage / `past_due` / `frozen` mit Klartext und Aktion zur Abo-Übersicht beziehungsweise zum Account-Manager. `deletion_pending` samt Shell-Aktion gehört zu `D-P21`; die finale Read-only-Toast-Optik bleibt hier offener Nachzug. | in A1-Shell integriert (D0) |
| Light/Dark-Toggle [Profil / User-Menü] | Vorerst nicht sichtbar und im App-/Admin-Bereich nicht aktiv (`DARK_MODE_IN_APP=false`) | kein neuer Screen |
*(Signup-Formular → P2-Auth. Mitarbeiter-Einladung → P2/P20-Seeds. Kein Onboarding-Setup-Wizard v1. Payment-Checkout läuft extern über Marketing-Site.)*
*(Signup-Formular → P2-Auth. Mitarbeiter-Einladung → P2/P20-Seeds. Kein Onboarding-Setup-Wizard und kein Customer-Checkout in v1; Self-Service-Billing folgt in v2/P24.)*
## Geplante Features (muss abgedeckt sein)
- [ ] Billing über Legacy-Provider als **Abo-Baukasten**: Basis-Preis pro Nutzer + Feature-Module als daten-getriebene Positionen (keine Seat-Typen — M154-Recut); konkrete Preise geparkt (AD-15)
- [ ] Billing zeigt lokale HiveGrid-Plans/Seats/Entitlements read-only; Lago liefert Invoice-/Billing-State, Mollie den Payment-State. Kein Customer-Checkout und kein Usage-Billing (AD-27).
- [ ] Trial mit Dunning (Tag 1/3/7) und **Frozen-Modus** (Read-Only-Middleware) greift; Status-Banner pro Zustand mit Klartext + Action; Verbrauchs-Zähler + Drossel aktiv (Aufschlags-Abrechnung → v2)
- [ ] **In-App keine** Pricing-Tabelle/Upgrade-Buttons/Plan-Wechsel-UI (LP-8) — Abo-Übersicht read-only + externer Verweis; Pause/Kündigen sind erlaubt
- [ ] **In-App keine** Pricing-Tabelle/Upgrade-Buttons/Plan-Wechsel-UI (LP-8) — Abo-Übersicht read-only + externer Verweis; Kündigen bleibt bei vorhandener Berechtigung erlaubt
- [ ] Neuer Tenant wird nach Signup automatisch **SHK-provisioniert** (Seeds M158: Pipelines, Custom-Felder, Rollen, Form-Templates, Checkliste) — **ohne Wizard-UI** (die folgt v2); Trial-Freischaltung durch Plattform-Admin
- [ ] Optionale **Demo-Daten** (5 Contacts, 3 Deals, 2 Projekte, Tasks) per Settings-Knopf provisionierbar und via `is_demo_data`-Flag löschbar; „Demo ausblenden"-Filter in Listen *(KI-Walkthrough → v2; einfaches Löschen statt Multi-Step-Bulk)*
- [ ] Erste-Schritte-Checkliste mit auto-erkanntem Status, CTA-Links, manuell abhakbar/ausblendbar (als Dashboard-Widget)
- [ ] Nutzer schaltet zwischen **Hell und Dunkel** um, flash-frei (SSR-Cookie) *(kein System-Modus — bewusst nur 2 Optionen; `next-themes`)*
- [x] Light/Dark-Toggle ist vorerst deaktiviert; der vorhandene Unterbau bleibt unangetastet (PR #81).
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
Plan-Positionsliste (Basis + Feature-Module mit Preisen, read-only), Trial-Countdown-Badge, KPI-/Quota-Balken (Verbrauch vs. inklusiv), Donut-Chart (AI-Verbrauch je Use-Case), 80%-Warnbanner, externer Verweis-Box („Plan-Wechsel über hivegrid.de", neuer Tab), Pause-Button + Kündigen-Button mit Bestätigungs-Modal, Legacy-Provider-Customer-Portal-Embed (iFrame/Redirect), Demo-Daten-Anlege-Knopf mit Klartext-Inhaltsliste, Demo-Zähler + Lösch-Button mit Multi-Step-Confirm, „Demo ausblenden"-Filter-Toggle, Checklisten-Items mit Status-Icon + CTA-Link + manuell-abhaken + ausblenden, Status-Banner-Stack (trial/past_due/frozen/deletion_pending) mit Action-Button, Read-Only-Toast bei blockiertem Schreib-Button, Hell/Dunkel-Toggle (2 Optionen), Empty-/Loading-/Fehler-/Permission-Denied-States (Klartext mit Lösungs-Knopf).
Plan-/Seat-/Feature-Positionsliste (read-only), Trial-Countdown- und Billing-Status-Badge, KPI-/Quota-Balken (Automation/Speicher), Warnbanner, externer Verweis („Plan-Wechsel über hivegrid.de", neuer Tab), Kündigen-Button mit Bestätigungs-Modal, Lago-Invoice-Status, Mollie-Payment-Status, Rechnung-Download/Support-Hinweis, Demo-Daten-Anlege-Knopf mit Klartext-Inhaltsliste, Demo-Zähler + Lösch-Button, „Demo ausblenden"-Filter-Toggle, Checklisten-Items mit Status-Icon + CTA-Link + manuell-abhaken + ausblenden, Status-Banner-Stack (trial/past_due/frozen) mit Action-Button, bestehende 423-Klartext-Hülle plus final zu gestaltender Read-only-Toast sowie Empty-/Loading-/Fehler-/Permission-Denied-States (Klartext mit Lösungs-Knopf). `deletion_pending` wird in `D-P21` gestaltet.
## Interim-UI-Handoff (AD-28, Stand 2026-07-12)
Die Dev-Vorschau steht auf den kanonischen Tenant-Routen `/:tenant/settings/subscription`,
`/:tenant/settings/usage`, `/:tenant/settings/billing`, `/:tenant/settings/onboarding/demo-data` und
`/:tenant/onboarding/checklist`; das Dashboard nutzt dasselbe Checklisten-VM. Die Screens erhalten reine
Billing-/Onboarding-VMs und injizierte Action-Callbacks. Der Hot-Swap-/Visual-Nachweis liegt unter
`packages/ui-mock/visual-baseline/ak-p20-interim.*`; der echte M016-Pixelnachweis liegt in
`tests/component/ak-p20-interim.ct.tsx` mit fünf PNG-Baselines unter `tests/component/__screenshots__/`.
Der schnelle React-Markup-Nachweis bleibt in `apps/web/app/components/screens/ak-p20-interim.visual.test.tsx`.
Davids finales `D-P20`-Delta bleibt offen und ersetzt
später nur die Screen-Internals; Loader, VM-Verträge und Routen bleiben stabil. Beim Nachzug ist die
Interim-Baseline neu zu ziehen.
## Davids Delta (David füllt aus)
@@ -52,5 +64,6 @@ Plan-Positionsliste (Basis + Feature-Module mit Preisen, read-only), Trial-Count
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] Plane-Ticket (AK-P20) aktualisiert:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [x] Plane-Ticket (AK-P20) aktualisiert: Recut-Titel, Label `design-nachzug` und Abschlusskommentar
`1dee227f-4726-4b7c-8ef1-7a15108f7e99`; Status bis zur Done-Freigabe unverändert.
@@ -1,28 +1,28 @@
# Designer-Brief · P21 — DSGVO & Launch-Reife
**Phase:** 21/21 · **Modul:** M35 (+ M27 D.3 User-Lösch-Verweis) · **Owner-Dev:** Akeshan (AK-P21) · **Designer:** David
**Quellen:** `ROADMAP.md` §Phase 21 · `ENTITY-MODEL.md` Domäne 13 (Onboarding/Branding/DSGVO) · `SCREEN-MAP.md` §6 (DSGVO-Compose) · `_bmad-output/specs/M35-dsgvo-export.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A5 Modal/Wizard, A6 Settings, A7 Zustände).
> 🟡 **Letzte v1-Phase — macht den Big-Bang-Launch (AD-19) auslösbar. Schnitte (verbindlich):**
> - **DSGVO-Auskunft = manuelles Playbook v1:** Suche → Kontakt-Detail (Activity-Stream) → CSV-Export → Anwalts-Vorlage → Frist-Task (+25 Tage). Es wird **KEIN** automatisches Auskunfts-/Voll-Export-Tooling pro betroffener Person gebaut (das ist v2, M34/M36/M38/M39). Bitte **keinen** Auskunfts-Wizard designen — das Playbook nutzt bestehende Screens (Cmd+K, Kontakt-Detail, CSV).
> - **v1 baut:** DSGVO-ZIP-Export (User-Self + Tenant-Full, 72h-signed-URL), Tenant-Lösch-Workflow (Crypto-Shredding, 30-Tage-Grace, Slug-Confirm-Phrase), Feedback-Widget (speist Admin-Support-Inbox P19), Minimal-FAQ-Seite. AVV/Subprozessoren-Anzeige im Privacy-Hub.
> - **v1 baut:** DSGVO-ZIP-Export (User-Self + Tenant-Full, authentifizierter bis zu 72 h verfügbarer App-Download), Tenant-Lösch-Workflow (Crypto-Shredding, 30-Tage-Grace, Slug-Confirm-Phrase), Feedback-Widget (speist Admin-Support-Inbox P19), Minimal-FAQ-Seite. AVV/Subprozessoren-Anzeige im Privacy-Hub.
> - **PWA-Hinweis:** Monteure arbeiten mobil über die **PWA/responsive Web-App** (mobile-first Screens + P9-Offline). Der PWA-Ausbau (Installierbarkeit/Web-Push, M27) folgt v2; **kein nativer Client** (AD-17, PWA-only). Für P21 heißt das: alle hier neuen Screens auch mobil tauglich, kein App-Store-/Native-Screen.
## Was dieses Modul tut (Kurzfassung)
Deckt den DSGVO-Lebenszyklus ab und macht die Plattform launch-fertig: tenant- und user-weiter DSGVO-ZIP-Export (asynchron, signierte Download-URL), Tenant-Lösch-Workflow mit Crypto-Shredding und Grace-Period, AVV-/Subprozessoren-Sichtbarkeit, ein In-App-Feedback-Widget, das die Admin-Support-Inbox speist, und eine Minimal-FAQ-Seite.
Deckt den DSGVO-Lebenszyklus ab und macht die Plattform launch-fertig: tenant- und user-weiter SSE-C-verschlüsselter DSGVO-ZIP-Export (asynchron, authentifizierte ablaufende `200`-App-Route), Tenant-Lösch-Workflow mit Crypto-Shredding und Grace-Period, AVV-/Subprozessoren-Sichtbarkeit, ein In-App-Feedback-Widget, das die Admin-Support-Inbox speist, und eine Minimal-FAQ-Seite.
## Benötigte Screens
| Screen [Route] | Kern-Inhalt | Archetyp |
|---|---|---|
| Privacy-Hub [`/admin/privacy`] | Übersicht: Export, Löschung, Subprozessoren, AVV, Privacy-Manifest-Link · Einstieg in die Sub-Bereiche | A6 + KPI |
| Tenant-Daten-Export [`/admin/privacy/export`, `/new`, `/:jobId`] | Job-Liste mit Status/Progress/Download (72h-Link) · Anstoßen mit Klartext (was, geschätzte Größe/Dauer, 7-Tage-Window) · Job-Status mit Progress | A2 + A5 |
| Tenant-Daten-Export [`/admin/privacy/export`, `/new`, `/:jobId`] | Job-Liste mit Status/Progress/Download (authentifizierte App-Route, maximal 72 h) · Anstoßen mit Klartext (was, geschätzte Größe/Dauer, Retention) · Job-Status mit Progress | A2 + A5 |
| **Tenant-Löschung** [`/admin/privacy/deletion`, `/:requestId`] | Multi-Step: Erklärung (30-Tage-Grace, Read-Only, Hard-Delete) → Export-Angebot → Legacy-Provider-Hinweis (Pro-rata) → Passwort + 2FA → **Slug als Confirm-Phrase** · Grace-Countdown mit Abbruch-Button | A5 (Wizard) |
| Subprozessoren [`/admin/privacy/subprocessors`] | Tabelle: Name, Land, EU/EEA-Marker, Zweck, Datenkategorien, DPA-Link, „aktiv seit" · Filter (EU/alle, Kategorie) · Export CSV/PDF | A2 |
| AVV [`/admin/privacy/avv`] | Aktuelle Version als PDF-Download + Akzeptanz-History (Version, Datum, Signer) · Re-Akzeptanz-Modal bei Update (Klartext-Änderungen) | A2 + A5 |
| User-Daten-Export [`/settings/account/data-export`, `/:jobId`] | Klartext was exportiert wird, Start-Button, Rate-Limit-Hinweis, Job-Status mit Download (signed-URL) | A6 |
| User-Daten-Export [`/settings/account/data-export`, `/:jobId`] | Klartext was exportiert wird, Start-Button, Rate-Limit-Hinweis, Job-Status mit authentifiziertem App-Download | A6 |
| Account-Löschung [`/settings/account/delete`] | Multi-Step: Erklärung → optional Daten-Export-Angebot → Passwort + 2FA → Countdown-Bestätigung (24h-Reverse-Window) · *(Detail-Logik M27 D.3)* | A5 (Wizard) |
| **Feedback-Widget** [global, klein] | Schwebender Button → Mini-Form (Kategorie Bug/Feature/Frage, Text, Screenshot-Häkchen, Rate-Limit) → landet in Admin-Support-Inbox (P19) · Erfolgs-/Fehler-Zustand | A5-klein |
| Minimal-FAQ [`/help` o.ä.] | Statische FAQ-Seite mit gruppierten Fragen/Antworten (Markdown), Suchfeld optional · kein Help-Center-Ausbau (→ v2) | A6 / statisch |
@@ -31,7 +31,7 @@ Deckt den DSGVO-Lebenszyklus ab und macht die Plattform launch-fertig: tenant- u
## Geplante Features (muss abgedeckt sein)
- [ ] Nutzer kann **DSGVO-ZIP-Export** anstoßen (User-Self **und** Tenant-Full); asynchroner BullMQ-Job mit Progress, 72h-signed-URL-Download, Rate-Limit (max. 3 User-Self/24h, max. 1 Tenant-Full aktiv); README + manifest.json im ZIP
- [ ] Nutzer kann **DSGVO-ZIP-Export** anstoßen (User-Self **und** Tenant-Full); asynchroner BullMQ-Job mit Progress, authentifiziertem bis zu 72 h verfügbarem `200`-Download, Rate-Limit (max. 3 User-Self/24h, max. 1 Tenant-Full aktiv); README + manifest.json im ZIP; direkter Storage-Zugriff ohne SSE-C-Key scheitert
- [ ] **Tenant-Löschung** führt Crypto-Shredding (Per-Tenant-DEK), Legacy-Provider-Cancel und Storage/Cache/Index-Bereinigung durch (AD-8); 30-Tage-Grace mit Read-Only + Abbruch-Möglichkeit; **Slug als Confirm-Phrase**; Legacy-Provider-Cancel erst beim Hard-Delete-Cron
- [ ] **DSGVO-Auskunft als dokumentiertes manuelles Playbook** (Suche → Kontakt-Detail → CSV → Anwalts-Vorlage → Frist-Task +25 Tage); AVV-Vorlage liegt vor (Externals E6) — **kein** automatisches Tooling v1
- [ ] AVV-Download + Akzeptanz-History + Re-Akzeptanz-Flow bei Updates (14-Tage-Frist, Read-Only-Sperre danach); Subprozessoren-Liste mit Drittland-Klartext-Warnung (v1 EU-only)
@@ -42,7 +42,7 @@ Deckt den DSGVO-Lebenszyklus ab und macht die Plattform launch-fertig: tenant- u
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
Export-Job-Liste mit Progress-Balken + Status-Badge + Download-Button (signed-URL, Ablauf-Hinweis), Export-Anstoß-Dialog mit Klartext-Größen-/Dauer-Schätzung, Multi-Step-Lösch-Wizard mit Progress, Slug-Confirm-Phrase-Eingabe (Tippen statt Knopf), Grace-Countdown-Banner mit Abbruch-Button, Passwort-+2FA-Bestätigungsschritt, Subprozessor-Tabelle mit EU/Drittland-Marker + DPA-Link + CSV/PDF-Export, AVV-PDF-Download + Akzeptanz-History-Liste + Re-Akzeptanz-Modal mit Änderungs-Klartext, Drittland-Warn-Badge, schwebender Feedback-Button + Mini-Form (Kategorie-Select, Textarea, Screenshot-Häkchen) mit Rate-Limit-Hinweis, FAQ-Akkordeon (gruppierte Fragen/Antworten, Markdown) + optionales Suchfeld, Empty-/Loading-/Fehler-/Permission-Denied-/Offline-States (Klartext mit Lösungs-Knopf), mobile-first-Varianten aller Screens.
Export-Job-Liste mit Progress-Balken + Status-Badge + Download-Button (authentifizierte `200`-App-Route, Ablauf-Hinweis), Export-Anstoß-Dialog mit Klartext-Größen-/Dauer-Schätzung, Multi-Step-Lösch-Wizard mit Progress, Slug-Confirm-Phrase-Eingabe (Tippen statt Knopf), Grace-Countdown-Banner mit Abbruch-Button, Passwort-+2FA-Bestätigungsschritt, Subprozessor-Tabelle mit EU/Drittland-Marker + DPA-Link + CSV/PDF-Export, AVV-PDF-Download + Akzeptanz-History-Liste + Re-Akzeptanz-Modal mit Änderungs-Klartext, Drittland-Warn-Badge, schwebender Feedback-Button + Mini-Form (Kategorie-Select, Textarea, Screenshot-Häkchen) mit Rate-Limit-Hinweis, FAQ-Akkordeon (gruppierte Fragen/Antworten, Markdown) + optionales Suchfeld, Empty-/Loading-/Fehler-/Permission-Denied-/Offline-States (Klartext mit Lösungs-Knopf), mobile-first-Varianten aller Screens.
## Davids Delta (David füllt aus)
@@ -54,5 +54,5 @@ Export-Job-Liste mit Progress-Balken + Status-Badge + Download-Button (signed-UR
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (AK-P21) aktualisiert:
@@ -1,7 +1,7 @@
# Designer-Brief · P22 — Public-API & Webhooks (v2-P1)
**Phase:** 22/34 (v2-P1) · **Modul:** M34 · **Owner-Dev:** Raffael (VR-P22a/b) · **Designer:** David · **Slot:** v2-W1 (13.–17.07.)
**Quellen:** `ROADMAP-V2.md` §v2-P1 (Screens/Features = Hauptquelle) · `ROADMAP.md` §Phase 22 · `ENTITY-MODEL.md` (ApiKey/WebhookSubscription) · `_bmad-output/specs/M34-public-api.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A3 Detail, A5 Modal, A6 Settings).
> 🔵 **Recut-Hinweis:** Bewusst **Read-only-REST + Webhooks** — kein Voll-CRUD, kein GraphQL, kein 3-Legged-OAuth (alles später). Das `ApiKey`-Modell lag aus v1 (M027) ungenutzt bereit — die API-Key-Verwaltung ist eine **Erweiterung** der vorhandenen v1-Fläche, kein Neubau. Secrets/Webhook-Signing-Secrets sind **einmalig sichtbar** (Copy-once-Muster).
@@ -48,5 +48,5 @@ Daten-Tabelle (sortierbar, paginiert) für Keys/Webhooks/Logs, „Secret/Token e
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (VR-P22a/b) aktualisiert:
@@ -1,7 +1,7 @@
# Designer-Brief · P23 — Postfach-Sync (Email-Inbox) (v2-P2)
**Phase:** 23/34 (v2-P2) · **Modul:** M09 (M096–M098) · **Owner-Dev:** Akeshan (VA-P23) · **Designer:** David · **Slot:** v2-W1 (13.–17.07.)
**Quellen:** `ROADMAP-V2.md` §v2-P2 (Screens/Features = Hauptquelle) · `ROADMAP.md` §Phase 23 · `ENTITY-MODEL.md` (Activity-Stream/Contact/Lead/Projekt-FKs) · `_bmad-output/specs/M09-email-inbox.md` (OAuth-Sync/Inbox/Threading-Teile)
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A3 Detail, A5 Modal, A6 Settings).
> 🔵 **Recut-Hinweis:** Nur der **OAuth-Sync/Inbox/Threading-Teil** von M09 ist v2. Die **Sende-Domain (DKIM/SPF/DMARC)** stammt aus v1-P14 und wird **NICHT** neu gebaut. Versand läuft über die **User-Mailbox** (Gmail/Graph), nicht über die Marketing-Sende-Domain. Push-Sync ist Pflicht (kein Primär-Polling). ⚠️ Gmail restricted scopes (`gmail.modify/send`) brauchen Google-Verifizierung/CASA (Antrag lief in v1 EXT-13); Microsoft-Graph-Subscription muss ~alle 3 Tage erneuert werden.
@@ -44,5 +44,5 @@ Provider-Connect-Buttons (Gmail/Microsoft mit Logo), Sync-Status-Panel (Progress
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (VA-P23) aktualisiert:
@@ -1,7 +1,7 @@
# Designer-Brief · P24 — Self-Service-Billing & Onboarding-Wizard (v2-P3)
**Phase:** 24/34 (v2-P3) · **Module:** M28/M29 (M157 + M28-Self-Service-Delta, Block P) · **Owner-Dev:** Akeshan (VA-P24a/b) · **Designer:** David · **Slot:** v2-W1→W2 (Abo-UI 13.–17., Wizard 18./19.07.)
**Quellen:** `ROADMAP-V2.md` §v2-P3 (Screens/Features = Hauptquelle) · `ROADMAP.md` §Phase 24 · `_bmad-output/specs/M28-subscriptions-billing.md` (Block P) · `_bmad-output/specs/M29-onboarding.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A3 Detail, A5 Modal, A6 Settings, Vollbild-Flow).
> 🔵 **Recut-/PWA-Hinweis:** **PWA-only (AD-17)** → Self-Service-Billing läuft komplett über **Web-Checkout** (v1-Payment-Checkout wiederverwenden). **Keine App-Store-Billing-Auflage** — Apple-Guideline 3.1.3 entfällt vollständig, Plan-Wechsel direkt im Web. Self-Service ist v2, weil konkrete **Preise feststehen müssen** (v1 EXT-14 fixiert). Das Wizard-Framework ist großteils v1-fähig; v2-Delta = weitere Branchen + KI-Coach (per Retro-Integration aus P25) + Migration-Importer. Branchen-Template-Seeding ist ein **geteilter Mechanismus** (P24/P26/P30).
@@ -44,5 +44,5 @@ Step-Progress-Indikator (10 Steps, Vollbild), Step-Inhalts-Container mit Validie
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (VA-P24a/b) aktualisiert:
@@ -1,30 +1,34 @@
# Designer-Brief · P26 — Customer-Portal (v2-P6) ⭐ *(ex-P18)*
**Phase:** 26/34 (v2-P6) · **Modul:** M15 (M141–M146) · **Owner-Dev:** Akeshan (VA-P26a/b) · **Designer:** David · **Slot:** v2-W2 (20.–22.07.)
**Quellen:** `ROADMAP-V2.md` §v2-P6 (Screens/Features = Hauptquelle) · `ROADMAP.md` §Phase 26 · `ENTITY-MODEL.md` (Project-Stages/Files/FileEntityLink) · `_bmad-output/specs/M15-customer-portal.md`
**Phase:** 26/34 (v2-P6) · **Modul:** M15 (M141–M146 + AD-30-Delta) · **Owner-Dev:** Akeshan (VA-P26a/b/c) · **Designer:** David · **Slot:** parallel zu P26, Zieltermin offen; `VA-P26a` 16.07.–05.08., `VA-P26b` frühestens ab 06.08., `VA-P26c` Termin offen
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. **Eigener Polish — extern sichtbar.** Archetypen aus D0 (A2 Liste, A3 Detail, A5 Modal, A6 Settings, Auth-Flow).
> 🔴 **Auth-Trennung & externer Polish:** Eigene **`PortalUser`-Klasse strikt getrennt von TenantUser** (eigene Cookies, eigene Routes unter `/portal/<tenant>/…`, keine Permission-Vermischung), **Magic-Link primär**. Eigene Auth = eigenes Härtungs-Budget (Rate-Limits, Captcha, **kein User-Enumeration**, fehlender Zugang → **404** statt Existenz-Offenlegung). Dies ist die einzige **extern sichtbare** Endkunden-Oberfläche → höchster Design-Polish. Ausgeklammert: Multi-Portal/Branding/Custom-Domain/PortalSubscription/PWA-Push.
> 🔴 **Auth-Trennung & externer Polish:** Eigene **`PortalUser`-Klasse strikt getrennt von TenantUser** (eigene hostgebundene Cookies, keine Permission-Vermischung), **Magic-Link primär**. Standard-Routes liegen unter `https://portal.hivegrid.de/<tenant>/…`; ein verifizierter Custom-Host zeigt dieselben Screens ohne Tenant-Slug. Endkunden-Screens laufen im separaten `hivegrid-portal`-Container, Workspace-Admin-Screens weiterhin in `hivegrid-web`; das ändert den gemeinsamen VM-/Action-Contract und die Optik nicht. Eigene Auth = eigenes Härtungs-Budget (Rate-Limits, Captcha, **kein User-Enumeration**, fehlender Zugang → **404** statt Existenz-Offenlegung). Dies ist die einzige **extern sichtbare** Endkunden-Oberfläche → höchster Design-Polish. Ausgeklammert: eigenes Portal-Image im ersten Schnitt, Multi-Portal, vollständiges App-White-Label, Apex-/Wildcard-/Mehrfach-Domains, eigenes PortalSubscription-Modell und PWA-Push.
## Was dieses Modul tut (Kurzfassung)
Endkunden (PortalUser) sehen über eine **eigene Auth-Schicht** ihre Projekte, deren Status (nur konfigurierte Stages) und freigegebene Dokumente, **laden Dateien hoch** (mobile Kamera, Multi-File) und melden Reklamationen. Bei `project.stage_changed` gehen **Auto-Status-Mails** raus (debounced, bedingungsgesteuert). Der Tenant-Admin konfiguriert Phasen-Sichtbarkeit, Dokument-Auto-Freigabe und Mail-Templates; DSGVO-Lösch/Export für PortalUser ist vorhanden.
Endkunden (PortalUser) sehen über eine **eigene Auth-Schicht** ihre Projekte, deren Status (nur konfigurierte Stages) und freigegebene Dokumente, **laden Dateien hoch** (mobile Kamera, Multi-File) und melden Reklamationen. Bei `project.stage_changed` gehen **Auto-Status-Mails** raus (debounced, bedingungsgesteuert). Der Workspace-Admin konfiguriert Phasen-Sichtbarkeit, Dokument-Auto-Freigabe und Mail-Templates, bucht das Portal-Add-on und richtet optional per DNS-Self-Service eine Custom-Domain ein; DSGVO-Lösch/Export für PortalUser ist vorhanden.
## Benötigte Screens
| Screen [Route] | Kern-Inhalt | Archetyp |
|---|---|---|
| Endkunde · Login [`/portal/{tenant}/login` · `/login/magic-sent`] | E-Mail-Login (Magic-Link primär, Passwort sekundär), „Magic-Link gesendet"-Bestätigung, kein User-Enumeration | Auth-Flow |
| Endkunde · Setup/Verify/Reset [`/portal/{tenant}/setup/{token}` · `/verify-email/{token}` · `/forgot-password` · `/reset-password/{token}`] | Erstzugang-Setup, E-Mail-Verifizierung, Passwort-Vergessen/-Reset | Auth-Flow |
| Endkunde · Portal-Dashboard [`/portal/{tenant}`] | Übersicht eigene Projekte + Status auf einen Blick, freigegebene Dokumente, Schnellaktionen | A3/Dashboard |
| Endkunde · Projekte-Liste [`/portal/{tenant}/projects`] | Liste eigener Projekte (Name, Stage/Fortschritt, letztes Update) | A2 |
| Endkunde · Project-Detail [`/portal/{tenant}/projects/:id`] | Fortschritt (nur sichtbare Stages), freigegebene Dokumente (Download), Upload, Reklamation melden, Forms (`portal_form`) | A3 |
| Endkunde · Upload [`/portal/{tenant}/upload`] | Datei-Upload (mobile-Kamera, Multi-File, Limits) → Files + Activity + PL-Notification | A5 |
| Endkunde · Settings [`/portal/{tenant}/settings` · `/notifications` · `/account-delete`] | Profil, Benachrichtigungs-Präferenzen, DSGVO-Account-Löschung/Export | A6 |
| Tenant-Admin · Portal-Konfig [`/admin/portal`] | Phasen-Sichtbarkeit, Dokument-Auto-Freigabe-Regeln, Aktivierung pro Projekt-Typ | A6 |
| Tenant-Admin · PortalUser-Verwaltung [`/admin/portal/users`] | PortalUser-Liste, Einladen, Zugang sperren/entziehen, Status | A2 |
| Tenant-Admin · Access-Matrix [`/admin/portal/access`] | Wer-sieht-welches-Projekt (Zugriffs-Matrix), Subunternehmer-Zugang | A2 |
| Tenant-Admin · Mail-Template-Editor [`/admin/portal/email-templates`] | Auto-Status-Mail-Vorlagen je Stage-Event, Variablen, Vorschau | A3 |
| Endkunde · Login [`portal.hivegrid.de/{tenant}/login` · `/login/magic-sent`] | E-Mail-Login (Magic-Link primär, Passwort sekundär), „Magic-Link gesendet"-Bestätigung, kein User-Enumeration | Auth-Flow |
| Endkunde · Setup/Verify/Reset [`portal.hivegrid.de/{tenant}/setup/{token}` · `/verify-email/{token}` · `/forgot-password` · `/reset-password/{token}`] | Erstzugang-Setup, E-Mail-Verifizierung, Passwort-Vergessen/-Reset | Auth-Flow |
| Endkunde · Portal-Dashboard [`portal.hivegrid.de/{tenant}`] | Übersicht eigene Projekte + Status auf einen Blick, freigegebene Dokumente, Schnellaktionen | A3/Dashboard |
| Endkunde · Projekte-Liste [`portal.hivegrid.de/{tenant}/projects`] | Liste eigener Projekte (Name, Stage/Fortschritt, letztes Update) | A2 |
| Endkunde · Project-Detail [`portal.hivegrid.de/{tenant}/projects/:id`] | Fortschritt (nur sichtbare Stages), freigegebene Dokumente (Download), Upload, Reklamation melden, Forms (`portal_form`) | A3 |
| Endkunde · Upload [`portal.hivegrid.de/{tenant}/upload`] | Datei-Upload (mobile-Kamera, Multi-File, Limits) → Files + Activity + PL-Notification | A5 |
| Endkunde · Settings [`portal.hivegrid.de/{tenant}/settings` · `/notifications` · `/account-delete`] | Profil, Benachrichtigungs-Präferenzen, DSGVO-Account-Löschung/Export | A6 |
| Workspace-Admin · Portal-Konfig [`app.hivegrid.de/settings/customer-portal`] | Paketstatus/Paywall, Phasen-Sichtbarkeit, Dokument-Auto-Freigabe-Regeln, Aktivierung pro Projekt-Typ | A6 |
| Workspace-Admin · Custom-Domain [`app.hivegrid.de/settings/customer-portal/domain`] | Hostname, TXT-/CNAME-Anleitung, Verify-Aktion, Provisioning-/TLS-/Fehlerstatus, Standardhost-Fallback, Entfernen/Wechseln | A6 + Web-Flow |
| Workspace-Admin · PortalUser-Verwaltung [`app.hivegrid.de/settings/customer-portal/users`] | PortalUser-Liste, Einladen, Zugang sperren/entziehen, Status | A2 |
| Workspace-Admin · Access-Matrix [`app.hivegrid.de/settings/customer-portal/access`] | Wer-sieht-welches-Projekt (Zugriffs-Matrix), Subunternehmer-Zugang | A2 |
| Workspace-Admin · Mail-Template-Editor [`app.hivegrid.de/settings/customer-portal/email-templates`] | Auto-Status-Mail-Vorlagen je Stage-Event, Variablen, Vorschau | A3 |
Auf einem aktiven Custom-Host, z. B. `portal.geerkens.de`, bleiben die Endkundenpfade identisch, aber ohne
`/{tenant}`. Der Standardhost ist immer sichtbar als Fallback-Link.
## Geplante Features (muss abgedeckt sein)
@@ -35,11 +39,13 @@ Endkunden (PortalUser) sehen über eine **eigene Auth-Schicht** ihre Projekte, d
- [ ] Tenant-Admin konfiguriert Phasen-Sichtbarkeit / Doc-Auto-Freigabe / Templates; Subunternehmer-Zugang (M144); Service-Inbox/Skalierungs-Sicht (M145)
- [ ] DSGVO-Lösch/Export für PortalUser + Lebensdauer-/Konfig-Verwaltung (M146)
- [ ] Härtung: Rate-Limits, Captcha, kein User-Enumeration, wasserdichte Cookie-Trennung
- [ ] Paket-/Paywall-Zustände: Starter/Team 19,99 EUR netto/Monat, Business/Enterprise inklusive; Custom-Domain Starter/Team/Business 299,99 EUR netto je Einrichtung, Enterprise eine inklusive; Domainwechsel ist eine neue kostenpflichtige Einrichtung, sofern keine individuelle Enterprise-Regel greift
- [ ] Custom-Domain-Self-Service mit verständlicher DNS-Anleitung und allen Zuständen (`pending_dns`, `verified`, `provisioning`, `active`, Fehler/deaktiviert); Standardhost-Fallback und 30-Tage-Reclaim-Cooldown bei Entfernen/Wechseln bleiben sichtbar
- [ ] Wiederverwendung v1: Auth-Pattern (parallel, NICHT geteilt), Files/FileEntityLink, Sende-Domain (Auto-Mails), Form-Builder (`portal_form`), Automation (`portal.*`), notify(), DSGVO-Lösch-Workflow
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
Magic-Link-Login-Formular (E-Mail-Feld, „Link senden"), „Magic-Link gesendet"-Bestätigung, Passwort-Setup/-Reset-Formulare, Captcha-Einbindung, Projekt-Karten/-Liste mit Fortschritts-/Stage-Indikator (nur sichtbare Stages), Dokument-Liste mit Download (freigegebene), Upload-Control (mobile-Kamera-Capture, Multi-File-Drag-Drop, Größen-/Typ-Limit-Hinweis), Reklamations-Formular, Portal-Form-Renderer (`portal_form`), Benachrichtigungs-Präferenz-Toggles, Account-Lösch-/Export-Flow (Bestätigung), Admin: Zugriffs-Matrix-Tabelle, PortalUser-Verwaltungs-Tabelle (Einladen/Sperren), Phasen-Sichtbarkeits-Konfig (Stage-Toggles), Doc-Auto-Freigabe-Regel-Editor, Mail-Template-Editor mit Variablen + Vorschau, 404-/Kein-Zugang-State (ohne Existenz-Offenlegung), Empty-/Loading-/Frozen-Read-Only-States (Klartext). **Hoher externer Polish** (Endkunden-facing).
Magic-Link-Login-Formular (E-Mail-Feld, „Link senden"), „Magic-Link gesendet"-Bestätigung, Passwort-Setup/-Reset-Formulare, Captcha-Einbindung, Projekt-Karten/-Liste mit Fortschritts-/Stage-Indikator (nur sichtbare Stages), Dokument-Liste mit Download (freigegebene), Upload-Control (mobile-Kamera-Capture, Multi-File-Drag-Drop, Größen-/Typ-Limit-Hinweis), Reklamations-Formular, Portal-Form-Renderer (`portal_form`), Benachrichtigungs-Präferenz-Toggles, Account-Lösch-/Export-Flow (Bestätigung), Admin: Paket-/Entitlement-Status und Add-on-CTA, Domain-Eingabe, kopierbare TXT-/CNAME-Werte, DNS-Prüfen-Aktion, Domain-/TLS-Status-Timeline, Fehlerbehebung, Standardhost-Fallback, Domain-Entfernen/-Wechseln-Bestätigung, Zugriffs-Matrix-Tabelle, PortalUser-Verwaltungs-Tabelle (Einladen/Sperren), Phasen-Sichtbarkeits-Konfig (Stage-Toggles), Doc-Auto-Freigabe-Regel-Editor, Mail-Template-Editor mit Variablen + Vorschau, 404-/Kein-Zugang-State (ohne Existenz-Offenlegung), Empty-/Loading-/Frozen-Read-Only-States (Klartext). **Hoher externer Polish** (Endkunden-facing).
## Davids Delta (David füllt aus)
@@ -51,5 +57,5 @@ Magic-Link-Login-Formular (E-Mail-Feld, „Link senden"), „Magic-Link gesendet
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] Plane-Ticket (VA-P26a/b) aktualisiert:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (VA-P26a/b/c) aktualisiert:
@@ -1,7 +1,7 @@
# Designer-Brief · P27 — Mobile-PWA-Ausbau
**Phase:** 27/34 · **Modul:** M36 · **Owner-Dev:** Akeshan (VA-P27a/b) · **Designer:** David (D-Mobile-PWA)
**Quellen:** `ROADMAP-V2.md` §v2-P7 · `ROADMAP.md` §Phase 27 · `_bmad-output/specs/M36-mobile-app.md` (⚠ Recut → PWA-only; Capacitor/Expo verworfen)
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Mobile-first PWA-Shell, Touch-Paradigma.
> 🔴 **PWA-only-Sonderfall (AD-17):** **Kein nativer Client, kein Expo/Capacitor, kein App-Store, kein EAS-Build, keine Store-Compliance.** Native-App + Stores → frühestens v3. Dieser Brief beschreibt ausschließlich den **PWA-Ausbau** der bereits in v1 vorhandenen mobile-first Web-App: installierbare PWA (Web-App-Manifest, Add-to-Homescreen, Standalone-Display), Service-Worker-Offline-Härtung, Web-Push via VAPID, Kamera/Foto über Web-APIs, Force-Update über Service-Worker-Versionierung. ⚠ iOS-Safari-Grenze: Web-Push auf iOS nur ≥16.4 im installierten Standalone-Modus.
@@ -48,5 +48,5 @@ Touch-optimierte Navigations-Shell (Bottom-Nav/Drawer), Modus-Umschalter (Bauste
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (VA-P27a/b) aktualisiert:
@@ -1,14 +1,14 @@
# Designer-Brief · P28 — Plattform-Admin-Tiefe
**Phase:** 28/34 · **Module:** M37/M32 (M038/M039/M033/M040) · **Owner-Dev:** Raffael (VR-P28a) + Akeshan (VA-P28b) · **Designer:** David (D-Admin-Tiefe)
**Quellen:** `ROADMAP-V2.md` §v2-P8 · `ROADMAP.md` §Phase 28 · `_bmad-output/specs/M37-plattform-admin.md` (Block A–D) · `_bmad-output/specs/M32-feature-flags.md` (Massen-Statistik)
**Phase:** 28/34 · **Module:** M37/M32 (M038/M039/M033/M040a/b) · **Owner-Dev:** Raffael (`R-LEADS`, `VR-P28a`, `VA-P28b`) · **Designer:** David (D-Admin-Tiefe)
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Interner Polish (Admin-Welt), nicht extern sichtbar.
> 🔴 **Hardgrenze Admin-Welt:** Läuft auf Sub-Domain `admin.hivegrid.de`, **nicht** unter `/{tenant}/...` erreichbar. Eigene `AdminUser`-Klasse parallel zu `User`/`TenantUser`, eigene Cookies (SameSite=Strict), kein Cross-Routing. **Kein BYPASSRLS** — der Admin liest Tenant-Daten via RLS mit gesetztem `app.tenant_id`. v1 lieferte die Auflagen-Brücke (M034: Host-Routing/Cookie-Trennung/TOTP); P28 löst sie durch die echte getrennte Identität/RBAC ab.
> 🔴 **Hardgrenze Admin-Welt:** Läuft auf Sub-Domain `admin.hivegrid.de`, **nicht** unter `/{tenant}/...` erreichbar. Eigene `AdminUser`-Klasse parallel zu `User`/`TenantUser`, eigene Cookies (SameSite=Strict), kein Cross-Routing. **Kein BYPASSRLS** — der Admin liest Tenant-Daten via RLS mit gesetztem `app.tenant_id`. Authentik ist der einzige produktive Admin-Login und liefert die MFA-Assurance; P28 löst die v1-`User`-/`UserSession`-Brücke vollständig ab.
## Was dieses Modul tut (Kurzfassung)
Macht die Plattform-Admin-Welt zur vollwertigen, getrennten Identitäts- und Rechte-Schicht für uns als Software-Betreiber: eigene AdminUser-Konten mit AdminRBAC (Default-Rollen super_admin/support/sales/engineering/viewer), 2FA-Pflicht, 8h-Session, Self-Permission-Schutz und cross-tenant AdminAuditLog mit Reason-Pflicht. Dazu die Feature-Flag-Massen-Statistik (effektive Auswertung über alle Tenants, Live-Filter-Vorschau, Bulk-Override) und eine interne Lead-Pipeline für HiveGrid-eigene Verkäufe.
Macht die Plattform-Admin-Welt zur vollwertigen, getrennten Identitäts- und Rechte-Schicht für uns als Software-Betreiber: eigene AdminUser-Konten mit Authentik-MFA-Assurance und AdminRBAC (Default-Rollen super_admin/support/sales/engineering/viewer), 8h-Session, Self-Permission-Schutz und cross-tenant AdminAuditLog mit Reason-Pflicht. Dazu die Feature-Flag-Massen-Statistik und die interne Vertriebswelt in zwei klaren Ebenen: M040a als native Plattform-Lead-Inbox/Source-Verwaltung (`R-LEADS`) und M040b als Deal-Kanban/Forecast/Promotion (`VA-P28b`).
## Benötigte Screens
@@ -21,7 +21,9 @@ Macht die Plattform-Admin-Welt zur vollwertigen, getrennten Identitäts- und Rec
| Feature-Flag Effektiv-Statistik [`/feature-flags`] | Pro Flag: X aktiv / Y nicht aktiv über alle Tenants, deterministische Auswertung (Override > Filter > Default) | A2 |
| Filter-Editor (Live-Match) [`/feature-flags/:key`] | Filter-Regeln definieren, Live-Vorschau der getroffenen Tenants (Read-Replica) | A6 + Live-Preview |
| Bulk-Override [`/feature-flags/:key/bulk`] | Massen-Setzen von Overrides auf gefilterte Tenant-Menge, mit Audit | A5 |
| Interne Lead-Pipeline [`/leads`] | HiveGrid-eigene Verkäufe: Lead-/Deal-Liste + Detail, Quelle/source_detail, Stage | A2 + A3 |
| Plattform-Lead-Inbox [`/leads`, `/leads/:id`] | M040a: Lead-Liste/-Detail, Quelle, Status, Assignment, Activity/Notizen, Archiv | A2 + A3 |
| Lead-Quellen [`/leads/sources`] | M040a: Source-Status, Default-Assignee/Empfänger, Credential erstellen/rotieren/revoken | A2 + A6 |
| Deal-Pipeline [`/leads/pipeline`, `/deals/:id`] | M040b: Deal-Kanban, Stage, Forecast/ARR, Promote-to-Tenant | A2 + A3 |
| Cross-Tenant-Audit-View [`/audit`] | AdminAuditLog über alle Tenants, Reason-Pflicht-Einträge, Impersonate-Records, Filter | A2 |
## Geplante Features (muss abgedeckt sein)
@@ -31,11 +33,11 @@ Macht die Plattform-Admin-Welt zur vollwertigen, getrennten Identitäts- und Rec
- [ ] AdminAuditLog cross-tenant mit Reason-Pflicht bei sensitiven Aktionen; Impersonate mit Reason + Banner
- [ ] Flag-Massen-Statistik: Effektiv-Auswertung (X aktiv/Y nicht), Live-Filter-Vorschau (Read-Replica), Bulk-Override
- [ ] Deterministische Flag-Auswertung (Override > Filter > Default) + Audit
- [ ] Interne Lead-Pipeline für HiveGrid-eigene Verkäufe
- [ ] M040a Plattform-Lead-Inbox/Quellen und M040b Deal-Pipeline visuell klar getrennt
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
Daten-Tabelle (sortierbar, paginiert), Rollen-/Permission-Bundle-Matrix, Session-Liste mit Revoke-Button, 2FA-Status-Badge, Reason-Pflicht-Dialog (Begründung erzwungen), Impersonate-Warn-Banner, Flag-Effektiv-Statistik-Kachel (aktiv/inaktiv-Zähler), Filter-Regel-Editor mit Live-Match-Vorschau-Liste, Bulk-Override-Bestätigung mit betroffener-Tenant-Anzahl, Audit-Timeline (Actor/Reason/Ziel), Lead-/Deal-Pipeline-Ansicht, Empty-/Loading-/Permission-Denied-States (Klartext).
Daten-Tabelle (sortierbar, paginiert), Rollen-/Permission-Bundle-Matrix, Session-Liste mit Revoke-Button, 2FA-Status-Badge, Reason-Pflicht-Dialog (Begründung erzwungen), Impersonate-Warn-Banner, Flag-Effektiv-Statistik-Kachel (aktiv/inaktiv-Zähler), Filter-Regel-Editor mit Live-Match-Vorschau-Liste, Bulk-Override-Bestätigung mit betroffener-Tenant-Anzahl, Audit-Timeline (Actor/Reason/Ziel), Lead-Inbox/-Detail/-Source-Verwaltung, getrennte Deal-Kanban-Ansicht, Empty-/Loading-/Permission-Denied-States (Klartext).
## Davids Delta (David füllt aus)
@@ -47,5 +49,5 @@ Daten-Tabelle (sortierbar, paginiert), Rollen-/Permission-Bundle-Matrix, Session
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] Plane-Ticket (VR-P28a / VA-P28b) aktualisiert:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (`R-LEADS` / `VR-P28a` / `VA-P28b`) aktualisiert:
@@ -1,7 +1,7 @@
# Designer-Brief · P29 — Help-Center & Help-Desk
**Phase:** 29/34 · **Module:** M38/M39 (M172–M175) · **Owner-Dev:** Akeshan (VA-P29) · **Designer:** David (D-Help)
**Quellen:** `ROADMAP-V2.md` §v2-P9 · `ROADMAP.md` §Phase 29 · `_bmad-output/specs/M38-help-center.md` · `_bmad-output/specs/M39-help-desk.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Öffentliche Help-Routen + In-App-Widget + interne Admin-Flächen.
> 🔵 **Bewusst klein (Phase 1):** Help-Center = Markdown-Artikel im Repo via Git-PRs (kein Editor-UI), Build-Time-Index, ~10–20 Artikel, primär Deutsch. Help-Desk = Email-Ticket-System basic + In-App-Feedback-Widget → landet im Plattform-Admin (kein User-facing-Status-Tracking, kein Live-Chat in Phase 1). `Feedback` liegt im Plattform-Admin-Datenraum (kein Tenant-RLS, App-Code permission-gegated). Help-Artikel werden rückwirkend RAG-Korpus für P25/v2-P4.
@@ -45,5 +45,5 @@ Such-Eingabe mit Auto-Suggest, Kategorie-Kacheln/-Liste, Artikel-Renderer (Markd
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (VA-P29) aktualisiert:
@@ -1,7 +1,7 @@
# Designer-Brief · P30 — Dashboard-Deluxe & Querschnitt
**Phase:** 30/34 · **Module:** M20/M22/M30 (M149/M150/M117/M029) · **Owner-Dev:** Akeshan (VA-P30a/b) · **Designer:** David (D-Querschnitt)
**Quellen:** `ROADMAP-V2.md` §v2-P10 · `ROADMAP.md` §Phase 30 · `_bmad-output/specs/M20-dashboard.md` · `_bmad-output/specs/M22-notifications.md` · `_bmad-output/specs/M30-i18n.md`
**Aktive Quellen:** zugehörige Ticket-Docs · `ROADMAP.md`/`ROADMAP-V2.md` · `REQUIREMENTS.md` · `ENTITY-MODEL.md`.
**Subframe:** Pflicht je Route. Querschnitts-Komfort über bestehende v1-Flächen.
> 🔵 **Delta-Phase, kein Neubau:** M20/M22/M30 sind großteils v1-fähig (Dashboard/Widget-Registry voll gebaut, notify() vorhanden, i18n-Library + DE-Locale da). P30 baut nur das **Komfort-/Tiefen-Delta**: anpassbare Dashboards + Export, Notification-Bündelung + Quiet-Hours, Sprach-Wechsler + EN-Locale. **HR-Drittanbieter (M138) ist NICHT Teil dieses Briefs** — das ist eine eigene Phase (P34); hier nur Dashboard/Notifications/i18n.
@@ -44,5 +44,5 @@ Anpassbares Dashboard-Grid (Drag/Resize-Handles), Widget-Catalog/-Picker (permis
## Dev-Nachzug (wir nach Davids Delta)
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
- [ ] REQUIREMENTS/ROADMAP nachgezogen:
- [ ] Plane-Ticket (VA-P30a/b) aktualisiert:
Loaded 100 of 5955 files, more files were not shown because too many files have changed in this diff. Show more