Refresh HiveGrid Cloud reference snapshot
This commit is contained in:
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.
|
||||
+4
@@ -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: []
|
||||
-82
@@ -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
|
||||
-74
@@ -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
|
||||
-198
@@ -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.*
|
||||
Binary file not shown.
@@ -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).*
|
||||
Binary file not shown.
Binary file not shown.
@@ -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.
|
||||
Binary file not shown.
@@ -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.*
|
||||
Binary file not shown.
@@ -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.*
|
||||
Binary file not shown.
@@ -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.
|
||||
Binary file not shown.
@@ -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.** *
|
||||
Binary file not shown.
@@ -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.*
|
||||
Binary file not shown.
@@ -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.
|
||||
Binary file not shown.
@@ -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.*
|
||||
Binary file not shown.
@@ -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).*
|
||||
Binary file not shown.
@@ -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 |
|
||||
Binary file not shown.
@@ -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.*
|
||||
Binary file not shown.
@@ -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]
|
||||
+2
-2
@@ -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:
|
||||
+6
-5
@@ -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:
|
||||
+3
-2
@@ -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:
|
||||
+3
-2
@@ -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:
|
||||
+6
-5
@@ -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:
|
||||
+5
-4
@@ -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:
|
||||
+4
-4
@@ -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:
|
||||
+3
-3
@@ -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:
|
||||
+16
-11
@@ -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:
|
||||
+9
-6
@@ -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:
|
||||
+2
-2
@@ -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:
|
||||
+2
-2
@@ -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:
|
||||
+2
-2
@@ -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:
|
||||
+2
-2
@@ -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:
|
||||
+32
-19
@@ -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.
|
||||
+8
-8
@@ -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:
|
||||
+2
-2
@@ -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:
|
||||
+2
-2
@@ -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:
|
||||
+2
-2
@@ -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:
|
||||
+24
-18
@@ -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:
|
||||
+2
-2
@@ -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:
|
||||
+11
-9
@@ -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:
|
||||
+2
-2
@@ -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:
|
||||
+2
-2
@@ -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
Reference in new issue
Block a user