Track HiveGrid Cloud planning reference
This commit is contained in:
1 parent
b3d5ea6764
commit
e341c5938a
5784 files changed
+1104929
-3
No files matched your search
@@ -1,5 +1,2 @@
|
||||
# Referenz-Codebase nicht in das Wireframe-Repo pushen.
|
||||
hivegrid-cloud/
|
||||
|
||||
# Lokaler Obsidian UI-/Tab-Zustand.
|
||||
.obsidian/workspace.json
|
||||
@@ -0,0 +1,58 @@
|
||||
.git
|
||||
.tc
|
||||
.claude
|
||||
.codex
|
||||
.cursor
|
||||
.idea
|
||||
.vscode
|
||||
.agents
|
||||
.planning
|
||||
cli-tokens
|
||||
node_modules
|
||||
**/node_modules
|
||||
.pnpm-store
|
||||
pnpm-store
|
||||
|
||||
*.log
|
||||
.DS_Store
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Repository docs and generated verification artifacts are not Docker build inputs.
|
||||
/docs
|
||||
.cache
|
||||
**/.cache
|
||||
.eslintcache
|
||||
**/.eslintcache
|
||||
.turbo
|
||||
**/.turbo
|
||||
.vite
|
||||
**/.vite
|
||||
.next
|
||||
**/.next
|
||||
.react-router
|
||||
**/.react-router
|
||||
coverage
|
||||
**/coverage
|
||||
.nyc_output
|
||||
**/.nyc_output
|
||||
tmp
|
||||
temp
|
||||
reports
|
||||
**/reports
|
||||
playwright-report
|
||||
test-results
|
||||
blob-report
|
||||
**/playwright-report
|
||||
**/test-results
|
||||
**/blob-report
|
||||
*.tsbuildinfo
|
||||
|
||||
public/build
|
||||
/build
|
||||
/apps/*/build
|
||||
apps/*/dist
|
||||
packages/*/dist
|
||||
|
||||
README.md
|
||||
@@ -0,0 +1,495 @@
|
||||
# Branding (optional overrides; defaultBrandTokens is used when these are unset)
|
||||
# BRAND_PRODUCT_NAME=Acme Ops
|
||||
# BRAND_SITE_URL=https://acme.example
|
||||
# BRAND_SUPPORT_EMAIL=support@acme.example
|
||||
# BRAND_SUPPORT_FROM_NAME=Acme Support
|
||||
# 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_FAVICON_URL=/favicon.ico
|
||||
# BRAND_MAIL_PRIMARY=#2563eb
|
||||
# BRAND_MAIL_PRIMARY_TEXT=#ffffff
|
||||
# BRAND_MAIL_BACKGROUND=#f6f8fb
|
||||
# BRAND_MAIL_LINK=#2563eb
|
||||
|
||||
# Core
|
||||
APP_NAME=ToolCTRL
|
||||
# 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/boilerplate?pgbouncer=true&connection_limit=10"
|
||||
# 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.
|
||||
CRYPTO_SECRET=
|
||||
APP_BASE_DOMAIN=localhost
|
||||
WEB_APP_HOST=app.localhost
|
||||
# Public app origin used for embed snippets, mail links, and worker-to-web callbacks.
|
||||
# APP_URL=http://app.localhost:3000
|
||||
ADMIN_APP_HOST=admin.localhost
|
||||
API_HOST=api.localhost
|
||||
# APP_PROTOCOL=http
|
||||
|
||||
# Legacy API/auth tokens
|
||||
API_ACCESS_TOKEN=
|
||||
JWT_SECRET=
|
||||
# Temporary cutover switch for plaintext API-key lookup. Secure-by-default: ships
|
||||
# disabled. Set to `true` ONLY during the hash-metadata backfill window, then set
|
||||
# back to `false` once the backfill is verified.
|
||||
API_KEY_LEGACY_PLAINTEXT_FALLBACK=false
|
||||
|
||||
# Local development
|
||||
# Set to true only for disposable local databases when you want sample tenants/users.
|
||||
# SEED_DEMO_DATA=true
|
||||
# DEMO_USER is read only when NODE_ENV=development.
|
||||
# DEMO_USER=admin@email.com:password
|
||||
# Production seed bootstrap credentials. Required for `NODE_ENV=production pnpm seed`.
|
||||
# SEED_ADMIN_EMAIL=admin@example.com
|
||||
# SEED_ADMIN_PASSWORD=replace-with-production-bootstrap-password
|
||||
# WEBHOOKS_URL=https://...ngrok-free.app
|
||||
|
||||
# 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).
|
||||
STORAGE_ENDPOINT=
|
||||
STORAGE_REGION=
|
||||
STORAGE_BUCKET=
|
||||
STORAGE_ACCESS_KEY_ID=
|
||||
STORAGE_SECRET_ACCESS_KEY=
|
||||
STORAGE_SESSION_TOKEN=
|
||||
STORAGE_PUBLIC_BASE_URL=
|
||||
# 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
|
||||
|
||||
# Billing
|
||||
STRIPE_SK=
|
||||
STRIPE_WEBHOOK_SIGNING_SECRET=
|
||||
STRIPE_ACCOUNT_COUNTRY=US
|
||||
|
||||
# Worker delivery credentials for queued transactional email (toolctrl.email -> Mailjet)
|
||||
MAILJET_API_KEY=
|
||||
MAILJET_SECRET_KEY=
|
||||
MAILJET_FROM_EMAIL=
|
||||
# MAILJET_FROM_NAME=
|
||||
# Inbound Mailjet event webhook Basic-Auth password (api runtime). Callback URL: https://mailjet:SECRET@api.example.com/v1/email-sequences/mailjet/webhooks
|
||||
# MAILJET_WEBHOOK_SECRET=
|
||||
SUPPORT_EMAIL=
|
||||
COMPANY_NAME=
|
||||
COMPANY_ADDRESS=
|
||||
|
||||
# Contact and newsletter
|
||||
INTEGRATIONS_CONTACT_FORMSPREE=
|
||||
|
||||
# Analytics (First-Party-Ingestion-Token; Google Analytics wurde EU-sterilisiert entfernt — R-P1a)
|
||||
ANALYTICS_TOKEN=
|
||||
|
||||
# mCaptcha (self-hosted PoW captcha — see infra/mcaptcha/README.md). Public bits
|
||||
# (instance URL + per-surface sitekeys) are safe to expose; the account secret is
|
||||
# server-only. Verification fails open by default (CAPTCHA_FAIL_OPEN).
|
||||
MCAPTCHA_INSTANCE_URL=
|
||||
MCAPTCHA_ACCOUNT_SECRET=
|
||||
MCAPTCHA_SITEKEY_LOGIN=
|
||||
MCAPTCHA_SITEKEY_FORMS=
|
||||
MCAPTCHA_SITEKEY_BOOKING=
|
||||
CAPTCHA_FAIL_OPEN=true
|
||||
AUTH_MAGIC_LINK_ENABLED=false
|
||||
AUTH_MAGIC_LINK_TOKEN_TTL_MINUTES=15
|
||||
|
||||
# Optional notification-provider diagnostics
|
||||
NOTIFICATIONS_NOVU_API_KEY=
|
||||
|
||||
# Queue and browser-backed workers
|
||||
WORKER_ENABLED=false
|
||||
# Worker queue group — one of general | mail | import | webhook | plugin. Required when
|
||||
# WORKER_ENABLED=true. Each docker-compose / K8s replica sets exactly one group
|
||||
# and that determines which BullMQ queues the process subscribes to. See
|
||||
# docs/ops/worker-queues.md.
|
||||
# WORKER_QUEUE_GROUP=general
|
||||
# General worker workflow-trigger executor. Mode `http` uses the signed web
|
||||
# bridge and falls back to APP_URL when URL is unset. Mode `hybrid` canaries the
|
||||
# worker-native runner with HTTP fallback. Mode `native` is opt-in for supported
|
||||
# safe-core workflows: manual/event triggers, if/switch, httpRequest, log,
|
||||
# alertUser, doNothing, rowGet, iterator, variable, email, and single-boundary
|
||||
# waitForInput continuation resumes.
|
||||
# WORKFLOW_TRIGGER_EXECUTOR_MODE=http
|
||||
# WORKFLOW_TRIGGER_EXECUTOR_URL=
|
||||
# API_ACCESS_TOKEN must match the web runtime token when http/hybrid mode is used.
|
||||
# WORKFLOW_TRIGGER_EXECUTOR_TIMEOUT_MS=30000
|
||||
# WORKFLOW_TRIGGER_OUTBOX_ENABLED=true
|
||||
# WORKFLOW_TRIGGER_OUTBOX_CONCURRENCY=5
|
||||
# WORKFLOW_TRIGGER_OUTBOX_REQUIRED=false
|
||||
# Per-group concurrency (only the matching group's value is read at runtime).
|
||||
# Defaults: general=10, mail=5, import=1, webhook=20, plugin=5.
|
||||
# WORKER_CONCURRENCY_GENERAL=10
|
||||
# WORKER_CONCURRENCY_MAIL=5
|
||||
# WORKER_CONCURRENCY_IMPORT=1
|
||||
# WORKER_CONCURRENCY_WEBHOOK=20
|
||||
# WORKER_CONCURRENCY_PLUGIN=5
|
||||
# Health HTTP port for /healthz and /readyz (per-worker). Defaults to 9100;
|
||||
# the five-service worker layout uses 9101-9105.
|
||||
# WORKER_HEALTH_PORT=9100
|
||||
# WORKER_HEALTH_HOST=0.0.0.0
|
||||
# Redis connection pool size advisory (forwarded to ioredis). Defaults differ
|
||||
# per group: general/mail=4, import=2, webhook=8, plugin=4.
|
||||
# WORKER_REDIS_POOL_SIZE=
|
||||
EXPORT_RETENTION_QUEUE_ENABLED=false
|
||||
IMPORT_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
|
||||
OUTBOX_DISPATCHER_REQUIRED=false
|
||||
OUTBOX_DISPATCH_BATCH_SIZE=100
|
||||
OUTBOX_DISPATCH_CONCURRENCY=10
|
||||
OUTBOX_DISPATCH_INTERVAL_MS=1000
|
||||
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.
|
||||
# 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
|
||||
# the only consistency mechanism). See docs/architecture/two-tier-cache.md.
|
||||
CACHE_INVALIDATION_ENABLED=true
|
||||
CACHE_L1_TTL_SECONDS=300
|
||||
# API idempotency-key storage backend. Default "prisma" keeps reservations in Postgres (multi-replica-safe).
|
||||
# Set "shared-store" to back them with Redis instead (keeps the primary DB cooler; Redis TTL handles eviction).
|
||||
IDEMPOTENCY_BACKEND=prisma
|
||||
# Headless browser runtime (Playwright/Puppeteer-as-a-service) used by worker-backed browser sessions.
|
||||
# Leave empty for local dev; set in production when workflow steps need real browser automation.
|
||||
BROWSER_RUNTIME_URL=
|
||||
BROWSER_RUNTIME_API_KEY=
|
||||
BROWSER_SESSION_TIMEOUT_MS=60000
|
||||
|
||||
# IP enrichment providers used by audit/log enrichment. Pick ONE; if both are set IPStack is preferred.
|
||||
# IPStack (ipstack.com) — paid tiers required for HTTPS and bulk lookups.
|
||||
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
|
||||
# authenticates with; it is a server-side secret — never expose it to browsers.
|
||||
# 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_API_KEY=devkey
|
||||
# MEILI_ENV=development
|
||||
# Toggle search backend hot-path strategy. `meilisearch` (default) goes
|
||||
# through the wrapper with automatic SQL-LIKE fallback on connection
|
||||
# errors; `sql` forces every read onto the legacy fallback (emergency
|
||||
# switch). See docs/features/search.md#rollback.
|
||||
# SEARCH_BACKEND=meilisearch
|
||||
|
||||
# Dynamic site API keys
|
||||
# SITE_KEY_EXAMPLE_SITE=
|
||||
|
||||
# Production/runtime platform
|
||||
# NODE_ENV=production
|
||||
# DIRECT_URL: unpooled Postgres URL (port 5432, bypasses PgBouncer). Required
|
||||
# by `prisma migrate` / `db push` so prepared statements survive. Apps still
|
||||
# use DATABASE_URL (above) for runtime queries. See docs/ops/pgbouncer.md.
|
||||
# DIRECT_URL="postgres://user:pass@localhost:5432/boilerplate"
|
||||
# DATABASE_READ_URL: optional Postgres read-replica used by getReadDbClient()
|
||||
# for hot-read paths (CRM/KB listings, dashboards, public sites/portals).
|
||||
# When unset or empty, getReadDbClient() falls back to DATABASE_URL so single-
|
||||
# DB dev and self-hosted setups work without any code change. Point at the
|
||||
# replica (or a PgBouncer-fronted replica) in staging/production. Replication
|
||||
# is eventually consistent — see docs/architecture/rw-split.md.
|
||||
# DATABASE_READ_URL="postgres://read_user:pass@replica.localhost:5432/boilerplate"
|
||||
# SERVER_URL=https://app.example.com
|
||||
# VERCEL_URL=
|
||||
|
||||
# Observability (opt-in; leave commented to keep the safe noop reporter and disabled tracing)
|
||||
# SENTRY_DSN=https://public@sentry.example/1
|
||||
# API (apps/api) and Worker (apps/worker) — independent DSNs so the two
|
||||
# processes report to separate Sentry projects (boilerplate-api / boilerplate-worker).
|
||||
# SENTRY_DSN_API=https://public-api@sentry.example/3
|
||||
# SENTRY_DSN_WORKER=https://public-worker@sentry.example/4
|
||||
# SENTRY_ENVIRONMENT=production
|
||||
# SENTRY_RELEASE=
|
||||
# SENTRY_TRACES_SAMPLE_RATE=0.1
|
||||
# SENTRY_PROFILES_SAMPLE_RATE=0.0
|
||||
# OpenTelemetry (opt-in; leave commented to keep the api/worker OTel bootstrap as a no-op).
|
||||
# Endpoint examples: sentry-relay (broken on Sentry 25.12.1 self-hosted upstream nginx, see B-005),
|
||||
# OTel collector (http://otel-collector:4318/v1/traces), Tempo, Jaeger.
|
||||
# OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318/v1/traces
|
||||
# Comma-separated key=value headers forwarded with every OTLP export.
|
||||
# OTEL_EXPORTER_OTLP_HEADERS=x-sentry-auth=Sentry sentry_key=<public-key>
|
||||
# OTEL_SERVICE_NAME=boilerplate-api
|
||||
# OTEL_TRACES_SAMPLER=parentbased_traceidratio
|
||||
# OTEL_TRACES_SAMPLER_ARG=0.1
|
||||
# OTEL_LOG_LEVEL=debug
|
||||
# Browser-side OTel (Vite-bundled). VITE_OTEL_EXPORTER_OTLP_ENDPOINT must be
|
||||
# CORS-reachable from the user agent; gateway/relay MUST be rate-limited.
|
||||
# VITE_OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.example.com/v1/traces
|
||||
# VITE_OTEL_SERVICE_NAME=boilerplate-web
|
||||
# Web (apps/web) — separate Sentry project from the API/Worker stack.
|
||||
# SENTRY_DSN_WEB=https://public-web@sentry.example/2
|
||||
# VITE_SENTRY_DSN_WEB=https://public-web@sentry.example/2
|
||||
# VITE_SENTRY_RELEASE=
|
||||
# VITE_SENTRY_TRACES_SAMPLE_RATE=0.1
|
||||
# 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.
|
||||
# SENTRY_AUTH_TOKEN=
|
||||
# SENTRY_ORG=
|
||||
# SENTRY_PROJECT=boilerplate-web
|
||||
# SENTRY_URL=https://sentry.boiler.saas-ctrl.com
|
||||
|
||||
# Asset CDN (opt-in; leave commented to keep origin-relative asset URLs).
|
||||
# When set at build time, Vite emits all asset URLs prefixed with this origin
|
||||
# so the CDN (Bunny.net by default — see docs/ops/asset-cdn.md) can pull from
|
||||
# the app server and serve users from the edge. Local dev ignores the var.
|
||||
# ASSET_CDN_URL=https://cdn.boiler.saas-ctrl.com
|
||||
# Bunny.net pull-zone id used by the post-deploy purge step. CI-only.
|
||||
# BUNNY_PULL_ZONE_ID=
|
||||
# Bunny.net account-level API key for cache-purge calls. CI-only.
|
||||
# BUNNY_API_KEY=
|
||||
|
||||
# Password policy (auth.password.errors.* messages; defaults match OWASP 2024).
|
||||
# Override at deploy time to relax or tighten without a code deploy.
|
||||
# AUTH_PASSWORD_MIN_LENGTH=12
|
||||
# AUTH_PASSWORD_REQUIRE_UPPER=true
|
||||
# AUTH_PASSWORD_REQUIRE_LOWER=true
|
||||
# AUTH_PASSWORD_REQUIRE_DIGIT=true
|
||||
# AUTH_PASSWORD_REQUIRE_SPECIAL=false
|
||||
# AUTH_PASSWORD_HIBP_CHECK=true
|
||||
# AUTH_PASSWORD_HIBP_MAX_OCCURRENCES=0
|
||||
|
||||
# Prometheus metrics + /status endpoints (api, worker, web).
|
||||
# When METRICS_ENABLED=true both endpoints are mounted; /status is public,
|
||||
# /metrics requires Authorization: Bearer $METRICS_TOKEN.
|
||||
# METRICS_ENABLED=false
|
||||
# METRICS_TOKEN=
|
||||
# Worker admin HTTP server (only opened when METRICS_ENABLED=true).
|
||||
# Keep it on a private network — Prometheus only.
|
||||
# WORKER_ADMIN_PORT=9100
|
||||
# WORKER_ADMIN_HOST=0.0.0.0
|
||||
# Region tag surfaced in /status. Falls back to FLY_REGION when unset.
|
||||
# APP_REGION=
|
||||
|
||||
# Backup CLI (@toolctrl/cli). See docs/operations/backup.md for the full runbook.
|
||||
# BACKUP_S3_ENDPOINT=https://s3.example.com
|
||||
# BACKUP_S3_REGION=us-east-1
|
||||
# BACKUP_S3_BUCKET=toolctrl-backups
|
||||
# BACKUP_S3_ACCESS_KEY_ID=
|
||||
# BACKUP_S3_SECRET_ACCESS_KEY=
|
||||
# BACKUP_S3_SESSION_TOKEN=
|
||||
# BACKUP_S3_FORCE_PATH_STYLE=true
|
||||
# Encryption: age (default), gpg, or none. age REQUIRES BACKUP_AGE_PUBLIC_KEY.
|
||||
# BACKUP_ENCRYPTION=age
|
||||
# Public-key recipient for age encryption (operator generates via `age-keygen`).
|
||||
# BACKUP_AGE_PUBLIC_KEY=age1exampleexampleexampleexampleexampleexampleexampleexample
|
||||
# Identity file used for `backup:restore` and `backup:verify` decryption.
|
||||
# BACKUP_AGE_IDENTITY_FILE=/secrets/age-backup.key
|
||||
# GPG fallback key id (only used when BACKUP_ENCRYPTION=gpg).
|
||||
# BACKUP_GPG_RECIPIENT=
|
||||
# Retention policy (most-recent kept per classification).
|
||||
# BACKUP_RETENTION_DAILY=7
|
||||
# BACKUP_RETENTION_WEEKLY=4
|
||||
# BACKUP_RETENTION_MONTHLY=12
|
||||
# Set to true to include a ClickHouse BACKUP statement in `backup:create`.
|
||||
# BACKUP_INCLUDE_CLICKHOUSE=false
|
||||
|
||||
# Embeddable form widget (Phase 05 #58 — packages/form-widget).
|
||||
# FORM_WIDGET_CDN_URL serves /embed/widget.js. Falls back to APP_URL when unset.
|
||||
# Captcha on form submissions uses the shared mCaptcha instance (MCAPTCHA_* at
|
||||
# the top of this file), opt-in per form AND gated behind the
|
||||
# `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 mCaptcha instance (MCAPTCHA_*); flag is gated via
|
||||
# the `marketing-funnel-turnstile` feature flag.
|
||||
# See docs/features/marketing-funnel.md.
|
||||
# MARKETING_ALLOWED_ORIGINS=https://marketing.example.com,https://*.example.com
|
||||
# MARKETING_RATE_LIMIT_PER_MIN=5
|
||||
|
||||
# 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
|
||||
# `/register?leadId=…&token=…&plan=…` deep-links produced by
|
||||
# `signLeadToken` and verified by the register loader. Rotate by setting a
|
||||
# new value; old tokens become invalid after 7 days (default TTL).
|
||||
# LEAD_CONVERSION_ENABLED=false short-circuits both the deep-link
|
||||
# pre-fill flow and the admin "Convert to Tenant" button without rolling
|
||||
# back the migration — useful for emergency disable.
|
||||
# MARKETING_WEBHOOKS_ENABLED=false freezes the apps/worker
|
||||
# `outbox.marketing` queue — outbox events accumulate so they replay
|
||||
# automatically after the flip back to true (raise outbox retention if
|
||||
# you plan a long pause).
|
||||
# See docs/features/marketing-funnel.md.
|
||||
# LEAD_CONVERSION_SECRET=
|
||||
# LEAD_CONVERSION_ENABLED=true
|
||||
# MARKETING_WEBHOOKS_ENABLED=true
|
||||
|
||||
# Marketing-Funnel Phase 3 — email-sequence engine (Phase 05 #80).
|
||||
# MARKETING_TOKEN_SECRET signs the unsubscribe tokens embedded in every
|
||||
# sequence email's `List-Unsubscribe` header. Falls back to
|
||||
# LEAD_CONVERSION_SECRET when unset — both must be at least 32 bytes
|
||||
# (`openssl rand -hex 32`).
|
||||
# MARKETING_SEQUENCES_ENABLED must be set to true before apps/worker starts
|
||||
# the `email-sequence.step` queue, trigger handler, or sequence cron producers.
|
||||
# Keep this unset or false in production until the delayed producer, renderer,
|
||||
# and mail-send adapter follow-ups are wired and verified.
|
||||
# See docs/features/email-sequences.md.
|
||||
# MARKETING_TOKEN_SECRET=
|
||||
# MARKETING_SEQUENCES_ENABLED=false
|
||||
|
||||
# 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
|
||||
# `onAuthenticate`; secret must match across web + hocuspocus deploys.
|
||||
# Min 32 bytes of entropy (`openssl rand -hex 32`).
|
||||
# VITE_HOCUSPOCUS_URL is the public WebSocket URL the browser connects to
|
||||
# (e.g. `wss://collab.example.com`). When unset, the Novel-Editor mounts
|
||||
# without collab extensions — graceful single-user fallback.
|
||||
# HOCUSPOCUS_URL is the server-internal WebSocket endpoint exposed by the
|
||||
# hocuspocus container (defaults to ws://hocuspocus:1234 in docker).
|
||||
# HOCUSPOCUS_MAX_PAYLOAD_BYTES caps the Y.js state we persist per doc.
|
||||
# Activation also requires the `realtime-collab-enabled` feature flag.
|
||||
# See docs/features/realtime-collab.md.
|
||||
# HOCUSPOCUS_AUTH_SECRET=
|
||||
# VITE_HOCUSPOCUS_URL=wss://collab.example.com
|
||||
# HOCUSPOCUS_URL=ws://hocuspocus:1234
|
||||
# HOCUSPOCUS_PORT=1234
|
||||
# HOCUSPOCUS_HOST=0.0.0.0
|
||||
# HOCUSPOCUS_MAX_PAYLOAD_BYTES=10485760
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Admin-Panel SSO via Authentik (Phase 09 #82 — apps/web/app/modules/admin-sso)
|
||||
# ---------------------------------------------------------------------------
|
||||
# AUTHENTIK_ISSUER_URL is the OIDC issuer published by the Authentik
|
||||
# `toolctrl-admin-panel` provider (matches the `iss` claim in ID-tokens).
|
||||
# Typically `https://auth.<domain>/application/o/toolctrl-admin-panel/`.
|
||||
# AUTHENTIK_ADMIN_CLIENT_ID must equal the blueprint client_id
|
||||
# (`toolctrl-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_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
|
||||
# the browser to after end_session_endpoint; default falls back to the
|
||||
# admin login page with `?logged_out=1`.
|
||||
#
|
||||
# ADMIN_FALLBACK_LOGIN_ENABLED gates the email/password emergency path.
|
||||
# When `false` (default) the admin login page hides the password form
|
||||
# entirely. ADMIN_FALLBACK_LOGIN_EMAILS is a comma-separated allowlist of
|
||||
# admin emails that may use the fallback when the flag is on — keep it
|
||||
# short (1-2 bootstrap accounts max). Each fallback login emits an
|
||||
# `admin.login.fallback.success` audit event tagged severity=warn.
|
||||
# See docs/operations/admin-sso.md.
|
||||
# AUTHENTIK_ISSUER_URL=https://auth.example.com/application/o/toolctrl-admin-panel/
|
||||
# AUTHENTIK_ADMIN_CLIENT_ID=toolctrl-admin-panel
|
||||
# AUTHENTIK_ADMIN_CLIENT_SECRET=
|
||||
# AUTHENTIK_ADMIN_REDIRECT_URI=https://admin.example.com/auth/admin/callback
|
||||
# AUTHENTIK_ADMIN_POST_LOGOUT_REDIRECT_URI=https://admin.example.com/admin/login?logged_out=1
|
||||
# ADMIN_FALLBACK_LOGIN_ENABLED=false
|
||||
# ADMIN_FALLBACK_LOGIN_EMAILS=
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Capacitor mobile + push backend (Phase 08 #65 — apps/mobile + apps/worker)
|
||||
# ---------------------------------------------------------------------------
|
||||
# FCM_SERVICE_ACCOUNT_JSON holds the Firebase Cloud Messaging service account
|
||||
# credentials used by the worker push job to dispatch Android notifications.
|
||||
# Accepted formats: (1) raw JSON, (2) base64-encoded JSON. Generate via the
|
||||
# Firebase console (Project settings → Service accounts → Generate new
|
||||
# private key). NEVER commit this — it grants full FCM send rights.
|
||||
#
|
||||
# APNS_KEY is the PEM contents of the .p8 Apple Push Notification Service
|
||||
# signing key (a standard PKCS#8 PEM block). APNS_KEY_ID is the 10-character
|
||||
# key id shown in the Apple Developer console next to the generated .p8 file.
|
||||
# APNS_TEAM_ID is the 10-character developer team id.
|
||||
# APNS_BUNDLE_ID defaults to de.toolctrl.app (matches capacitor.config.ts
|
||||
# > appId); override only when shipping a re-branded fork.
|
||||
#
|
||||
# MOBILE_LIVE_RELOAD_URL is a dev-only convenience: when set, apps/mobile
|
||||
# emits a Capacitor `server.url` in capacitor.config.ts so the native shell
|
||||
# loads the running web dev server (typically http://192.168.x.x:3000)
|
||||
# instead of the bundled webDir. Leave empty for production builds.
|
||||
# See docs/operations/capacitor.md.
|
||||
# FCM_SERVICE_ACCOUNT_JSON=
|
||||
# APNS_KEY=
|
||||
# APNS_KEY_ID=
|
||||
# APNS_TEAM_ID=
|
||||
# APNS_BUNDLE_ID=de.toolctrl.app
|
||||
# MOBILE_LIVE_RELOAD_URL=
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# AI-cost Phase 3 — Stripe overage billing (apps/worker cron + reconcile)
|
||||
# ---------------------------------------------------------------------------
|
||||
# AI_OVERAGE_SUBMISSION_ENABLED is the master killswitch for the nightly
|
||||
# Stripe Billing Meter event submitter. When `false` (or `0`), AI events are still
|
||||
# marked `isOverage = true` + `markedUpCostCents` populated, but the cron
|
||||
# skips Stripe. Default: enabled when STRIPE_SK is configured. Use this to
|
||||
# pause submissions during an incident; the next enabled run backfills via
|
||||
# `stripeReportedAt IS NULL`.
|
||||
#
|
||||
# Per-plan markup multiplier + Stripe identifiers ship in
|
||||
# `packages/entitlements/src/ai-overage.ts` (`standardAIOverageDefaults`).
|
||||
# Configure live Stripe ids via /admin/settings/pricing/ai-overage (admin
|
||||
# UI writes an audit log) and/or per-tenant overrides on
|
||||
# `Tenant.aiQuotaOverrideJson` — see docs/features/ai-cost-billing.md.
|
||||
# AI_OVERAGE_SUBMISSION_ENABLED=true
|
||||
|
||||
# Phase 06: Plugin output sanitization (strict|moderate|off)
|
||||
PLUGIN_OUTPUT_SANITIZATION_STRICTNESS=moderate
|
||||
|
||||
# Phase 06: production runtime rollout gate. Leave false until the
|
||||
# external plugin runtime security sign-off is complete. Production
|
||||
# install/grant/enable and plugin workers fail closed unless true.
|
||||
PLUGIN_RUNTIME_PRODUCTION_ENABLED=false
|
||||
# Optional fail-closed switch for worker-general plugin hook fanout. In
|
||||
# production with PLUGIN_RUNTIME_PRODUCTION_ENABLED=true and Redis present,
|
||||
# worker-general already treats plugin hook fanout as required; set this only
|
||||
# to force the same startup behavior in staging/canary environments.
|
||||
# PLUGIN_HOOK_FANOUT_REQUIRED=false
|
||||
|
||||
# Phase 06: plugin worker sandbox limits. Trusted keys are a CSV of hex
|
||||
# Ed25519 public keys; empty fails signature verification closed.
|
||||
# PLUGIN_TRUSTED_PUBLIC_KEYS=
|
||||
PLUGIN_MAX_FUEL=1000000
|
||||
PLUGIN_MAX_MEMORY_MB=64
|
||||
PLUGIN_MAX_WALL_CLOCK_MS=5000
|
||||
PLUGIN_RATE_LIMIT_PER_MINUTE=100
|
||||
PLUGIN_RATE_LIMIT_WINDOW_SECONDS=60
|
||||
|
||||
# Phase 06: PluginCapabilityUse audit retention (days)
|
||||
PLUGIN_AUDIT_RETENTION_DAYS=90
|
||||
PLUGIN_AUDIT_RETENTION_BATCH_SIZE=1000
|
||||
PLUGIN_AUDIT_RETENTION_MAX_BATCHES=100
|
||||
PLUGIN_AUDIT_RETENTION_CRON="0 3 * * *"
|
||||
|
||||
# Phase 06: optional override for host version used in plugin compat check (default: package.json version)
|
||||
PLUGIN_HOST_VERSION_OVERRIDE=
|
||||
|
||||
# Phase 06 / F-005 Phase B: dev escape hatch to skip the on-disk binary
|
||||
# signature verify at install time. MUST NOT be set in production.
|
||||
PLUGIN_INSTALL_SKIP_BINARY_VERIFY=false
|
||||
|
||||
# Phase 06 / F-001: explicit per-tenant capability consent.
|
||||
# When "true" (default in production), enablePlugin refuses to flip
|
||||
# Plugin.enabled=true until every manifest-declared capability has a
|
||||
# matching TenantPluginCapabilityGrant row. Set "false" for dev /
|
||||
# integration-test environments that pre-date F-001.
|
||||
PLUGIN_REQUIRE_CAPABILITY_CONSENT=true
|
||||
|
||||
# Phase 06 / F-011: per-tenant install rate limit (sliding window, 60s).
|
||||
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
|
||||
@@ -0,0 +1,74 @@
|
||||
# REQUIRED CORE
|
||||
|
||||
flyctl secrets set APP_NAME=YOUR_APP_NAME \
|
||||
DATABASE_URL=postgres://{USER}:{PASSWORD}@{HOST}:{PORT}/{DATABASE} \
|
||||
SESSION_SECRET=<session-secret> \
|
||||
CRYPTO_SECRET=<crypto-secret> \
|
||||
API_ACCESS_TOKEN=<api-access-token> \
|
||||
JWT_SECRET=<jwt-secret> \
|
||||
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 \
|
||||
APP_PROTOCOL=https \
|
||||
--app YOUR_APP_NAME
|
||||
|
||||
# APP AND PROVIDER SECRETS
|
||||
|
||||
flyctl secrets set APP_NAME=YOUR_APP_NAME \
|
||||
DATABASE_URL=postgres://{USER}:{PASSWORD}@{HOST}:{PORT}/{DATABASE} \
|
||||
SESSION_SECRET=<session-secret> \
|
||||
CRYPTO_SECRET=<crypto-secret> \
|
||||
API_ACCESS_TOKEN=<api-access-token> \
|
||||
JWT_SECRET=<jwt-secret> \
|
||||
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 \
|
||||
APP_PROTOCOL=https \
|
||||
STORAGE_ENDPOINT=https://s3.your-domain.invalid \
|
||||
STORAGE_REGION=us-east-1 \
|
||||
STORAGE_BUCKET=toolctrl-exports \
|
||||
STORAGE_ACCESS_KEY_ID=<storage-access-key-id> \
|
||||
STORAGE_SECRET_ACCESS_KEY=<storage-secret-access-key> \
|
||||
STORAGE_SESSION_TOKEN= \
|
||||
STORAGE_PUBLIC_BASE_URL=https://cdn.your-domain.invalid \
|
||||
STORAGE_FORCE_PATH_STYLE=false \
|
||||
STRIPE_SK=<stripe-secret-key> \
|
||||
STRIPE_WEBHOOK_SIGNING_SECRET=<stripe-webhook-signing-secret> \
|
||||
STRIPE_ACCOUNT_COUNTRY=US \
|
||||
MAILJET_API_KEY=<mailjet-api-key> \
|
||||
MAILJET_SECRET_KEY=<mailjet-secret-key> \
|
||||
MAILJET_FROM_EMAIL=notifications@example.com \
|
||||
MAILJET_FROM_NAME=ToolCTRL \
|
||||
SUPPORT_EMAIL=support@example.com \
|
||||
COMPANY_NAME=ExampleCo \
|
||||
COMPANY_ADDRESS="Example address" \
|
||||
INTEGRATIONS_CONTACT_FORMSPREE=https://formspree.io/f/example \
|
||||
ANALYTICS_TOKEN=<analytics-token> \
|
||||
MCAPTCHA_INSTANCE_URL=<mcaptcha-instance-url> \
|
||||
MCAPTCHA_ACCOUNT_SECRET=<mcaptcha-account-secret> \
|
||||
MCAPTCHA_SITEKEY_LOGIN=<mcaptcha-sitekey-login> \
|
||||
MCAPTCHA_SITEKEY_FORMS=<mcaptcha-sitekey-forms> \
|
||||
MCAPTCHA_SITEKEY_BOOKING=<mcaptcha-sitekey-booking> \
|
||||
AUTH_MAGIC_LINK_ENABLED=false \
|
||||
AUTH_MAGIC_LINK_TOKEN_TTL_MINUTES=15 \
|
||||
NOTIFICATIONS_NOVU_API_KEY=<novu-api-key> \
|
||||
EXPORT_RETENTION_QUEUE_ENABLED=false \
|
||||
IMPORT_QUEUE_ENABLED=false \
|
||||
BULLMQ_REDIS_URL=redis://default:<redis-password>@redis.your-domain.invalid:6379/0 \
|
||||
BROWSER_RUNTIME_URL=https://browser-runtime.your-domain.invalid \
|
||||
BROWSER_RUNTIME_API_KEY=<browser-runtime-api-key> \
|
||||
BROWSER_SESSION_TIMEOUT_MS=60000 \
|
||||
IPSTACK_API_KEY=<ipstack-api-key> \
|
||||
IPAPIIS_API_KEY=<ipapiis-api-key> \
|
||||
--app YOUR_APP_NAME
|
||||
|
||||
# REDIS_URL is a fallback only when BULLMQ_REDIS_URL is absent; keep it commented if a platform injects it.
|
||||
# REDIS_URL=redis://default:<redis-password>@redis.example.com:6379/0
|
||||
|
||||
# PORTAL SECRETS
|
||||
|
||||
flyctl secrets set PORTAL_SERVER_URL=https://portal.your-domain.invalid \
|
||||
PORTAL_SERVER_FLY_TOKEN="FlyV1 <portal-token>" \
|
||||
--app YOUR_APP_NAME
|
||||
@@ -0,0 +1,47 @@
|
||||
# Core local development
|
||||
APP_NAME=ToolCTRL Local
|
||||
DATABASE_URL="file:./dev.db?connection_limit=1&connect_timeout=30"
|
||||
SESSION_SECRET=replace-with-local-session-secret
|
||||
CRYPTO_SECRET=replace-with-local-crypto-secret
|
||||
APP_BASE_DOMAIN=localhost:3000
|
||||
WEB_APP_HOST=app.localhost:3000
|
||||
ADMIN_APP_HOST=admin.localhost:3000
|
||||
API_HOST=api.localhost:3001
|
||||
APP_PROTOCOL=http
|
||||
|
||||
# Legacy API/auth tokens
|
||||
API_ACCESS_TOKEN=replace-with-local-api-token
|
||||
JWT_SECRET=replace-with-local-jwt-secret
|
||||
|
||||
# Local convenience
|
||||
SEED_DEMO_DATA=true
|
||||
# Matches the local seed admin only; ignored outside NODE_ENV=development.
|
||||
DEMO_USER=admin@email.com:password
|
||||
# WEBHOOKS_URL=https://...ngrok-free.app
|
||||
|
||||
# Optional local providers; MailerSend is the default transactional runtime provider
|
||||
# STORAGE_ENDPOINT=
|
||||
# STORAGE_REGION=
|
||||
# STORAGE_BUCKET=
|
||||
# STORAGE_ACCESS_KEY_ID=
|
||||
# STORAGE_SECRET_ACCESS_KEY=
|
||||
# STORAGE_SESSION_TOKEN=
|
||||
# STORAGE_PUBLIC_BASE_URL=
|
||||
# STORAGE_FORCE_PATH_STYLE=false
|
||||
# STRIPE_SK=
|
||||
# STRIPE_ACCOUNT_COUNTRY=US
|
||||
# MAILJET_API_KEY=
|
||||
# MAILJET_SECRET_KEY=
|
||||
# MAILJET_FROM_EMAIL=
|
||||
# MAILJET_FROM_NAME=
|
||||
# WORKER_ENABLED=false
|
||||
# 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=redis://localhost:6379/0
|
||||
# BROWSER_RUNTIME_URL=
|
||||
# BROWSER_RUNTIME_API_KEY=
|
||||
# BROWSER_SESSION_TIMEOUT_MS=60000
|
||||
# ANALYTICS_TOKEN=
|
||||
# SITE_KEY_EXAMPLE_SITE=
|
||||
@@ -0,0 +1,96 @@
|
||||
# Required core
|
||||
APP_NAME=ToolCTRL
|
||||
# DATABASE_URL points at PgBouncer (port 6432) for application traffic.
|
||||
# Append `?pgbouncer=true&connection_limit=10` so Prisma disables prepared-
|
||||
# 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"
|
||||
SESSION_SECRET=
|
||||
CRYPTO_SECRET=
|
||||
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
|
||||
APP_PROTOCOL=https
|
||||
|
||||
# Required for current legacy API/auth endpoints
|
||||
API_ACCESS_TOKEN=
|
||||
JWT_SECRET=
|
||||
API_KEY_LEGACY_PLAINTEXT_FALLBACK=false
|
||||
|
||||
# Required if public analytics ingestion is enabled
|
||||
ANALYTICS_TOKEN=
|
||||
|
||||
# Production/runtime platform
|
||||
NODE_ENV=production
|
||||
# DIRECT_URL: unpooled Postgres URL (port 5432, bypasses PgBouncer). Required
|
||||
# so Prisma Migrate keeps prepared statements alive. See docs/ops/pgbouncer.md.
|
||||
DIRECT_URL="postgres://{USER}:{PASSWORD}@{POSTGRES_HOST}:5432/{DATABASE}"
|
||||
# Optional Postgres read-replica for hot-read paths (CRM/KB listings,
|
||||
# dashboards, public sites/portals). Falls back to DATABASE_URL when
|
||||
# unset — single-DB deploys keep working unchanged. Use a read-only DB
|
||||
# user (GRANT SELECT) and ideally a PgBouncer-fronted replica endpoint.
|
||||
# Replication is eventually consistent. See docs/architecture/rw-split.md.
|
||||
# DATABASE_READ_URL="postgres://{READ_USER}:{PASSWORD}@{REPLICA_HOST}:6432/{DATABASE}?pgbouncer=true&connection_limit=10"
|
||||
# SERVER_URL=https://app.example.com
|
||||
|
||||
# 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
|
||||
|
||||
# Optional providers; MailerSend is the default transactional runtime provider
|
||||
STORAGE_ENDPOINT=
|
||||
STORAGE_REGION=
|
||||
STORAGE_BUCKET=
|
||||
STORAGE_ACCESS_KEY_ID=
|
||||
STORAGE_SECRET_ACCESS_KEY=
|
||||
STORAGE_SESSION_TOKEN=
|
||||
STORAGE_PUBLIC_BASE_URL=
|
||||
STORAGE_FORCE_PATH_STYLE=false
|
||||
STRIPE_SK=
|
||||
STRIPE_WEBHOOK_SIGNING_SECRET=
|
||||
STRIPE_ACCOUNT_COUNTRY=US
|
||||
MAILJET_API_KEY=
|
||||
MAILJET_SECRET_KEY=
|
||||
MAILJET_FROM_EMAIL=
|
||||
# MAILJET_FROM_NAME=
|
||||
MAILJET_WEBHOOK_SECRET=
|
||||
SUPPORT_EMAIL=
|
||||
COMPANY_NAME=
|
||||
COMPANY_ADDRESS=
|
||||
INTEGRATIONS_CONTACT_FORMSPREE=
|
||||
MCAPTCHA_INSTANCE_URL=
|
||||
MCAPTCHA_ACCOUNT_SECRET=
|
||||
MCAPTCHA_SITEKEY_LOGIN=
|
||||
MCAPTCHA_SITEKEY_FORMS=
|
||||
MCAPTCHA_SITEKEY_BOOKING=
|
||||
CAPTCHA_FAIL_OPEN=true
|
||||
AUTH_MAGIC_LINK_ENABLED=false
|
||||
AUTH_MAGIC_LINK_TOKEN_TTL_MINUTES=15
|
||||
NOTIFICATIONS_NOVU_API_KEY=
|
||||
# Set WORKER_ENABLED=true only on the worker resource. Leave it unset for web/API resources.
|
||||
# WORKER_ENABLED=false
|
||||
EXPORT_RETENTION_QUEUE_ENABLED=false
|
||||
IMPORT_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=redis://localhost:6379/0
|
||||
|
||||
# Plugin worker runtime. Set these on WORKER_QUEUE_GROUP=plugin resources.
|
||||
# PLUGIN_TRUSTED_PUBLIC_KEYS=
|
||||
PLUGIN_MAX_FUEL=1000000
|
||||
PLUGIN_MAX_MEMORY_MB=64
|
||||
PLUGIN_MAX_WALL_CLOCK_MS=5000
|
||||
PLUGIN_RATE_LIMIT_PER_MINUTE=100
|
||||
PLUGIN_RATE_LIMIT_WINDOW_SECONDS=60
|
||||
PLUGIN_OUTPUT_SANITIZATION_STRICTNESS=moderate
|
||||
|
||||
BROWSER_RUNTIME_URL=
|
||||
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=
|
||||
@@ -0,0 +1,47 @@
|
||||
# Non-secret test fixture used by env-contract checks.
|
||||
# Values are deterministic placeholders only; never copy production secrets here.
|
||||
APP_NAME=ToolCTRL Test
|
||||
DATABASE_URL="file:./test.db?connection_limit=1&connect_timeout=30"
|
||||
SESSION_SECRET=test-session-secret-placeholder
|
||||
CRYPTO_SECRET=test-crypto-secret-placeholder
|
||||
APP_BASE_DOMAIN=localhost.test
|
||||
WEB_APP_HOST=app.localhost.test
|
||||
ADMIN_APP_HOST=admin.localhost.test
|
||||
API_HOST=api.localhost.test
|
||||
APP_PROTOCOL=http
|
||||
|
||||
# Legacy API/auth tokens
|
||||
API_ACCESS_TOKEN=test-api-access-token-placeholder
|
||||
JWT_SECRET=test-jwt-secret-placeholder
|
||||
|
||||
# Test-safe platform/runtime values
|
||||
NODE_ENV=test
|
||||
PORT=3000
|
||||
HOST=127.0.0.1
|
||||
API_PORT=3001
|
||||
WORKER_ENABLED=false
|
||||
EXPORT_RETENTION_QUEUE_ENABLED=false
|
||||
IMPORT_QUEUE_ENABLED=false
|
||||
BULLMQ_REDIS_URL=redis://localhost:6379/15
|
||||
BROWSER_RUNTIME_URL=http://localhost:9222
|
||||
BROWSER_RUNTIME_API_KEY=test-browser-runtime-api-key-placeholder
|
||||
BROWSER_SESSION_TIMEOUT_MS=1000
|
||||
STORAGE_ENDPOINT=https://storage.example.test
|
||||
STORAGE_REGION=us-east-1
|
||||
STORAGE_BUCKET=test-storage
|
||||
STORAGE_ACCESS_KEY_ID=test-storage-access-key
|
||||
STORAGE_SECRET_ACCESS_KEY=test-storage-secret-key
|
||||
STORAGE_SESSION_TOKEN=
|
||||
STORAGE_PUBLIC_BASE_URL=
|
||||
STORAGE_FORCE_PATH_STYLE=true
|
||||
|
||||
# Safe optional provider placeholders used by contract tests
|
||||
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
|
||||
ANALYTICS_TOKEN=test-analytics-token-placeholder
|
||||
STRIPE_ACCOUNT_COUNTRY=US
|
||||
SITE_KEY_EXAMPLE_SITE=test-site-key-placeholder
|
||||
@@ -0,0 +1,7 @@
|
||||
!.eslintrc
|
||||
!app/utils/services/.server/
|
||||
!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
|
||||
@@ -0,0 +1,298 @@
|
||||
{
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"es2022": true
|
||||
},
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"plugins": ["@typescript-eslint", "import", "jsx-a11y", "react-hooks"],
|
||||
"extends": ["plugin:jsx-a11y/recommended"],
|
||||
"ignorePatterns": [
|
||||
".react-router/",
|
||||
"apps/web/.react-router/",
|
||||
"app/",
|
||||
"app/generated/",
|
||||
"apps/web/app/generated/",
|
||||
"build/",
|
||||
"coverage/",
|
||||
"dist/",
|
||||
"node_modules/",
|
||||
"!apps/web/app/utils/services/.server/",
|
||||
"!apps/web/app/utils/services/.server/urlService.test.ts",
|
||||
"!apps/web/app/utils/services/apiService.entity-resolver.test.ts",
|
||||
"!apps/web/app/utils/db/users.mfa.test.ts",
|
||||
"!utils/services/.server/",
|
||||
"!utils/services/.server/urlService.test.ts",
|
||||
"!utils/services/apiService.entity-resolver.test.ts"
|
||||
],
|
||||
"rules": {
|
||||
"no-console": "warn",
|
||||
"no-debugger": "error",
|
||||
"jsx-a11y/no-autofocus": "off",
|
||||
"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",
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": [
|
||||
{
|
||||
"group": [
|
||||
"~/generated/prisma/client/*",
|
||||
"app/generated/prisma/client/*",
|
||||
"apps/web/app/generated/prisma/client/*",
|
||||
"@prisma/client",
|
||||
"@prisma/client/*"
|
||||
],
|
||||
"message": "Import Prisma through @toolctrl/db package boundaries instead of generated clients."
|
||||
},
|
||||
{
|
||||
"group": ["@toolctrl/entitlements/src/*", "packages/entitlements/src/*"],
|
||||
"message": "Import entitlements through the public @toolctrl/entitlements package boundary."
|
||||
},
|
||||
{
|
||||
"group": [
|
||||
"@toolctrl/foundation/src/*",
|
||||
"packages/foundation/src/*",
|
||||
"@toolctrl/view-models/src/*",
|
||||
"packages/view-models/src/*",
|
||||
"@toolctrl/ui-app/src/*",
|
||||
"packages/ui-app/src/*",
|
||||
"@toolctrl/ui-subframe/src/*",
|
||||
"packages/ui-subframe/src/*",
|
||||
"@toolctrl/ui-mock/src/*",
|
||||
"packages/ui-mock/src/*"
|
||||
],
|
||||
"message": "Import Phase C packages through their public @toolctrl/* package boundaries."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": [".eslintrc"],
|
||||
"parser": "jsonc-eslint-parser",
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-vars": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"**/*.server.ts",
|
||||
"**/*.server.tsx",
|
||||
"apps/api/src/**/*.ts",
|
||||
"apps/worker/src/**/*.ts",
|
||||
"packages/*/src/**/*.ts",
|
||||
"apps/web/app/utils/**/*.ts",
|
||||
"apps/web/app/modules/**/services/**/*.ts",
|
||||
"apps/web/app/modules/**/db/**/*.ts"
|
||||
],
|
||||
"excludedFiles": [
|
||||
"**/*.test.ts",
|
||||
"**/*.test.tsx",
|
||||
"**/*.spec.ts",
|
||||
"**/*.spec.tsx"
|
||||
],
|
||||
"rules": {
|
||||
"no-console": "error"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"**/*.test.ts",
|
||||
"**/*.test.tsx",
|
||||
"**/*.spec.ts",
|
||||
"**/*.spec.tsx",
|
||||
"scripts/**/*.ts",
|
||||
"scripts/**/*.mjs",
|
||||
"scripts/**/*.js"
|
||||
],
|
||||
"rules": {
|
||||
"no-console": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"apps/web/app/components/**/*.tsx",
|
||||
"apps/web/app/routes/**/*.tsx"
|
||||
],
|
||||
"excludedFiles": [
|
||||
"**/*.server.tsx",
|
||||
"**/*.server.ts"
|
||||
],
|
||||
"rules": {
|
||||
"no-console": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["packages/db/src/client.server.ts", "packages/db/src/prisma-browser.ts"],
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": [
|
||||
{
|
||||
"group": [
|
||||
"~/generated/prisma/client/*",
|
||||
"app/generated/prisma/client/*",
|
||||
"apps/web/app/generated/prisma/client/*",
|
||||
"@prisma/client",
|
||||
"@prisma/client/*"
|
||||
],
|
||||
"message": "Import Prisma through package-owned generated entrypoints inside @toolctrl/db boundaries."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["app/utils/db/**/*.ts", "apps/web/app/utils/db/**/*.ts"],
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": [
|
||||
{
|
||||
"group": [
|
||||
"~/generated/prisma/client/*",
|
||||
"app/generated/prisma/client/*",
|
||||
"apps/web/app/generated/prisma/client/*",
|
||||
"@prisma/client",
|
||||
"@prisma/client/*"
|
||||
],
|
||||
"message": "Import Prisma through @toolctrl/db package boundaries instead of generated clients."
|
||||
},
|
||||
{
|
||||
"group": ["react", "react/*"],
|
||||
"message": "app/utils/db is a server-only legacy DB boundary; keep React/UI imports out. See docs/db-legacy.md."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["packages/foundation/src/**/*.{ts,tsx}", "packages/view-models/src/**/*.{ts,tsx}"],
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": [
|
||||
{
|
||||
"group": [
|
||||
"react",
|
||||
"react/*",
|
||||
"react-dom",
|
||||
"react-dom/*",
|
||||
"~/generated/prisma/client/*",
|
||||
"app/generated/prisma/client/*",
|
||||
"apps/web/app/generated/prisma/client/*",
|
||||
"@prisma/client",
|
||||
"@prisma/client/*",
|
||||
"~/routes/*",
|
||||
"~/components/*",
|
||||
"app/*",
|
||||
"apps/web/app/*"
|
||||
],
|
||||
"message": "Foundation and view-model packages must stay UI/runtime/generated-client free."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["packages/ui-app/src/**/*.{ts,tsx}", "packages/ui-subframe/src/**/*.{ts,tsx}", "packages/ui-mock/src/**/*.{ts,tsx}"],
|
||||
"rules": {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"patterns": [
|
||||
{
|
||||
"group": [
|
||||
"~/generated/prisma/client/*",
|
||||
"app/generated/prisma/client/*",
|
||||
"apps/web/app/generated/prisma/client/*",
|
||||
"@prisma/client",
|
||||
"@prisma/client/*",
|
||||
"@toolctrl/db",
|
||||
"@toolctrl/db/*"
|
||||
],
|
||||
"message": "UI packages must not access DB boundaries directly."
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["packages/ui-app/src/**/*.{ts,tsx}", "packages/ui-subframe/src/**/*.{ts,tsx}", "packages/ui-mock/src/**/*.{ts,tsx}"],
|
||||
"rules": {
|
||||
"no-restricted-syntax": [
|
||||
"error",
|
||||
{
|
||||
"selector": "Property[key.name=/^(title|label|placeholder|ariaLabel|alt|description|message|heading|subject)$/] > Literal[value=/[A-Za-zÄÖÜäöü]/]",
|
||||
"message": "Use i18n key fields instead of hardcoded user-facing strings in Phase C UI package descriptors."
|
||||
},
|
||||
{
|
||||
"selector": "Property[key.value=/^(title|label|placeholder|aria-label|ariaLabel|alt|description|message|heading|subject)$/] > Literal[value=/[A-Za-zÄÖÜäöü]/]",
|
||||
"message": "Use i18n key fields instead of hardcoded user-facing strings in Phase C UI package descriptors."
|
||||
},
|
||||
{
|
||||
"selector": "Property[key.name=/^(title|label|placeholder|ariaLabel|alt|description|message|heading|subject)$/] > TemplateLiteral",
|
||||
"message": "Use i18n key fields instead of hardcoded user-facing strings in Phase C UI package descriptors."
|
||||
},
|
||||
{
|
||||
"selector": "Property[key.value=/^(title|label|placeholder|aria-label|ariaLabel|alt|description|message|heading|subject)$/] > TemplateLiteral",
|
||||
"message": "Use i18n key fields instead of hardcoded user-facing strings in Phase C UI package descriptors."
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["packages/ui-app/src/**/*.{tsx}", "packages/ui-subframe/src/**/*.{tsx}", "packages/ui-mock/src/**/*.{tsx}"],
|
||||
"rules": {
|
||||
"no-restricted-syntax": [
|
||||
"error",
|
||||
{
|
||||
"selector": "Property[key.name=/^(title|label|placeholder|ariaLabel|alt|description|message|heading|subject)$/] > Literal[value=/[A-Za-zÄÖÜäöü]/]",
|
||||
"message": "Use i18n key fields instead of hardcoded user-facing strings in Phase C UI package descriptors."
|
||||
},
|
||||
{
|
||||
"selector": "Property[key.value=/^(title|label|placeholder|aria-label|ariaLabel|alt|description|message|heading|subject)$/] > Literal[value=/[A-Za-zÄÖÜäöü]/]",
|
||||
"message": "Use i18n key fields instead of hardcoded user-facing strings in Phase C UI package descriptors."
|
||||
},
|
||||
{
|
||||
"selector": "Property[key.name=/^(title|label|placeholder|ariaLabel|alt|description|message|heading|subject)$/] > TemplateLiteral",
|
||||
"message": "Use i18n key fields instead of hardcoded user-facing strings in Phase C UI package descriptors."
|
||||
},
|
||||
{
|
||||
"selector": "Property[key.value=/^(title|label|placeholder|aria-label|ariaLabel|alt|description|message|heading|subject)$/] > TemplateLiteral",
|
||||
"message": "Use i18n key fields instead of hardcoded user-facing strings in Phase C UI package descriptors."
|
||||
},
|
||||
{
|
||||
"selector": "JSXText[value=/\\S/]",
|
||||
"message": "Use i18n label keys or translated values instead of hardcoded JSX text in Phase C UI packages."
|
||||
},
|
||||
{
|
||||
"selector": "JSXAttribute[name.name=/^(aria-label|title|placeholder)$/] > Literal[value=/[A-Za-zÄÖÜäöü]/]",
|
||||
"message": "Use i18n label keys or translated values instead of hardcoded JSX accessibility/title text in Phase C UI packages."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"$schema-comment": "Baseline catalogue of jsx-a11y/recommended rules that are currently disabled in .eslintrc because the codebase has pre-existing violations. The plan is to drive these counts down to zero, then promote each rule back to `error` in .eslintrc and remove it from this file. See docs/contributing/wcag-audit.md for the reduction policy. Counts are produced by `scripts/verify-a11y-baseline.mjs`.",
|
||||
"generatedAt": "2026-05-17",
|
||||
"lastUpdatedAt": "2026-05-28",
|
||||
"scope": ["apps/web/app/**/*.tsx", "packages/ui/src/stories/**/*.tsx"],
|
||||
"ruleset": "plugin:jsx-a11y/recommended",
|
||||
"totalViolations": 81,
|
||||
"rules": {
|
||||
"jsx-a11y/no-autofocus": {
|
||||
"violations": 81,
|
||||
"severity": "P2",
|
||||
"rationale": "Autofocus remains in form/editor surfaces. Button/link wrappers now use programmatic focus instead of DOM autoFocus. Migration plan: prefer programmatic focus on open() so screen-reader users hear the modal title first."
|
||||
}
|
||||
},
|
||||
"promoted": {
|
||||
"jsx-a11y/anchor-has-content": {
|
||||
"promotedAt": "2026-05-20",
|
||||
"rationale": "Reached 0 violations. The two reusable wrappers (PaginationLink, StepperTitle) now destructure `children` and render it explicitly so the rule can statically verify content. Rule moved back to `error` (jsx-a11y/recommended default) and the `off` override removed from .eslintrc."
|
||||
},
|
||||
"jsx-a11y/heading-has-content": {
|
||||
"promotedAt": "2026-05-20",
|
||||
"rationale": "Reached 0 violations alongside anchor-has-content — see StepperTitle. Rule moved back to `error` and the `off` override removed from .eslintrc."
|
||||
},
|
||||
"jsx-a11y/label-has-associated-control": {
|
||||
"promotedAt": "2026-05-20",
|
||||
"rationale": "P1. Reached 0 violations (#73 WCAG sweep). Form labels were associated with their controls via htmlFor+id (marketing-funnels, PropertyForm); accessible text was flattened to within depth-2 (NewMember, RowForm, GroupForm); empty/decorative labels captioning non-form widgets were converted to <div>/role=group captions (ConfirmModal inputs now carry aria-label, PreviewTooltips, PreviewInputTextWithMonacoEditor, JsonPropertyForm, PromptTemplateForm). Rule moved back to `error` and the `off` override removed from .eslintrc."
|
||||
},
|
||||
"jsx-a11y/click-events-have-key-events": {
|
||||
"promotedAt": "2026-05-20",
|
||||
"rationale": "P1. Reached 0 violations (#73 WCAG sweep). Genuine div-buttons were converted to <button> (ShowMoreLinesText, WorkflowExecutionsSidebar, BlockRun toggle); rows with nested interactive children gained role=button + tabIndex + onKeyDown (ConditionsGroupsInfo, prompt-builder templates); dead onClick={e=>e.preventDefault()} handlers on plain divs were removed (PdfViewer, WorkflowRun); image lightbox trigger wrapped in <button> (HoverEffect). Three genuine mouse-only click-to-focus hit-area enhancements (input-group, InputRichTextEditor, novel editor, SiteTypeCard wrapper) retain a justified inline eslint-disable to avoid a redundant tab stop ahead of an already-keyboard-accessible control. Rule moved back to `error` and the `off` override removed from .eslintrc."
|
||||
},
|
||||
"jsx-a11y/no-static-element-interactions": {
|
||||
"promotedAt": "2026-05-20",
|
||||
"rationale": "P1. Reached 0 violations alongside click-events-have-key-events (#73 WCAG sweep) — same set of fixes. Rule moved back to `error` and the `off` override removed from .eslintrc."
|
||||
},
|
||||
"jsx-a11y/no-noninteractive-element-interactions": {
|
||||
"promotedAt": "2026-05-20",
|
||||
"rationale": "P1. Reached 0 violations (#73 WCAG sweep). The <img> lightbox trigger (HoverEffect) was wrapped in a <button>; the role=group input-group addon retains a justified inline eslint-disable for its mouse-only focus-forwarding click. Rule moved back to `error` and the `off` override removed from .eslintrc."
|
||||
},
|
||||
"jsx-a11y/anchor-is-valid": {
|
||||
"promotedAt": "2026-05-25",
|
||||
"rationale": "Reached 0 violations after Storybook Popover demo menu anchors were converted to button controls. Rule moved back to `error` and the `off` override removed from .eslintrc."
|
||||
},
|
||||
"jsx-a11y/no-noninteractive-tabindex": {
|
||||
"promotedAt": "2026-05-25",
|
||||
"rationale": "Verifier reproduced 0 violations across the tracked app and Storybook scope. Rule moved back to `error` and the stale `off` override was removed from .eslintrc."
|
||||
},
|
||||
"jsx-a11y/media-has-caption": {
|
||||
"promotedAt": "2026-05-28",
|
||||
"rationale": "Reached 0 violations after AudioOrVideoPlayer started rendering a captions track for audio and video media by default, with optional caller-provided VTT metadata. Rule moved back to `error` and the `off` override was removed from .eslintrc."
|
||||
}
|
||||
},
|
||||
"reductionPolicy": {
|
||||
"monotonicDecrease": "scripts/verify-a11y-baseline.mjs (run in CI on PRs) MUST fail if any rule's count grows above the value recorded here. Reducing the count is encouraged — re-run the script to update the baseline.",
|
||||
"promotionThreshold": "When a rule's violation count reaches 0, remove its `off` override from .eslintrc, delete the entry from this file, and add a row to docs/contributing/wcag-audit.md changelog."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
name: Sentry release
|
||||
description: |
|
||||
Composite action wrapper for scripts/ci/sentry-release.sh. Use this
|
||||
from Gitea workflows that target a Gitea-Actions runner without
|
||||
workflow_call support (Gitea < 1.21). Callers must already have the
|
||||
repository checked out before invoking this action.
|
||||
|
||||
inputs:
|
||||
project:
|
||||
description: "Sentry project slug (boilerplate-api|boilerplate-worker|boilerplate-web)"
|
||||
required: true
|
||||
environment:
|
||||
description: "Deployment environment label (production|staging|preview)"
|
||||
required: true
|
||||
release:
|
||||
description: "Release identifier (typically gitea.sha)"
|
||||
required: true
|
||||
sourcemaps-path:
|
||||
description: "Directory containing source-maps to upload, or 'none'"
|
||||
required: false
|
||||
default: "none"
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Verify sentry-cli is reachable
|
||||
shell: bash
|
||||
run: |
|
||||
node -v
|
||||
npx --yes @sentry/cli@2.41.1 --version
|
||||
|
||||
- name: Tag Sentry release
|
||||
shell: bash
|
||||
run: |
|
||||
bash scripts/ci/sentry-release.sh \
|
||||
--project "${{ inputs.project }}" \
|
||||
--environment "${{ inputs.environment }}" \
|
||||
--release "${{ inputs.release }}" \
|
||||
--sourcemaps "${{ inputs.sourcemaps-path }}"
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:recommended",
|
||||
":dependencyDashboard",
|
||||
":semanticCommitTypeAll(chore)"
|
||||
],
|
||||
"schedule": ["before 5am on monday"],
|
||||
"timezone": "Europe/Berlin",
|
||||
"labels": ["dependencies"],
|
||||
"commitMessagePrefix": "chore(deps):",
|
||||
"prHourlyLimit": 4,
|
||||
"prConcurrentLimit": 10,
|
||||
"rangeStrategy": "bump",
|
||||
"packageRules": [
|
||||
{
|
||||
"groupName": "ai-providers",
|
||||
"matchPackagePatterns": [
|
||||
"^@mistralai/",
|
||||
"^mistralai$",
|
||||
"^@scaleway",
|
||||
"^scaleway$",
|
||||
"^aleph-alpha",
|
||||
"^@aleph-alpha/"
|
||||
]
|
||||
},
|
||||
{
|
||||
"groupName": "react-stack",
|
||||
"matchPackageNames": ["react", "react-dom", "react-router", "vite"],
|
||||
"matchPackagePatterns": ["^@react-router/", "^@vitejs/"]
|
||||
},
|
||||
{
|
||||
"groupName": "test-tooling",
|
||||
"matchPackageNames": ["vitest"],
|
||||
"matchPackagePatterns": ["^@vitest/", "^@testing-library/"]
|
||||
},
|
||||
{
|
||||
"groupName": "lint-tooling",
|
||||
"matchPackageNames": ["eslint"],
|
||||
"matchPackagePatterns": ["^eslint-", "^@eslint/", "^@typescript-eslint/"]
|
||||
},
|
||||
{
|
||||
"matchManagers": ["dockerfile"],
|
||||
"schedule": ["before 5am on the first day of the month"]
|
||||
},
|
||||
{
|
||||
"matchManagers": ["github-actions"],
|
||||
"schedule": ["before 5am on monday"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
name: Sentry Release
|
||||
|
||||
# Reusable workflow for Gitea Actions. Mirrors the GitHub equivalent at
|
||||
# .github/workflows/_sentry-release.yml. Requires 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.
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
project:
|
||||
description: "Sentry project slug (boilerplate-api|boilerplate-worker|boilerplate-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
|
||||
|
||||
env:
|
||||
TOOLCTRL_GITEA_HOST_IP: ${{ vars.TOOLCTRL_GITEA_HOST_IP }}
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Sentry release (${{ inputs.project }})
|
||||
runs-on: toolctrl-ci
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Resolve internal Gitea host
|
||||
run: |
|
||||
if [ -n "${TOOLCTRL_GITEA_HOST_IP:-}" ]; then
|
||||
if ! TOOLCTRL_GITEA_HOST_IP="$TOOLCTRL_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.TOOLCTRL_GITEA_HOST_IP || "") ? 0 : 1)'; then
|
||||
echo "TOOLCTRL_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
|
||||
exit 1
|
||||
fi
|
||||
printf '%s git.tool-ctrl.de\n' "$TOOLCTRL_GITEA_HOST_IP" >> /etc/hosts
|
||||
fi
|
||||
|
||||
- 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 "${{ gitea.sha }}" \
|
||||
--sourcemaps "${{ inputs.sourcemaps-path }}"
|
||||
@@ -0,0 +1,64 @@
|
||||
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.
|
||||
#
|
||||
# Spec: docs/improvement-plan/10-compliance-polish/wcag-internal.md
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
axe:
|
||||
name: axe-core + color-contrast
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
DATABASE_URL: postgresql://toolctrl:toolctrl@localhost:5432/toolctrl?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
|
||||
@@ -0,0 +1,101 @@
|
||||
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.
|
||||
# Spec: docs/improvement-plan/10-compliance-polish/bundle-budget.md
|
||||
# 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"
|
||||
- ".gitea/workflows/bundle-budget.yml"
|
||||
|
||||
env:
|
||||
TOOLCTRL_GITEA_HOST_IP: ${{ vars.TOOLCTRL_GITEA_HOST_IP }}
|
||||
|
||||
jobs:
|
||||
measure:
|
||||
name: Measure & report bundle sizes
|
||||
runs-on: toolctrl-ci
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
DATABASE_URL: postgresql://toolctrl:toolctrl@localhost:5432/toolctrl?schema=public
|
||||
steps:
|
||||
- name: Resolve internal Gitea host
|
||||
run: |
|
||||
if [ -n "${TOOLCTRL_GITEA_HOST_IP:-}" ]; then
|
||||
if ! TOOLCTRL_GITEA_HOST_IP="$TOOLCTRL_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.TOOLCTRL_GITEA_HOST_IP || "") ? 0 : 1)'; then
|
||||
echo "TOOLCTRL_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
|
||||
exit 1
|
||||
fi
|
||||
printf '%s git.tool-ctrl.de\n' "$TOOLCTRL_GITEA_HOST_IP" >> /etc/hosts
|
||||
fi
|
||||
|
||||
- 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 @toolctrl/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: 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: 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
|
||||
@@ -0,0 +1,470 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
TOOLCTRL_GITEA_HOST_IP: ${{ vars.TOOLCTRL_GITEA_HOST_IP }}
|
||||
|
||||
jobs:
|
||||
quality:
|
||||
name: Quality Gates
|
||||
runs-on: toolctrl-ci
|
||||
timeout-minutes: 45
|
||||
env:
|
||||
DATABASE_URL: postgresql://toolctrl:toolctrl@localhost:5432/toolctrl?schema=public
|
||||
steps:
|
||||
- name: Resolve internal Gitea host
|
||||
run: |
|
||||
if [ -n "${TOOLCTRL_GITEA_HOST_IP:-}" ]; then
|
||||
if ! TOOLCTRL_GITEA_HOST_IP="$TOOLCTRL_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.TOOLCTRL_GITEA_HOST_IP || "") ? 0 : 1)'; then
|
||||
echo "TOOLCTRL_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
|
||||
exit 1
|
||||
fi
|
||||
printf '%s git.tool-ctrl.de\n' "$TOOLCTRL_GITEA_HOST_IP" >> /etc/hosts
|
||||
fi
|
||||
|
||||
- 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 Docker non-root runtime
|
||||
run: pnpm run verify:docker-non-root
|
||||
|
||||
- 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: Mobile wrapper tests
|
||||
run: pnpm run test:mobile
|
||||
|
||||
- name: Unit tests
|
||||
run: pnpm test
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
TOOLCTRL_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: toolctrl-ci
|
||||
timeout-minutes: 25
|
||||
env:
|
||||
DATABASE_URL: postgresql://toolctrl:toolctrl@localhost:5432/toolctrl?schema=public
|
||||
steps:
|
||||
- name: Resolve internal Gitea host
|
||||
run: |
|
||||
if [ -n "${TOOLCTRL_GITEA_HOST_IP:-}" ]; then
|
||||
if ! TOOLCTRL_GITEA_HOST_IP="$TOOLCTRL_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.TOOLCTRL_GITEA_HOST_IP || "") ? 0 : 1)'; then
|
||||
echo "TOOLCTRL_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
|
||||
exit 1
|
||||
fi
|
||||
printf '%s git.tool-ctrl.de\n' "$TOOLCTRL_GITEA_HOST_IP" >> /etc/hosts
|
||||
fi
|
||||
|
||||
- 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 @toolctrl/api typecheck
|
||||
|
||||
- name: Test API
|
||||
run: pnpm exec vitest run apps/api/src
|
||||
|
||||
- name: Build API
|
||||
run: pnpm --filter @toolctrl/api build
|
||||
|
||||
worker:
|
||||
name: Worker Service
|
||||
runs-on: toolctrl-ci
|
||||
timeout-minutes: 25
|
||||
env:
|
||||
DATABASE_URL: postgresql://toolctrl:toolctrl@localhost:5432/toolctrl?schema=public
|
||||
steps:
|
||||
- name: Resolve internal Gitea host
|
||||
run: |
|
||||
if [ -n "${TOOLCTRL_GITEA_HOST_IP:-}" ]; then
|
||||
if ! TOOLCTRL_GITEA_HOST_IP="$TOOLCTRL_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.TOOLCTRL_GITEA_HOST_IP || "") ? 0 : 1)'; then
|
||||
echo "TOOLCTRL_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
|
||||
exit 1
|
||||
fi
|
||||
printf '%s git.tool-ctrl.de\n' "$TOOLCTRL_GITEA_HOST_IP" >> /etc/hosts
|
||||
fi
|
||||
|
||||
- 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 @toolctrl/worker typecheck
|
||||
|
||||
- name: Test Worker
|
||||
run: pnpm --filter @toolctrl/worker exec vitest run
|
||||
|
||||
- name: Verify workflow outbox native readiness
|
||||
run: pnpm run verify:workflow-outbox-native
|
||||
|
||||
- name: Build Worker
|
||||
run: pnpm --filter @toolctrl/worker build
|
||||
|
||||
- name: Health Check Worker
|
||||
run: pnpm --filter @toolctrl/worker health
|
||||
env:
|
||||
WORKER_ENABLED: "false"
|
||||
|
||||
database:
|
||||
name: Database Checks
|
||||
runs-on: toolctrl-ci
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Resolve internal Gitea host
|
||||
run: |
|
||||
if [ -n "${TOOLCTRL_GITEA_HOST_IP:-}" ]; then
|
||||
if ! TOOLCTRL_GITEA_HOST_IP="$TOOLCTRL_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.TOOLCTRL_GITEA_HOST_IP || "") ? 0 : 1)'; then
|
||||
echo "TOOLCTRL_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
|
||||
exit 1
|
||||
fi
|
||||
printf '%s git.tool-ctrl.de\n' "$TOOLCTRL_GITEA_HOST_IP" >> /etc/hosts
|
||||
fi
|
||||
|
||||
- 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://toolctrl:toolctrl@localhost:5432/toolctrl?schema=public
|
||||
|
||||
- name: Verify database migration status
|
||||
if: gitea.event_name != 'pull_request'
|
||||
run: pnpm run verify:db-migrate-status:staging
|
||||
env:
|
||||
COOLIFY_STAGING_SSH_HOST: ${{ vars.COOLIFY_STAGING_SSH_HOST }}
|
||||
COOLIFY_STAGING_SSH_USER: ${{ vars.COOLIFY_STAGING_SSH_USER }}
|
||||
COOLIFY_STAGING_WEB_RESOURCE_UUID: ${{ vars.COOLIFY_STAGING_WEB_RESOURCE_UUID }}
|
||||
COOLIFY_STAGING_SSH_KEY: ${{ secrets.COOLIFY_STAGING_SSH_KEY }}
|
||||
|
||||
- name: Test database package
|
||||
run: pnpm --filter @toolctrl/db test
|
||||
|
||||
docker-smoke:
|
||||
name: Docker Smoke
|
||||
runs-on: toolctrl-ci
|
||||
timeout-minutes: 30
|
||||
needs: [quality, api, worker, database]
|
||||
steps:
|
||||
- name: Setup hosts override and Docker CLI
|
||||
run: |
|
||||
if [ -n "${TOOLCTRL_GITEA_HOST_IP:-}" ]; then
|
||||
if ! TOOLCTRL_GITEA_HOST_IP="$TOOLCTRL_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.TOOLCTRL_GITEA_HOST_IP || "") ? 0 : 1)'; then
|
||||
echo "TOOLCTRL_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
|
||||
exit 1
|
||||
fi
|
||||
printf '%s git.tool-ctrl.de\n' "$TOOLCTRL_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
|
||||
|
||||
- name: Build Docker smoke targets
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
docker build --target web --build-arg APP_REVISION=ci-smoke-revision --tag toolctrl-web:smoke . &
|
||||
web_pid=$!
|
||||
docker build --target api --build-arg APP_REVISION=ci-smoke-revision --tag toolctrl-api:smoke . &
|
||||
api_pid=$!
|
||||
docker build --target worker --build-arg APP_REVISION=ci-smoke-revision --tag toolctrl-worker:smoke . &
|
||||
worker_pid=$!
|
||||
|
||||
status=0
|
||||
wait "$web_pid" || status=$?
|
||||
wait "$api_pid" || status=$?
|
||||
wait "$worker_pid" || status=$?
|
||||
exit "$status"
|
||||
|
||||
- name: Validate web Docker artifacts
|
||||
run: docker run --rm --entrypoint /bin/sh toolctrl-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 toolctrl-web:smoke
|
||||
env:
|
||||
DOCKER_WEB_SMOKE_TRANSPORT: exec
|
||||
|
||||
- name: Validate API Docker runtime
|
||||
run: bash scripts/docker-api-runtime-smoke.sh toolctrl-api:smoke
|
||||
env:
|
||||
DOCKER_API_SMOKE_TRANSPORT: exec
|
||||
|
||||
- name: Validate worker Docker runtime
|
||||
run: bash scripts/docker-worker-runtime-smoke.sh toolctrl-worker:smoke
|
||||
|
||||
- name: Validate Docker Compose config
|
||||
run: docker compose config
|
||||
|
||||
resolve-sentry-environment:
|
||||
name: Resolve Sentry environment
|
||||
runs-on: toolctrl-ci
|
||||
timeout-minutes: 5
|
||||
needs: docker-smoke
|
||||
outputs:
|
||||
environment: ${{ steps.resolve.outputs.environment }}
|
||||
steps:
|
||||
- name: Resolve target environment from ref
|
||||
id: resolve
|
||||
run: |
|
||||
REF="${GITEA_REF:-${{ gitea.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: ./.gitea/workflows/_sentry-release.yml
|
||||
with:
|
||||
project: boilerplate-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: ./.gitea/workflows/_sentry-release.yml
|
||||
with:
|
||||
project: boilerplate-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: ./.gitea/workflows/_sentry-release.yml
|
||||
with:
|
||||
project: boilerplate-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 }}
|
||||
@@ -0,0 +1,68 @@
|
||||
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.
|
||||
#
|
||||
# Spec: docs/improvement-plan/10-compliance-polish/test-coverage.md
|
||||
# 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"
|
||||
- ".gitea/workflows/coverage.yml"
|
||||
|
||||
env:
|
||||
TOOLCTRL_GITEA_HOST_IP: ${{ vars.TOOLCTRL_GITEA_HOST_IP }}
|
||||
|
||||
jobs:
|
||||
coverage:
|
||||
name: Measure coverage and gate thresholds
|
||||
runs-on: toolctrl-ci
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Resolve internal Gitea host
|
||||
run: |
|
||||
if [ -n "${TOOLCTRL_GITEA_HOST_IP:-}" ]; then
|
||||
if ! TOOLCTRL_GITEA_HOST_IP="$TOOLCTRL_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.TOOLCTRL_GITEA_HOST_IP || "") ? 0 : 1)'; then
|
||||
echo "TOOLCTRL_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
|
||||
exit 1
|
||||
fi
|
||||
printf '%s git.tool-ctrl.de\n' "$TOOLCTRL_GITEA_HOST_IP" >> /etc/hosts
|
||||
fi
|
||||
|
||||
- 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: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Run vitest with coverage (enforces per-path gates)
|
||||
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
|
||||
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
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,209 @@
|
||||
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:
|
||||
TOOLCTRL_GITEA_HOST_IP: ${{ vars.TOOLCTRL_GITEA_HOST_IP }}
|
||||
E2E_BASE_URL: https://boiler.saas-ctrl.com
|
||||
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: toolctrl-ci
|
||||
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: Resolve internal Gitea host
|
||||
run: |
|
||||
if [ -n "${TOOLCTRL_GITEA_HOST_IP:-}" ]; then
|
||||
if ! TOOLCTRL_GITEA_HOST_IP="$TOOLCTRL_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.TOOLCTRL_GITEA_HOST_IP || "") ? 0 : 1)'; then
|
||||
echo "TOOLCTRL_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
|
||||
exit 1
|
||||
fi
|
||||
printf '%s git.tool-ctrl.de\n' "$TOOLCTRL_GITEA_HOST_IP" >> /etc/hosts
|
||||
fi
|
||||
|
||||
- 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
|
||||
@@ -0,0 +1,73 @@
|
||||
name: Lighthouse CI
|
||||
|
||||
# Audits the deployed staging site (https://boiler.saas-ctrl.com). A
|
||||
# meaningful Lighthouse audit needs a live server, a database and seeded
|
||||
# content; reproducing that whole stack inside a CI job is brittle, so the
|
||||
# audit targets the deployed environment instead.
|
||||
#
|
||||
# This is therefore a post-deploy / monitoring audit, NOT a per-commit merge
|
||||
# gate — staging always lags the commit under review. It runs nightly and on
|
||||
# manual dispatch.
|
||||
#
|
||||
# Spec: docs/improvement-plan/10-compliance-polish/lighthouse.md
|
||||
# Docs: docs/architecture/lighthouse.md
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# 03:00 UTC nightly — after the day's deploys have settled.
|
||||
- cron: "0 3 * * *"
|
||||
|
||||
env:
|
||||
TOOLCTRL_GITEA_HOST_IP: ${{ vars.TOOLCTRL_GITEA_HOST_IP }}
|
||||
|
||||
jobs:
|
||||
lighthouse:
|
||||
name: Run Lighthouse audits
|
||||
runs-on: toolctrl-ci
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Resolve internal Gitea host
|
||||
run: |
|
||||
if [ -n "${TOOLCTRL_GITEA_HOST_IP:-}" ]; then
|
||||
if ! TOOLCTRL_GITEA_HOST_IP="$TOOLCTRL_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.TOOLCTRL_GITEA_HOST_IP || "") ? 0 : 1)'; then
|
||||
echo "TOOLCTRL_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
|
||||
exit 1
|
||||
fi
|
||||
printf '%s git.tool-ctrl.de\n' "$TOOLCTRL_GITEA_HOST_IP" >> /etc/hosts
|
||||
fi
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Mint Lighthouse session cookie
|
||||
run: node scripts/rotate-lighthouse-session-cookie.mjs
|
||||
env:
|
||||
LIGHTHOUSE_LOGIN_URL: https://boiler.saas-ctrl.com/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: RJ_session
|
||||
LIGHTHOUSE_COOKIE_DOMAIN: boiler.saas-ctrl.com
|
||||
|
||||
- name: Install Chromium
|
||||
# The Gitea runner image (node:20-bookworm) ships no browser; LHCI's
|
||||
# healthcheck otherwise fails with "Chrome installation not found".
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y --no-install-recommends chromium fonts-liberation
|
||||
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
|
||||
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@v4
|
||||
with:
|
||||
name: lighthouse-ci-results
|
||||
path: .lighthouseci/
|
||||
retention-days: 14
|
||||
@@ -0,0 +1,79 @@
|
||||
name: SDK Codegen Drift
|
||||
|
||||
# Gitea variant of .github/workflows/sdk-codegen.yml. Re-runs the
|
||||
# @toolctrl/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.
|
||||
#
|
||||
# Spec: docs/improvement-plan/08-mobile-cli-storybook-sdk/ts-sdk.md
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "apps/api/src/openapi.ts"
|
||||
- "apps/api/src/openapi.test.ts"
|
||||
- "packages/api-client-ts/**"
|
||||
- "packages/api-types/**"
|
||||
- ".gitea/workflows/sdk-codegen.yml"
|
||||
|
||||
env:
|
||||
TOOLCTRL_GITEA_HOST_IP: ${{ vars.TOOLCTRL_GITEA_HOST_IP }}
|
||||
|
||||
jobs:
|
||||
drift-check:
|
||||
name: Verify SDK codegen is in sync with OpenAPI spec
|
||||
runs-on: toolctrl-ci
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Resolve internal Gitea host
|
||||
run: |
|
||||
if [ -n "${TOOLCTRL_GITEA_HOST_IP:-}" ]; then
|
||||
if ! TOOLCTRL_GITEA_HOST_IP="$TOOLCTRL_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.TOOLCTRL_GITEA_HOST_IP || "") ? 0 : 1)'; then
|
||||
echo "TOOLCTRL_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
|
||||
exit 1
|
||||
fi
|
||||
printf '%s git.tool-ctrl.de\n' "$TOOLCTRL_GITEA_HOST_IP" >> /etc/hosts
|
||||
fi
|
||||
|
||||
- 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: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Regenerate OpenAPI capture
|
||||
run: pnpm --filter @toolctrl/api-client-ts generate-spec
|
||||
|
||||
- name: Regenerate typed client (Hey-API)
|
||||
run: pnpm --filter @toolctrl/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 @toolctrl/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 @toolctrl/api-client-ts typecheck
|
||||
pnpm --filter @toolctrl/api-types typecheck
|
||||
|
||||
- name: Run SDK tests
|
||||
run: |
|
||||
pnpm --filter @toolctrl/api-client-ts test
|
||||
pnpm --filter @toolctrl/api-types test
|
||||
@@ -0,0 +1,217 @@
|
||||
name: Storybook
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "apps/storybook/**"
|
||||
- "packages/ui/src/stories/**"
|
||||
- "packages/ui-app/src/stories/**"
|
||||
- "packages/ui-subframe/src/stories/**"
|
||||
- "packages/ui-mock/src/stories/**"
|
||||
- ".gitea/workflows/storybook.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
TOOLCTRL_GITEA_HOST_IP: ${{ vars.TOOLCTRL_GITEA_HOST_IP }}
|
||||
PLAYWRIGHT_BROWSERS_PATH: .cache/ms-playwright
|
||||
|
||||
jobs:
|
||||
build-storybook:
|
||||
name: Build static Storybook
|
||||
runs-on: toolctrl-ci
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Resolve internal Gitea host
|
||||
run: |
|
||||
if [ -n "${TOOLCTRL_GITEA_HOST_IP:-}" ]; then
|
||||
if ! TOOLCTRL_GITEA_HOST_IP="$TOOLCTRL_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.TOOLCTRL_GITEA_HOST_IP || "") ? 0 : 1)'; then
|
||||
echo "TOOLCTRL_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
|
||||
exit 1
|
||||
fi
|
||||
printf '%s git.tool-ctrl.de\n' "$TOOLCTRL_GITEA_HOST_IP" >> /etc/hosts
|
||||
fi
|
||||
|
||||
- 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
|
||||
|
||||
- name: Build Storybook static site
|
||||
run: pnpm --filter @toolctrl/storybook build-storybook
|
||||
|
||||
- name: Upload static Storybook artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: storybook-static
|
||||
path: apps/storybook/storybook-static
|
||||
retention-days: 14
|
||||
|
||||
test-storybook:
|
||||
name: Storybook test-runner (a11y gate)
|
||||
needs: build-storybook
|
||||
runs-on: toolctrl-ci
|
||||
timeout-minutes: 25
|
||||
steps:
|
||||
- name: Resolve internal Gitea host
|
||||
run: |
|
||||
if [ -n "${TOOLCTRL_GITEA_HOST_IP:-}" ]; then
|
||||
if ! TOOLCTRL_GITEA_HOST_IP="$TOOLCTRL_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.TOOLCTRL_GITEA_HOST_IP || "") ? 0 : 1)'; then
|
||||
echo "TOOLCTRL_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
|
||||
exit 1
|
||||
fi
|
||||
printf '%s git.tool-ctrl.de\n' "$TOOLCTRL_GITEA_HOST_IP" >> /etc/hosts
|
||||
fi
|
||||
|
||||
- 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
|
||||
|
||||
- name: Download built Storybook
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: storybook-static
|
||||
path: apps/storybook/storybook-static
|
||||
|
||||
- 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 Playwright Chromium
|
||||
run: pnpm --filter @toolctrl/storybook exec playwright install --with-deps chromium
|
||||
|
||||
- name: Serve static Storybook and run test-runner with a11y gate
|
||||
run: |
|
||||
set -euo pipefail
|
||||
pnpm --filter @toolctrl/storybook exec http-server storybook-static --port 6006 --silent &
|
||||
SERVER_PID=$!
|
||||
trap "kill $SERVER_PID 2>/dev/null || true" EXIT
|
||||
pnpm --filter @toolctrl/storybook exec wait-on http://127.0.0.1:6006 --timeout 60000
|
||||
TARGET_URL=http://127.0.0.1:6006 pnpm --filter @toolctrl/storybook test:storybook
|
||||
|
||||
visual-regression:
|
||||
name: Storybook visual-regression (Lost-Pixel)
|
||||
needs: build-storybook
|
||||
runs-on: toolctrl-ci
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Resolve internal Gitea host
|
||||
run: |
|
||||
if [ -n "${TOOLCTRL_GITEA_HOST_IP:-}" ]; then
|
||||
if ! TOOLCTRL_GITEA_HOST_IP="$TOOLCTRL_GITEA_HOST_IP" node -e 'process.exit(require("node:net").isIP(process.env.TOOLCTRL_GITEA_HOST_IP || "") ? 0 : 1)'; then
|
||||
echo "TOOLCTRL_GITEA_HOST_IP must be a single IPv4 or IPv6 token"
|
||||
exit 1
|
||||
fi
|
||||
printf '%s git.tool-ctrl.de\n' "$TOOLCTRL_GITEA_HOST_IP" >> /etc/hosts
|
||||
fi
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check for committed Lost-Pixel baseline
|
||||
id: baseline
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if ls apps/storybook/.lostpixel/baseline/*.png >/dev/null 2>&1; then
|
||||
echo "present=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "present=false" >> "$GITHUB_OUTPUT"
|
||||
echo "No Lost-Pixel baseline committed yet — skipping visual-regression. Run 'pnpm --filter @toolctrl/storybook visual-regression:update' and commit apps/storybook/.lostpixel/baseline/*.png to enable this gate."
|
||||
fi
|
||||
|
||||
- name: Enable Corepack
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
run: corepack enable
|
||||
|
||||
- name: Prepare pnpm 10.33.0
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
run: corepack prepare pnpm@10.33.0 --activate
|
||||
|
||||
- name: Configure pnpm store
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
run: pnpm config set store-dir .pnpm-store
|
||||
|
||||
- name: Cache pnpm store
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .pnpm-store
|
||||
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-
|
||||
|
||||
- name: Install dependencies
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Download built Storybook
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: storybook-static
|
||||
path: apps/storybook/storybook-static
|
||||
|
||||
- name: Cache Playwright browsers
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .cache/ms-playwright
|
||||
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-playwright-
|
||||
|
||||
- name: Install Playwright Chromium
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
run: pnpm --filter @toolctrl/storybook exec playwright install --with-deps chromium
|
||||
|
||||
- name: Run Lost-Pixel visual-regression diff
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
run: pnpm --filter @toolctrl/storybook visual-regression
|
||||
|
||||
- name: Upload Lost-Pixel diff images
|
||||
if: steps.baseline.outputs.present == 'true' && failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: lost-pixel-diff
|
||||
path: apps/storybook/.lostpixel/difference
|
||||
retention-days: 14
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
# 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: []
|
||||
@@ -0,0 +1,82 @@
|
||||
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 (boilerplate-api|boilerplate-worker|boilerplate-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 }}"
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
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.
|
||||
#
|
||||
# Spec: docs/improvement-plan/10-compliance-polish/wcag-internal.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://toolctrl:toolctrl@localhost:5432/toolctrl?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
|
||||
@@ -0,0 +1,74 @@
|
||||
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`.
|
||||
# Spec: docs/improvement-plan/10-compliance-polish/bundle-budget.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 @toolctrl/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
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
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.
|
||||
# Spec: docs/improvement-plan/10-compliance-polish/bundle-budget.md
|
||||
# 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://toolctrl:toolctrl@localhost:5432/toolctrl?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 @toolctrl/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
|
||||
+402
@@ -0,0 +1,402 @@
|
||||
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://toolctrl:toolctrl@localhost:5432/toolctrl?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: Mobile wrapper tests
|
||||
run: pnpm run test:mobile
|
||||
|
||||
- name: Unit tests
|
||||
run: pnpm test
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
TOOLCTRL_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://toolctrl:toolctrl@localhost:5432/toolctrl?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 @toolctrl/api typecheck
|
||||
|
||||
- name: Test API
|
||||
run: pnpm exec vitest run apps/api/src
|
||||
|
||||
- name: Build API
|
||||
run: pnpm --filter @toolctrl/api build
|
||||
|
||||
worker:
|
||||
name: Worker Service
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 25
|
||||
env:
|
||||
DATABASE_URL: postgresql://toolctrl:toolctrl@localhost:5432/toolctrl?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 @toolctrl/worker typecheck
|
||||
|
||||
- name: Test Worker
|
||||
run: pnpm --filter @toolctrl/worker exec vitest run
|
||||
|
||||
- name: Build Worker
|
||||
run: pnpm --filter @toolctrl/worker build
|
||||
|
||||
- name: Health Check Worker
|
||||
run: pnpm --filter @toolctrl/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://toolctrl:toolctrl@localhost:5432/toolctrl?schema=public
|
||||
|
||||
- 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 @toolctrl/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: toolctrl-web:smoke
|
||||
load: true
|
||||
push: false
|
||||
cache-from: type=gha,scope=toolctrl-web-smoke
|
||||
cache-to: type=gha,mode=max,scope=toolctrl-web-smoke
|
||||
|
||||
- name: Validate web Docker artifacts
|
||||
run: docker run --rm --entrypoint /bin/sh toolctrl-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 toolctrl-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: toolctrl-api:smoke
|
||||
load: true
|
||||
push: false
|
||||
cache-from: type=gha,scope=toolctrl-api-smoke
|
||||
cache-to: type=gha,mode=max,scope=toolctrl-api-smoke
|
||||
|
||||
- name: Validate API Docker runtime
|
||||
run: bash scripts/docker-api-runtime-smoke.sh toolctrl-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: toolctrl-worker:smoke
|
||||
load: true
|
||||
push: false
|
||||
cache-from: type=gha,scope=toolctrl-worker-smoke
|
||||
cache-to: type=gha,mode=max,scope=toolctrl-worker-smoke
|
||||
|
||||
- name: Validate worker Docker runtime
|
||||
run: bash scripts/docker-worker-runtime-smoke.sh toolctrl-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: boilerplate-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: boilerplate-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: boilerplate-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 }}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
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 SaasRock 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:'
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
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.
|
||||
#
|
||||
# Spec: docs/improvement-plan/10-compliance-polish/test-coverage.md
|
||||
# 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:
|
||||
TOOLCTRL_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
@@ -0,0 +1,198 @@
|
||||
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://boiler.saas-ctrl.com
|
||||
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
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
name: Lighthouse CI
|
||||
|
||||
# GitHub mirror of .gitea/workflows/lighthouse.yml. Audits the deployed
|
||||
# staging site (https://boiler.saas-ctrl.com) 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://boiler.saas-ctrl.com/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: RJ_session
|
||||
LIGHTHOUSE_COOKIE_DOMAIN: boiler.saas-ctrl.com
|
||||
|
||||
- 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
|
||||
@@ -0,0 +1,83 @@
|
||||
name: SDK Codegen Drift
|
||||
|
||||
# Re-runs the @toolctrl/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.
|
||||
#
|
||||
# Spec: docs/improvement-plan/08-mobile-cli-storybook-sdk/ts-sdk.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 @toolctrl/api-client-ts generate-spec
|
||||
|
||||
- name: Regenerate typed client (Hey-API)
|
||||
run: pnpm --filter @toolctrl/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 @toolctrl/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 @toolctrl/api-client-ts typecheck
|
||||
pnpm --filter @toolctrl/api-types typecheck
|
||||
|
||||
- name: Run SDK tests
|
||||
run: |
|
||||
pnpm --filter @toolctrl/api-client-ts test
|
||||
pnpm --filter @toolctrl/api-types test
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
name: Storybook
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "apps/storybook/**"
|
||||
- "packages/ui/src/stories/**"
|
||||
- "packages/ui-app/src/stories/**"
|
||||
- "packages/ui-subframe/src/stories/**"
|
||||
- "packages/ui-mock/src/stories/**"
|
||||
- ".github/workflows/storybook.yml"
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "apps/storybook/**"
|
||||
- "packages/ui/src/stories/**"
|
||||
- "packages/ui-app/src/stories/**"
|
||||
- "packages/ui-subframe/src/stories/**"
|
||||
- "packages/ui-mock/src/stories/**"
|
||||
- ".github/workflows/storybook.yml"
|
||||
|
||||
env:
|
||||
PLAYWRIGHT_BROWSERS_PATH: .cache/ms-playwright
|
||||
|
||||
jobs:
|
||||
build-storybook:
|
||||
name: Build static Storybook
|
||||
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
|
||||
|
||||
- name: Build Storybook static site
|
||||
run: pnpm --filter @toolctrl/storybook build-storybook
|
||||
|
||||
- name: Upload static Storybook artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: storybook-static
|
||||
path: apps/storybook/storybook-static
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
|
||||
test-storybook:
|
||||
name: Storybook test-runner (a11y gate)
|
||||
needs: build-storybook
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 25
|
||||
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
|
||||
|
||||
- name: Download built Storybook
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: storybook-static
|
||||
path: apps/storybook/storybook-static
|
||||
|
||||
- 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 Playwright Chromium
|
||||
run: pnpm --filter @toolctrl/storybook exec playwright install --with-deps chromium
|
||||
|
||||
- name: Serve static Storybook and run test-runner with a11y gate
|
||||
run: |
|
||||
set -euo pipefail
|
||||
pnpm --filter @toolctrl/storybook exec http-server storybook-static --port 6006 --silent &
|
||||
SERVER_PID=$!
|
||||
trap "kill $SERVER_PID 2>/dev/null || true" EXIT
|
||||
pnpm --filter @toolctrl/storybook exec wait-on http://127.0.0.1:6006 --timeout 60000
|
||||
TARGET_URL=http://127.0.0.1:6006 pnpm --filter @toolctrl/storybook test:storybook
|
||||
|
||||
visual-regression:
|
||||
name: Storybook visual-regression (Lost-Pixel)
|
||||
needs: build-storybook
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Check for committed Lost-Pixel baseline
|
||||
id: baseline
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if ls apps/storybook/.lostpixel/baseline/*.png >/dev/null 2>&1; then
|
||||
echo "present=true" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "present=false" >> "$GITHUB_OUTPUT"
|
||||
echo "::notice::No Lost-Pixel baseline committed yet — skipping visual-regression. Run 'pnpm --filter @toolctrl/storybook visual-regression:update' and commit apps/storybook/.lostpixel/baseline/*.png to enable this gate."
|
||||
fi
|
||||
|
||||
- name: Enable Corepack
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
run: corepack enable
|
||||
|
||||
- name: Prepare pnpm 10.33.0
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
run: corepack prepare pnpm@10.33.0 --activate
|
||||
|
||||
- name: Configure pnpm store
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
run: pnpm config set store-dir .pnpm-store
|
||||
|
||||
- name: Cache pnpm store
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .pnpm-store
|
||||
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-
|
||||
|
||||
- name: Install dependencies
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Download built Storybook
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: storybook-static
|
||||
path: apps/storybook/storybook-static
|
||||
|
||||
- name: Cache Playwright browsers
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .cache/ms-playwright
|
||||
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-playwright-
|
||||
|
||||
- name: Install Playwright Chromium
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
run: pnpm --filter @toolctrl/storybook exec playwright install --with-deps chromium
|
||||
|
||||
- name: Run Lost-Pixel visual-regression diff
|
||||
if: steps.baseline.outputs.present == 'true'
|
||||
run: pnpm --filter @toolctrl/storybook visual-regression
|
||||
|
||||
- name: Upload Lost-Pixel diff images
|
||||
if: steps.baseline.outputs.present == 'true' && failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: lost-pixel-diff
|
||||
path: apps/storybook/.lostpixel/difference
|
||||
if-no-files-found: ignore
|
||||
retention-days: 14
|
||||
@@ -0,0 +1,100 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
|
||||
.cache
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.local.example
|
||||
!.env.production.example
|
||||
!.env.fly.example
|
||||
!.env.test
|
||||
.vercel
|
||||
.output
|
||||
|
||||
/build/
|
||||
/public/build
|
||||
/apps/web/public/build
|
||||
/apps/*/dist/
|
||||
/packages/*/dist/
|
||||
/apps/web/app/styles/app.css
|
||||
|
||||
# Supabase
|
||||
**/supabase/.branches
|
||||
**/supabase/.temp
|
||||
**/supabase/.env
|
||||
|
||||
prisma/*.db
|
||||
prisma/schema/*.db
|
||||
|
||||
.idea
|
||||
apps/web/app/styles/app.css
|
||||
apps/web/app/styles/app.css
|
||||
|
||||
vite.config.ts.timestamp*
|
||||
|
||||
openai/files
|
||||
aws-lightsail-containers.json
|
||||
tsconfig.tsbuildinfo
|
||||
|
||||
.react-router/
|
||||
**/.react-router/
|
||||
apps/web/app/generated/prisma/
|
||||
.claude/
|
||||
.cursor
|
||||
__pycache__
|
||||
|
||||
# ── TC baseline (auto-generated) ──
|
||||
.tc
|
||||
.tc-id
|
||||
.bg-shell/
|
||||
Thumbs.db
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.idea/
|
||||
.vscode/
|
||||
*.code-workspace
|
||||
node_modules/
|
||||
.next/
|
||||
dist/
|
||||
build/
|
||||
!apps/web/app/utils/build/
|
||||
!apps/web/app/utils/build/**
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.venv/
|
||||
venv/
|
||||
target/
|
||||
vendor/
|
||||
*.log
|
||||
coverage/
|
||||
coverage-gate/
|
||||
.cache/
|
||||
tmp/
|
||||
|
||||
evals/results/injection-vectors.json
|
||||
evals/results/injection-vectors.html
|
||||
|
||||
# SBOM produced by scripts/generate-sbom.mjs (build-time artifact, shipped inside Docker images)
|
||||
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
|
||||
.mcp.json
|
||||
nul
|
||||
nul.*
|
||||
con
|
||||
con.*
|
||||
prn
|
||||
prn.*
|
||||
aux
|
||||
aux.*
|
||||
com[1-9]
|
||||
com[1-9].*
|
||||
lpt[1-9]
|
||||
lpt[1-9].*
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"ci": {
|
||||
"collect": {
|
||||
"url": [
|
||||
"http://localhost:3000/",
|
||||
"http://localhost:3000/pricing",
|
||||
"http://localhost:3000/contact",
|
||||
"http://localhost:3000/login",
|
||||
"http://localhost:3000/app/demo/dashboard",
|
||||
"http://localhost:3000/app/demo/crm",
|
||||
"http://localhost:3000/app/demo/settings/members",
|
||||
"http://localhost:3000/admin/dashboard",
|
||||
"http://localhost:3000/admin/analytics"
|
||||
],
|
||||
"numberOfRuns": 3,
|
||||
"puppeteerScript": "./scripts/lighthouse-puppeteer-auth.cjs",
|
||||
"settings": {
|
||||
"preset": "desktop"
|
||||
}
|
||||
},
|
||||
"assert": {
|
||||
"assertions": {
|
||||
"categories:performance": ["error", { "minScore": 0.95 }],
|
||||
"categories:accessibility": ["warn", { "minScore": 0.95 }],
|
||||
"categories:best-practices": ["warn", { "minScore": 0.95 }],
|
||||
"categories:pwa": ["warn", { "minScore": 0.9 }],
|
||||
"first-contentful-paint": ["warn", { "maxNumericValue": 2500 }],
|
||||
"largest-contentful-paint": ["warn", { "maxNumericValue": 3500 }],
|
||||
"total-blocking-time": ["warn", { "maxNumericValue": 300 }],
|
||||
"cumulative-layout-shift": ["warn", { "maxNumericValue": 0.1 }]
|
||||
}
|
||||
},
|
||||
"upload": {
|
||||
"target": "temporary-public-storage"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"ci": {
|
||||
"collect": {
|
||||
"url": [
|
||||
"https://boiler.saas-ctrl.com/login",
|
||||
"https://boiler.saas-ctrl.com/privacy-policy",
|
||||
"https://boiler.saas-ctrl.com/terms-and-conditions"
|
||||
],
|
||||
"puppeteerScript": "./scripts/lighthouse-puppeteer-auth.cjs",
|
||||
"numberOfRuns": 3,
|
||||
"settings": {
|
||||
"preset": "desktop",
|
||||
"chromeFlags": "--no-sandbox --disable-dev-shm-usage"
|
||||
}
|
||||
},
|
||||
"assert": {
|
||||
"assertions": {
|
||||
"categories:performance": ["error", { "minScore": 0.95 }],
|
||||
"categories:accessibility": ["warn", { "minScore": 0.95 }],
|
||||
"categories:best-practices": ["warn", { "minScore": 0.95 }],
|
||||
"categories:pwa": ["warn", { "minScore": 0.9 }],
|
||||
"first-contentful-paint": ["warn", { "maxNumericValue": 2500 }],
|
||||
"largest-contentful-paint": ["warn", { "maxNumericValue": 3500 }],
|
||||
"total-blocking-time": ["warn", { "maxNumericValue": 300 }],
|
||||
"cumulative-layout-shift": ["warn", { "maxNumericValue": 0.1 }]
|
||||
}
|
||||
},
|
||||
"upload": {
|
||||
"target": "temporary-public-storage"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
v22.12.0
|
||||
@@ -0,0 +1,177 @@
|
||||
---
|
||||
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; }
|
||||
---
|
||||
|
||||
# Designer-First Playbook — HiveGrid 2.0
|
||||
|
||||
Ausführungsplan für den Fall: **Designer baut Screens zuerst, Backend wird dagegen gebaut.**
|
||||
Erstellt: 2026-06-08. Basiert auf ROADMAP.md (21 Phasen) + der Hot-Swap-Architektur (Phase 1, M013–M017).
|
||||
|
||||
---
|
||||
|
||||
## 0. Das Grundprinzip
|
||||
|
||||
- **Backend-Abhängigkeit** läuft 1→21 (Datenmodell vor Features). Das ist DEINE Reihenfolge.
|
||||
- **Design-Abhängigkeit** läuft über **wiederverwendbare Archetypen**, NICHT über die Phasen-Nummern. Das ist die Reihenfolge des **Designers**.
|
||||
- Beide Tracks brauchen **je ein Fundament zuerst**:
|
||||
- Backend-Fundament = **Phase 1** (VM/Adapter/ui-mock/Visual-Reg/Smoke-Harness). Blockt alles.
|
||||
- Design-Fundament = **Sprint D0** (Design-System + App-Shell + Archetypen). Blockt ~70% aller Screens.
|
||||
- Danach läuft der **Designer 1–2 Phasen vor dir**. Du baust Backend gegen fertige Screens.
|
||||
|
||||
---
|
||||
|
||||
## 1. Die zwei Fundamente (Block 0 — parallel)
|
||||
|
||||
| Track | Wer | Inhalt | Fertig wenn |
|
||||
|---|---|---|---|
|
||||
| Backend-Fundament = Phase 1 | Du | Boilerplate, EU-Sterilisation, VM-Konvention, Action-Callback, Subframe-Adapter, ui-mock, Visual-Reg-Gate, Hot-Swap-Drill | Hot-Swap-Drill grün; 1 Beispiel-Route lädt VM gegen Mock |
|
||||
| Design-Fundament = Sprint D0 | Designer | Subframe-Design-System (Tokens, Farben, Typo, Spacing) + App-Shell (Sidebar/Breadcrumb/Topbar) + die 5 Archetypen + Zustands-Kit | Alle Archetypen + Zustände in Subframe vorhanden |
|
||||
|
||||
**Diese beiden laufen GLEICHZEITIG.** Solange beide nicht stehen, gibt es kein sauberes designer-first.
|
||||
|
||||
---
|
||||
|
||||
## 2. Die Archetypen (= die Design-Dependency-Map)
|
||||
|
||||
Jeder Archetyp wird **einmal** designt und von vielen Phasen konsumiert. Reihenfolge = nach Hebel.
|
||||
|
||||
| # | Archetyp | Einmal designen → diese Screens werden „compose" |
|
||||
|---|----------|---|
|
||||
| A1 | **App-Shell** (Sidebar, Breadcrumb, Topbar, Nav) | ALLE Phasen |
|
||||
| A2 | **List-View** (Filterbar, Tabelle/Cards, Bulk-Bar, Pagination, Spalten-Config, CSV, Leerzustand) | P6, P7, P8(Liste), P4(Tasks/Files), P3(Audit-Viewer/Notif-Center), P14(Segmente), P19(Tenant-Liste + Flag-Admin), P21(Help-Artikel) |
|
||||
| A3 | **Detail-View** (Header+Quick-Actions, Inline-Edit-Feld, Related-Panels, Activity-Sidebar, Custom-Felder) | P6(Contact/Company/Lead), P8(Deal), P9(Projekt), P17(HR-Profil), P18(Portal-Projekt) |
|
||||
| A4 | **Form/Input-Kit** (alle 12 Feldtypen, Validierung, Datei-Feld, Select/Multiselect) | P6(Custom-Felder), P16(Form-Builder), P20(Onboarding), P2(Auth-Forms), jedes Create/Edit |
|
||||
| A5 | **Modal/Wizard** (mehrstufig, Bestätigungs-Dialog, Side-Panel) | P6(Lead-Promotion), P20(Onboarding-Wizard), Bestätigungen überall |
|
||||
| A6 | **Settings/Connection-Cards** (Toggle, Connection-Status, Key-Eingabe) | P5(Apps-Engine), P3(Feature-Flags), P20(Billing/Branding), P19(Admin) |
|
||||
| A7 | **Zustands-Kit** (Leer / Laden-Skeleton / Fehler / keine-Berechtigung) | ALLE — Pflicht laut VM-Konvention (Loading/Error sind VM-Zustände) |
|
||||
|
||||
**Konsequenz:** Sind A1–A7 fertig (= Sprint D0), kann der Designer ~70% der Screens in Stunden statt Tagen zusammenstecken.
|
||||
|
||||
---
|
||||
|
||||
## 3. Die Bespoke-Screens (Sonderfälle — früh starten!)
|
||||
|
||||
Diese nutzen kaum Archetypen, brauchen die meiste Iteration → **so früh wie möglich starten, auch wenn das Backend noch fern ist.** Sortiert nach Vorlaufzeit (längste zuerst):
|
||||
|
||||
| Rang | Bespoke-Screen | Phase | Aufwand | Warum früh |
|
||||
|---|---|:---:|---|---|
|
||||
| 1 | **Automation Flow-/Node-Editor** | P12 | 🔴 sehr hoch | Schwierigste UI der ganzen App; viele Iterationen |
|
||||
| 2 | **Form-Builder-Canvas** (Drag-Drop) | P16 | 🔴 sehr hoch | Komplexe Interaktion + Conditional-Logic-Editor |
|
||||
| 3 | **Plantafel / Scheduling-Board** | P9 | 🟠 hoch | Custom-Grid, Drag pro Monteur/Tag, offline |
|
||||
| 4 | **Dashboard + Widget-Grid + Cmd+K** | P11 | 🟠 hoch | Widget-System + Command-Palette = 2 Sonder-UIs |
|
||||
| 5 | **Customer-Portal-Shell** | P18 | 🟠 hoch | **Extern sichtbar** — eigene Design-Sprache, höchster Polish |
|
||||
| 6 | **Mobile-PWA-Shell** (installierbare PWA) | P27 (v2) | 🟠 hoch | Eigenes Touch-Paradigma (Tab-Bar, offline) — PWA-only, kein nativer Client (AD-17) |
|
||||
| 7 | **Kalender-View** | P16 | 🟡 mittel | Standard-aber-eigen (Monats/Wochen-Grid) |
|
||||
| 8 | **Team-Chat / HiveMind-Chat** | P15/P13 | 🟡 mittel | Message-Liste + Composer + Presence |
|
||||
| 9 | **Sales-Kanban** | P8 | 🟡 mittel | Spalten + Draggable-Cards |
|
||||
| 10 | **Öffentliche Booking-Seiten** | P16 | 🟡 mittel | **Extern sichtbar** — Slot-Picker, Branding |
|
||||
| 11 | **Help-Center** (public) | P21 | 🟡 mittel | Content-Site, SEO, Suche |
|
||||
|
||||
---
|
||||
|
||||
## 4. Designer-Reihenfolge (die Antwort auf „welche Screens zuerst")
|
||||
|
||||
```
|
||||
D0 Design-Fundament System + App-Shell + Archetypen A1–A7 + Zustände ◄── ZUERST, höchster Hebel
|
||||
│
|
||||
D1 CRM-Cluster (P6) Contact/Company/Lead-Liste + Detail + Lead-Promo-Modal + Custom-Feld-UI
|
||||
│ → etabliert das dominante Muster für den halben Rest
|
||||
│
|
||||
D2 Bespoke früh starten (PARALLEL, lange Vorlaufzeit):
|
||||
├─ Flow-Editor (P12) ◄── längste Vorlaufzeit, JETZT anfangen
|
||||
├─ Form-Builder (P16)
|
||||
├─ Plantafel (P9)
|
||||
└─ Dashboard + Cmd+K (P11)
|
||||
│
|
||||
D3 CRUD-Feature-Screens (schnell, reuse Archetypen):
|
||||
Lead-Inbox (P7), Sales-Liste+Kanban (P8), Tasks/Files (P4),
|
||||
Email/Marketing (P14), HR (P17), Auth-Screens (P2)
|
||||
│
|
||||
D4 Extern/Brand-kritisch (eigene Politur-Runde):
|
||||
Customer-Portal (P18), Booking-public (P16), Onboarding-Wizard (P20),
|
||||
Help-Center + Mobile (P21)
|
||||
│
|
||||
D5 Niedriger Polish-Druck (intern), dazwischen:
|
||||
Plattform-Admin (P19), Settings (P5/P3), KI-Chat (P13)
|
||||
```
|
||||
|
||||
**Kurzantwort:** **Design-Fundament → CRM → parallel die 4 Bespoke-Langläufer (Flow-Editor, Form-Builder, Plantafel, Dashboard).**
|
||||
|
||||
---
|
||||
|
||||
## 5. Backend-Track (deine Reihenfolge) mit Parallelisierung
|
||||
|
||||
Du baust sequenziell, aber der Designer liegt vor dir. Pro Block: was du baust + was der Designer geliefert haben muss.
|
||||
|
||||
| Block | Deine Phasen (Backend) | Designer muss fertig haben | Charakter |
|
||||
|---|---|---|---|
|
||||
| **0** | **P1** Fundament | D0 läuft parallel | Infra, kein Design nötig |
|
||||
| **1** | P2, P3, P4, P5 | D0 fertig; D1(CRM) + D2(Bespoke) laufen | Auth/Plumbing/Files/Apps-Engine — backend-lastig |
|
||||
| **2** | **P6, P7, P8, P9** (SHK-Kernpfad) | CRM, Lead, Sales-Kanban, Plantafel | erste echte Screens — Noah-Validierung startet |
|
||||
| **3** | **P10** KWP | — (kein UI) | reines Backend |
|
||||
| **4** | P11, P12, P13 | Dashboard/Cmd+K, Flow-Editor, KI-Chat | USP-Säulen — Bespoke muss bereitliegen |
|
||||
| **5** | P14, P15, P16 | Email, Chat, Form-Builder, Kalender, Booking | Kommunikation |
|
||||
| **6** | P17, P18 | HR, **Customer-Portal (extern)** | Menschen/extern |
|
||||
| **7** | P19, P20, P21 | Admin, Onboarding, **Mobile**, Help | Plattform & Launch |
|
||||
|
||||
**Reorder-Spielraum (echte Deps, nicht 1→21-Zwang):** P14/P15 hängen nur an P6+P5, P16 an P7+P5, P17 an P4, P19 an P3. Heißt: sobald CRM (P6) steht, könntest du Email (P14) oder Telefonie (P15) vorziehen, falls ein Screen früher fertig ist. P10 (KWP) kann jederzeit nach P9 laufen.
|
||||
|
||||
---
|
||||
|
||||
## 6. Verifikations-Gates (was du wo prüfst)
|
||||
|
||||
### 6a. Pro Screen — die Designer→Backend-Übergabe (Checkliste)
|
||||
|
||||
```
|
||||
[ ] 1. UI-SPEC existiert /gsd-ui-phase N → 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
|
||||
[ ] 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)
|
||||
|
||||
- **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.
|
||||
|
||||
### 6c. Projektweit — Dauergates (CI, jeder Merge)
|
||||
|
||||
- **ESLint**: kein React-Import im VM-Paket (erzwingt Trennung).
|
||||
- **Smoke-Test pro Route** (gegen ui-mock).
|
||||
- **Visual-Regression**: Diff > Threshold → Build bricht mit Klartext-Liste betroffener Screens.
|
||||
- **Hot-Swap-Drill**: ui-mock-Tausch muss grün bleiben.
|
||||
|
||||
### 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.
|
||||
|
||||
---
|
||||
|
||||
## 7. Die drei kritischen Erfolgsregeln
|
||||
|
||||
1. **Designer designt aus der UI-SPEC-Element-Liste**, nicht frei — sonst Reconciliation-Hölle (Screens mit Daten, die's nicht gibt).
|
||||
2. **Phase 1 zuerst, ohne Kompromiss** — die Hot-Swap-Maschine ist die Voraussetzung, dass ein Screen überhaupt andocken kann.
|
||||
3. **Bespoke-Langläufer (Flow-Editor, Form-Builder) sofort starten** — sie sind der kritische Pfad des Design-Tracks, auch wenn ihr Backend (P12/P16) erst spät kommt.
|
||||
|
||||
---
|
||||
|
||||
*Erstellt 2026-06-08 als Ergänzung zu ROADMAP.md / PHASE-SOURCES.md für den designer-first-Modus.*
|
||||
Binary file not shown.
@@ -0,0 +1,319 @@
|
||||
---
|
||||
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: 12px; 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; border-right: 1px solid #ccc; border-bottom: 1px solid #ccc; padding: 3px 5px; vertical-align: top; }
|
||||
th { background: #fff7e8; }
|
||||
li { break-inside: avoid; }
|
||||
p { orphans: 3; widows: 3; }
|
||||
pre { background: #f4f4f4; padding: 8px; font-size: 8.5px; break-inside: avoid; }
|
||||
code { background: #f4f4f4; padding: 1px 3px; font-size: 8.5px; }
|
||||
.pagebreak { page-break-after: always; }
|
||||
---
|
||||
|
||||
# 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.
|
||||
|
||||
> ✅ **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.
|
||||
|
||||
## Lies das zuerst (3 Architektur-Grundregeln)
|
||||
|
||||
1. **First-Class-Tabellen + Konfig-Layer, KEIN Entity-Builder (AD-2, revidiert).** Jede Entität ist eine typisierte Prisma-Tabelle mit echten Spalten. Der `Projekt`-Kern ist EINE typisierte Tabelle (Superset der Felder); Konfigurierbarkeit läuft über `CustomFieldDefinition`+`CustomFieldValue` **und** den **Pipeline-Feld-Config-Layer** (`PipelineFieldConfig`: Sichtbarkeit/Pflicht je Pipeline+Status). Der Boilerplate-`entityBuilder.prisma` (Entity/Row/RowValue) bleibt **entfernt** — kein generisches Row/RowValue-Modell.
|
||||
2. **RLS auf allem Tenant-bezogenen (AD-1).** Fast jede Tabelle hat `tenant_id` + Postgres-Row-Level-Security. Ausnahmen: globale Definitions-Tabellen (App, SubscriptionProduct, FeatureFlag, Onboarding-Templates, Subprocessor) und die Plattform-Admin-Welt (eigene Trennung).
|
||||
3. **Polymorphe Verknüpfung statt harter FKs, wo es modulübergreifend ist.** `FileEntityLink`, `Activity`, `SearchIndexEntry`, `Task.linked_entity` nutzen `entity_type` + `entity_id` (kein FK), damit jedes Modul andocken kann, ohne das Schema zu ändern.
|
||||
|
||||
**Legende:** `[v1]` = Launch-Scope · `[v2]` = nach Launch (markiert, nicht weggelassen) · Flags: `[RLS]` `[Soft-Delete]` (archived_at) `[polymorph]` `[verschlüsselt]` `[append-only]`
|
||||
|
||||
## Die Kern-Kette (das Herzstück, hier zählt jede Relation)
|
||||
|
||||
```
|
||||
┌─ Pipeline (View) ─1:N─ PipelineStage (= Status; offen/gewonnen/verloren)
|
||||
│ └─1:N─ PipelineAccess (wer darf sehen/bearbeiten)
|
||||
│ └─1:N─ PipelineFieldConfig (Feld sichtbar/pflicht je Pipeline+Status)
|
||||
Lead ──Weiterverar- ▼ N:1
|
||||
(Vorstufe) beitungsfrei- PROJEKT ◀──M:N (Rolle)──▶ Kontakt ◀──self-ref (Rolle: haupt/sekundär)──▶ Kontakt
|
||||
│ gabe=ja ──────▶ │ (EIN Kern: Deal- + Auftrags-Felder) (Privatperson | Organisation)
|
||||
│ konvertiert_ │
|
||||
│ projekt_id ├─1:N─▶ Termin · Rechnung [v1 NEU] · Aufgabe · Aktivität · Dokument
|
||||
└ verknuepfter_ ├─1:N─▶ Checkliste ─1:N─▶ ChecklistItem (Mängel = Checkliste)
|
||||
kontakt_id ├─1:N─▶ AbnahmeProtokoll ─1:N─▶ AbnahmeSignatur (immutable; Kunde+Monteur)
|
||||
├─1:N─▶ ProjektMitglied (Monteure, Rolle)
|
||||
└─1:N─▶ ProjektExternesFeld [v2] (KWP/API — komplett v2, in v1 NICHT)
|
||||
```
|
||||
|
||||
Merksätze: **Es gibt nur einen Arbeitsdatensatz — das Projekt.** „Deal" und „Auftrag" sind Pipelines (Views), keine Entitäten — ein Projekt wechselt nur die Pipeline, es entsteht kein zweiter Datensatz und kein Won-Handoff. **`Status` ist immer pipeline-intern** (kein globaler Projektstatus). **Lead → Projekt** bei Weiterverarbeitungsfreigabe; der Kontakt wird separat verknüpft (kein Promotion-Modal mehr). **Kontakt ist Oberbegriff** (Privatperson/Organisation); Haupt-/Sekundärkontakt = Rolle einer Kontakt-Relation. **AbnahmeProtokoll bleibt rechtlich bindend** (immutable, 6 Jahre, signatur-gebunden) und bindet eine Mängel-Checkliste ein.
|
||||
|
||||
<div class="pagebreak"></div>
|
||||
|
||||
## Cross-Cutting-Entitäten (modulübergreifend - zuerst verstehen!)
|
||||
|
||||
Diese werden von vielen Modulen geschrieben/referenziert. Sie sind der Grund, warum das Modell erweiterbar bleibt.
|
||||
|
||||
| Entität | Modul | Rolle | Schlüssel |
|
||||
|---|---|---|---|
|
||||
| **Activity** [v1] | CRM | Event-Sourcing-Zentrale: jedes Modul schreibt Aktivitäten hierher, ein Stream liest sie | `subject_type` + `subject_id` (polymorph) · `actor_kind` (user/system/automation/ki_agent) · `activity_type` (~30 Typen) · `related_entity_refs[]` |
|
||||
| **AuditEntry** [v1] | Audit | Append-only Compliance-Log, SHA-256-Hash-Kette | `subject_type/id` · `before_diff`/`after_diff` (JSONB) · `summary_text` (DE) · [append-only] |
|
||||
| **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` |
|
||||
| **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` |
|
||||
|
||||
**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).
|
||||
|
||||
## Domäne 1: Identität & Mandanten (M27)
|
||||
|
||||
| Entität | v | Kern-Felder | Relationen / Flags |
|
||||
|---|---|---|---|
|
||||
| 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 |
|
||||
| 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 |
|
||||
| Session | v1 | user_id, tenant_id, last_activity_at, browser_fingerprint | Postgres-Source + Redis-Cache · [RLS] |
|
||||
| ApiKey | **v2** | key_hash, scope, expires_at | [RLS][Soft-Delete] · wandert mit Public-API |
|
||||
|
||||
## Domäne 2: Querschnitt (Audit M21, Notifications M22, i18n M30)
|
||||
|
||||
| Entität | v | Kern-Felder | Relationen / Flags |
|
||||
|---|---|---|---|
|
||||
| AuditEntry | v1 | actor_kind, action, subject_type/id, before/after_diff, summary_text, ip | [RLS][append-only] |
|
||||
| AuditExportJob | **v2** | filter_criteria, format (csv/json/pdf), status, result_file_url | [RLS] |
|
||||
| AuditRetentionPolicy | **v2** | default_retention_months (6–120), legal_hold_active | (tenant_id PK) |
|
||||
| Notification | v1 | recipient_user_id, event_type, title, body, deeplink, priority, read_at, bundle_id | [RLS] |
|
||||
| NotificationPreference | v1 | user_id, event_type, channel_in_app/email/push, priority_threshold | [RLS] |
|
||||
| NotificationDevice | v1 | user_id, device_kind, push_token | [RLS] · Push-Kanal ruht in v1 |
|
||||
| NotificationBundle | **v2** | event_type_group, count, bundle_window_seconds | [RLS] |
|
||||
| NotificationQuietHours | **v2** | user_id, weekday, start/end_time, urgent_override | [RLS] |
|
||||
|
||||
*i18n: keine eigene Tabelle - Strings in JSON-Files; nur Felder `User.language`, `Tenant.default_language`, `Kontakt.language`.*
|
||||
|
||||
## Domäne 3: Files & Tasks (M23, M26)
|
||||
|
||||
| Entität | v | Kern-Felder | Relationen / Flags |
|
||||
|---|---|---|---|
|
||||
| File | v1 | display_name, mime_type, size, storage_key, checksum, preview_status, assigned_to, source | [RLS][Soft-Delete] |
|
||||
| FileVersion | **v2** | file_id, version_number, storage_key, change_note | [RLS][append-only] |
|
||||
| FileChunk / FileUploadProgress | v1 | upload_id, chunk_index / received_chunks, status, expires_at (24h) | chunked Upload + Resume |
|
||||
| **FileEntityLink** | v1 | file_id, entity_type, entity_id, link_role | [RLS][polymorph] |
|
||||
| Task | v1 | title, description, assigned_to_user **oder** _group, deadline, priority, status, source, linked_entity_type/id | [RLS][Soft-Delete][polymorph link] |
|
||||
| TaskWatcher | v1 | task_id, user_id | M:N · [RLS] |
|
||||
|
||||
## Domäne 4: Apps-Engine (M33a) - der Integrations-Vertrag
|
||||
|
||||
| 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 |
|
||||
| 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] |
|
||||
| AppSyncItem | v1 | entity_type/id (HiveGrid) ↔ external_id, operation, status | [RLS][polymorph] |
|
||||
|
||||
<div class="pagebreak"></div>
|
||||
|
||||
## Domäne 5: Projekt-zentrischer CRM-Kern (M01–M04, AD-20) — siehe Kern-Ketten-Diagramm
|
||||
|
||||
> **Ersetzt** die früher getrennten Domänen CRM-Kern / Lead-Inbox / Sales-Pipeline / Auftragspipeline. Ein `Projekt`-Kern, Pipelines als Views.
|
||||
|
||||
| Entität | v | Kern-Felder | Relationen / Flags |
|
||||
|---|---|---|---|
|
||||
| **Projekt** | v1 | projekt_nummer (HiveNumberSeq), projektname, projekttyp, quelle, promotion, prioritaet, start/deadline, auftragsvolumen, potenzieller_auftragswert, zustaendige_person_id, projektleiter_id, projekt/rechnungs/bauher_adresse_id, kommunikation_*, stage_id (=Status), konvertiert_aus_lead_id | N:1 Pipeline/Stage · M:N Kontakt (ProjektKontakt) · 1:N Sub-Areas · [RLS][Soft-Delete] |
|
||||
| **Pipeline** | v1 | name, typ_hint (sales/auftrag/custom), position | 1:N Stage/FieldConfig/Access · [Soft-Delete] |
|
||||
| **PipelineStage** | v1 | pipeline_id, name, stage_kind (offen/gewonnen/verloren), win_probability, color | N:1 Pipeline · = die Statuswerte |
|
||||
| **PipelineFieldConfig** | v1 | pipeline_id, stage_id (NULL=pipeline-weit), field_key (System ODER `custom:<id>`), sichtbar, pflicht, reihenfolge | Konfig-Layer · nicht sichtbare Felder bleiben erhalten |
|
||||
| **PipelineFieldVisibility** | v1 | field_config_id, principal_type (rolle/gruppe/user), principal_id, kann_sehen, kann_bearbeiten | **Field-Level-Rechte (komplex, Entsch. 16.06.)** — z.B. Auftragsvolumen nur für Vertrieb; ohne Eintrag = für alle sichtbar |
|
||||
| **PipelineAccess** | v1 | pipeline_id, principal_type (rolle/user/gruppe), principal_id, kann_sehen, kann_bearbeiten | wer-sieht-Pipeline |
|
||||
| **ProjektMitglied** | v1 | projekt_id, user_id, rolle (projektleiter/monteur/zustaendig/beobachter) | M:N (mehrere Monteure) |
|
||||
| **Kontakt** | v1 | kontakt_typ (privatperson/organisation), kontakt_status (kontakt/kunde/bestandskunde), vorname/nachname, org_name, org_merkmal (gmbh/kg/öffentlich/sonstige — optional), primaer_email/-telefon, adresse_id | M:N Projekt · self-ref KontaktRelation · [RLS][Soft-Delete] |
|
||||
| **KontaktRelation** | v1 | von_kontakt_id, zu_kontakt_id, rolle (hauptkontakt/sekundaerkontakt), kontext | self-ref M:N — Kontaktart = Rolle der Relation |
|
||||
| **KontaktEmail / KontaktTelefon** | v1 | kontakt_id, wert, primaer | Multi-Werte 1:N |
|
||||
| **ProjektKontakt** | v1 | projekt_id, kontakt_id, rolle (auftraggeber/bauherr/rechnungsempfaenger/ansprechpartner), primaer | M:N-Brücke Projekt↔Kontakt |
|
||||
| **Lead** | v1 | quelle, quelle_detail, status (new/qualified/converted/lost/spam), **weiterverarbeitung_freigabe (ja/nein/unklar)**, vorname/nachname/email/telefon, rohdaten (JSONB), spam_score, konvertiert_projekt_id, verknuepfter_kontakt_id | → Projekt, → Kontakt · [Soft-Delete] · DSGVO-Auto-Lösch |
|
||||
| **Adresse** | v1 | strasse, hausnummer, plz, ort, land | von Projekt (3 Slots: Projekt/Rechnung/Bauherr) + Kontakt referenziert |
|
||||
|
||||
**Sub-Areas am Projekt:**
|
||||
|
||||
| Entität | v | Kern-Felder | Flags |
|
||||
|---|---|---|---|
|
||||
| **Rechnung** | **v1 NEU** | rechnungsnummer (HiveNumberSeq), betrag, status (entwurf/gestellt/bezahlt/storniert), datum, faellig_am, datei_id, quelle (manuell/kwp) | einfaches Sub-Entity am Projekt (E3) |
|
||||
| **Termin** | v1 | projekt_id, kontakt_id, titel, start/ende_at, ort | Kalender-Sync (M25) dockt an |
|
||||
| **Checkliste / ChecklistItem** | v1 | name, typ (generisch/maengel/abnahme_doku) / text, status, maengel_klasse (kritisch/klein/kosmetisch), foto_file_id | „Mängel" = Checkliste mit typ=maengel (E2) |
|
||||
| **AbnahmeProtokoll** | v1 | projekt_id, maengel_checkliste_id, datum, anwesende, druckprobe, funktionspruefung, zaehlerstaende, pdf_file_id, gesperrt_at | **[immutable]** 6 Jahre · offline-fähig |
|
||||
| **AbnahmeSignatur** | v1 | abnahme_id, signer_name, signer_rolle (kunde/monteur), signatur_file_id, signiert_at | Touch-Unterschrift |
|
||||
| **ProjektExternesFeld** | **v2** | projekt_id, system (kwp), feld_key, wert | KWP/API-Felder — **komplett v2** (in v1 NICHT vorhanden, Entscheidung 16.06.); v2: Sync mit „KWP gewinnt" |
|
||||
| **CustomFieldDefinition / Value** | v1 | entity_target (projekt/kontakt/lead/rechnung), field_type / entity_id, wert | dynamische Felder, pro Pipeline schaltbar |
|
||||
| **Activity / Tag** | v1 | siehe Cross-Cutting | [polymorph] |
|
||||
|
||||
*Material-Ausgang/Lagerist-Sicht, Zeiterfassung, Leistungspositionen, Baustelle, Supporttickets → v2-Backlog (Modell-Pivot E2). Material-Listen am Auftrag bleiben v1.*
|
||||
|
||||
<div class="pagebreak"></div>
|
||||
|
||||
## Domäne 6: Suche & Dashboard (M24, M20)
|
||||
|
||||
| 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** |
|
||||
| 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) |
|
||||
|
||||
## Domäne 7: Automation & ~~KI~~ (M17, ~~M18~~ → KI entfällt, [[AD-26]])
|
||||
|
||||
| Entität | v | Kern-Felder | Relationen / Flags |
|
||||
|---|---|---|---|
|
||||
| AutomationRule | v1 | name, flow_data (JSON), enabled, created_via | [RLS][Soft-Delete] |
|
||||
| AutomationRuleStep | v1 | rule_id, step_kind (trigger/condition/action/flow_control), node_type, config, parent_step_ids[] | Graph-Knoten |
|
||||
| AutomationExecution | v1 | rule_id, trigger_payload, status, dry_run, idempotency_key, reverse_window_expires_at | [RLS][24h-Undo] |
|
||||
| AutomationStepExecution | v1 | execution_id, step_id, input/output, summary_text | |
|
||||
| AutomationCredential | v1 | key, value (verschlüsselt) | [verschlüsselt] |
|
||||
| AutomationTemplate | v1 | flow_data, category, is_published | SHK-Vorlagen |
|
||||
| ~~LlmGatewayProvider / Model~~ | ~~v1~~ | ~~key, region (EU), model_kind~~ | **entfernt — KI→MCP ([[AD-26]])** |
|
||||
| ~~AiSettings~~ | ~~v1~~ | ~~enabled_use_cases[], default_models, usage_limit_tokens~~ | **entfernt — KI→MCP ([[AD-26]])** |
|
||||
| ~~AiCredits~~ | ~~v1~~ | ~~current_balance_tokens, monthly_grant~~ | **entfernt — KI→MCP ([[AD-26]])** |
|
||||
| ~~AiTokenUsage~~ | ~~v1~~ | ~~use_case, model_id, input/output_tokens, cost~~ | **entfernt — KI→MCP ([[AD-26]])** |
|
||||
| ~~Conversation / ConversationMessage~~ | ~~v1~~ | ~~kind, role, content~~ | **entfernt — KI→MCP ([[AD-26]])** |
|
||||
| ~~GeneratedObject~~ | ~~v1~~ | ~~use_case, data (Schema-validiert)~~ | **entfernt — KI→MCP ([[AD-26]])** |
|
||||
| ~~TenantEmbedding / HiveMindRAGEmbedding~~ | ~~v2~~ | ~~entity_type/id, embedding (pgvector)~~ | **zurückgestellt — RAG entfällt, KI→MCP ([[AD-26]]); v3-Kandidat** |
|
||||
| ~~WhisperTranscript~~ | ~~v2~~ | ~~audio_source_type, transcript_text, confidence~~ | **zurückgestellt — KI→MCP ([[AD-26]]); v3-Kandidat** |
|
||||
|
||||
> ⛔ **KI→MCP-Pivot ([[AD-26]]):** Alle KI-Entitäten oben sind **entfernt bzw. zurückgestellt** — HiveGrid hostet kein eigenes LLM/RAG/Whisper, sondern wird Remote-MCP-Server ([[VR-MCP]]/[[VD-MCP]]). **MCP führt KEINE neuen KI-Entitäten ein:** es nutzt das bestehende `ApiKey`/`Credential` (Auth + Scopes aus der Public-API, [[VR-P22]]) + M001-Audit; höchstens eine kleine `McpGrant`/Scope-Tabelle kommt hinzu. Die Automation-Entitäten (AutomationRule … AutomationTemplate) bleiben **unverändert v1**.
|
||||
|
||||
## Domäne 8: Kommunikation (Email M09/M10, Telefonie M12, Chat M13)
|
||||
|
||||
| Entität | v | Kern-Felder | Relationen / Flags |
|
||||
|---|---|---|---|
|
||||
| TenantSendingDomain | v1 | domain, dkim/spf/dmarc-Records, verification_status | [RLS][verschlüsselt][Soft-Delete] |
|
||||
| TenantInboundAddress | v1 | local_part, full_address, purpose (lead_inbox/bcc_logging/reply_routing) | [RLS][Soft-Delete] |
|
||||
| Email | v1 | purpose, from_sender_id, to, delivery_status, related_kontakt/projekt_id | System-/Transaktions-Mails · [RLS][Soft-Delete] |
|
||||
| EmailIntegrationMailbox / Message / SyncCursor / WebhookEvent | **v2** | provider (gmail/microsoft), oauth_tokens, matched_kontakt/projekt_id | Postfach-Sync [RLS][polymorph] |
|
||||
| Campaign | v1 | name, subject, template_id, sender_id, recipient_segment_id, status, delivered/opened/clicked_count | [RLS][Soft-Delete] |
|
||||
| OutboundEmail | v1 | campaign_id, recipient_kontakt_id, tracking_token, unsubscribe_token, delivery_status | pro Empfänger [RLS] |
|
||||
| OutboundEmailOpen / Click | v1 | opened_at (IP anonymisiert) / clicked_at, link_url | Tracking |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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] |
|
||||
| TeamChatThread / PinnedMessage / Reaction / Read | v1 | parent_message_id / message_id / emoji / read_at | Threads, Pins (max 50), Reactions, Read-Receipts |
|
||||
|
||||
<div class="pagebreak"></div>
|
||||
|
||||
## Domäne 9: Kalender, Booking, Forms, Signatur (M25, M06, M05, M07)
|
||||
|
||||
| Entität | v | Kern-Felder | Relationen / Flags |
|
||||
|---|---|---|---|
|
||||
| CalendarConnection | v1 (Google) / **v2 (MS)** | provider, oauth_refresh_token (verschl.), status | [RLS][verschlüsselt] |
|
||||
| CalendarEvent | v1 | source (internal/external_synced), starts/ends_at, is_busy, internal_entity_link | [RLS][Soft-Delete] |
|
||||
| CalendarEventMapping / SyncCursor / WebhookEvent | v1 | internal↔external_id / cursor_token / payload | Sync-Infra |
|
||||
| BookingPage | v1 | slug, duration_minutes, assignment_strategy (eine Strategie v1), is_published, intake_form_id | [RLS][Soft-Delete] |
|
||||
| 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] |
|
||||
| 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 |
|
||||
| FormAction | v1 | action_type (send_email/create_lead/create_projekt/webhook/trigger_automation), action_config | Post-Submit |
|
||||
| FormLink | **v2** | token, expires_at, usage_limit | personalisierte Links |
|
||||
| SignatureProviderConnection | v1 | data_connection_id (Apps-Engine!), provider (PandaDoc), is_default | [RLS] |
|
||||
| ProjektSignatureDocument | v1 | projekt_id, provider_document_id, source_pdf_file_id, status (draft/sent/viewed/signed/declined), signed_pdf_file_id | → Projekt (Angebot/Pipeline) · [RLS][Soft-Delete] |
|
||||
| ProjektSignatureSigner | v1 | document_id, signer_email/name, linked_kontakt_id, status, signed_at | → Kontakt |
|
||||
|
||||
## Domäne 10: HR-Hub (M14) - viel Verschlüsselung
|
||||
|
||||
| Entität | v | Kern-Felder | Flags |
|
||||
|---|---|---|---|
|
||||
| HrEmployeeProfile | v1 | user_id (1:1), personal_number, hire_date, position, team, location_id, manager_user_id, emergency_contact_* | [RLS] |
|
||||
| HrLocation | v1 | name, address_*, geo, image_file_id | [RLS][Soft-Delete] |
|
||||
| HrAnnouncement (+ Read/Reaction/Comment) | v1 | title, body, audience_kind, requires_acknowledgement | [RLS][Soft-Delete] |
|
||||
| HrEmployeeDocument | v1 | employee_user_id, document_kind, file_id, visibility | [RLS][Soft-Delete] |
|
||||
| HrResource / HrQuickLink | v1 | kind, url/file_id, category, audience | [RLS][Soft-Delete] |
|
||||
| HrSurvey (+ Item/Submission) | v1 | is_anonymous, result_visibility, item_type (text/rating_5/nps/choice/boolean) | [RLS] · anonym: submitter_hash |
|
||||
| HrRequest (+ Template) | v1 | request_kind (expense/hardware/training/reference), form_submission_id, status, assigned_approver | [RLS][Soft-Delete] |
|
||||
| EmployeePayslip | v1 | period_year/month, file_id (PDF), is_read | [RLS][Soft-Delete] |
|
||||
| EmployeeUploadReminder (+ Dispatch) | v1 | document_kind, cadence_kind, due_at, status | [RLS] |
|
||||
| EmployeeVacationRequest | v1 | start/end_date, request_kind, status, assigned_approver, calendar_event_id | → Calendar · [RLS] |
|
||||
| EmployeeSickLeaveReport | v1 | start/return_date, certificate_file_id, status | [RLS][**verschlüsselt** AU-Schein] |
|
||||
| EmployeePasswordSafeVault (+ Entry/Access) | v1 | username/password/notes (**AES-256-GCM**), permission_level (read/write/admin) | [RLS][**verschlüsselt**] · Reveal audit-geloggt |
|
||||
|
||||
<div class="pagebreak"></div>
|
||||
|
||||
## Domäne 11: Plattform-Admin (M37) - eigene Welt, KEIN tenant_id
|
||||
|
||||
| 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 |
|
||||
| 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 |
|
||||
|
||||
## Domäne 12: Billing & Abo-Baukasten (M28) - wichtig: das Recut-Modell
|
||||
|
||||
**Struktur (keine Seat-Typen mehr - Basis-Preis pro Nutzer + Feature-Module als Positionen):**
|
||||
|
||||
```
|
||||
SubscriptionProduct ─1:N─▶ SubscriptionPrice (stripe_price_id, interval month|year|one_time)
|
||||
│ (Plan: Core/Swarm/Colony)
|
||||
├─M:N─▶ SubscriptionFeature (via ProductFeature, +quota_value JSON) ◀── Konnektor-Gate!
|
||||
└─1:N─▶ SubscriptionUsageBasedPrice ─1:N─▶ UsageBasedTier (Staffel-Overage)
|
||||
│
|
||||
TenantSubscription (1:1 Tenant) ─N:1─▶ Product │
|
||||
├─1:N─▶ TenantSubscriptionProductPrice (quantity=Seats, is_metered)
|
||||
├─1:N─▶ TenantSubscriptionUsageRecord (metric, usage_amount, reported_to_stripe)
|
||||
└─ status (trial/active/past_due/cancelled/frozen) + Stripe-IDs + Dunning-Felder
|
||||
Credit (ai_token/bonus, balance_after, valid_until) ─N:1─▶ Tenant
|
||||
CheckoutSessionStatus (stripe_checkout_session, intent) ─N:1─▶ Tenant
|
||||
```
|
||||
|
||||
`SubscriptionFeature.code` (z. B. `kwp_integration`) ist die Brücke zur Konnektor-Pflicht: `tenantHasModule()` prüft, ob das Feature im Abo des Tenants enthalten ist. Quotas (max_users, ai_tokens) hängen an `SubscriptionProductFeature.quota_value`.
|
||||
|
||||
## Domäne 13: Onboarding, Branding, DSGVO (M29, M31, M35)
|
||||
|
||||
| Entität | v | Kern-Felder | Flags |
|
||||
|---|---|---|---|
|
||||
| Onboarding (+ Filter/Step) | v1 | code (shk_standard), industry, template_directory | global · Wizard-UI → v2 |
|
||||
| OnboardingSession (+ Action) | v1 | onboarding_id, current_step, status, payload | [RLS] |
|
||||
| OnboardingDemoProvisioning | v1 | template_code, entities_created (JSON), removable_until (+30d) | is_demo_data-Flag in Listen |
|
||||
| OnboardingInvitationDispatch | v1 | tenant_user_invitation_id | → M27 |
|
||||
| (User.theme_preference) | v1 | system/light/dark - **v1 nur light/dark** | Feld in User; TenantBranding → v2 |
|
||||
| GdprExportJob | v1 | scope (user_self/tenant_full), status, result_file_id (ZIP), result_expires_at | [RLS] |
|
||||
| TenantDeletionRequest | v1 | reason, grace_period_ends_at (+30d), status | [RLS] · Slug-Confirm |
|
||||
| AvvAcceptance | v1 | avv_version, accepted_by, pdf_file_id, signer_name | [RLS] |
|
||||
| Subprocessor | v1 | name, country, is_eu_eea, data_categories, dpa_url | global |
|
||||
|
||||
## Zähl-Übersicht & offene Modellierungs-Fragen
|
||||
|
||||
**~135 Entitäten gesamt** (Kern konsolidiert: Deal+Project → Projekt), davon ~25 mit `[v2]` markiert. Cross-Cutting (polymorph): Activity, AuditEntry, FileEntityLink, SearchIndexEntry, Tag, CustomField, AppSyncItem, Task-Link, Telephony/Email-Match, ProjektKontakt.
|
||||
|
||||
**Entschieden 16.06. (Raffael + Claude) — Modell final festgesetzt:**
|
||||
1. **Polymorphe Refs ohne FK** (Activity/FileEntityLink/SearchIndexEntry) — ✅ akzeptiert (Erweiterbarkeit); App-seitige Konsistenz + Cleanup-Jobs.
|
||||
2. **Adressen** — ✅ eigene `Adresse`-Tabelle (Projekt 3 Slots: Projekt/Rechnung/Bauherr; Kontakt 1 Slot); HrLocation embedded.
|
||||
3. **Rechte/Sichtbarkeit pro Pipeline** — ✅ **voll/komplex schon in v1**: `PipelineAccess` (wer sieht/bearbeitet Pipeline) + `PipelineFieldConfig` (Feld sichtbar/pflicht je Pipeline+Status) + **NEU `PipelineFieldVisibility`** (Field-Level-Rechte je Rolle/Gruppe/User, z.B. Auftragsvolumen nur für Vertrieb). Ersetzt harte Permission-Bundles für Feld-Sichtbarkeit.
|
||||
4. **HiveNumberSeq** — ✅ Row-Lock-/`SELECT … FOR UPDATE`-Strategie, **lückenlos** (GoBD-Pflicht für Rechnungen; **keine** Postgres-Sequence wegen Lücken bei Rollback). Gilt für Projekt- + Rechnungs-Nummern.
|
||||
5. **`is_demo_data`-Flag** — ✅ auf allen seedbaren Entitäten (Bulk-Lösch beim Echt-Start), quer durchs Modell.
|
||||
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).*
|
||||
Binary file not shown.
@@ -0,0 +1,164 @@
|
||||
---
|
||||
pdf_options:
|
||||
format: A4
|
||||
margin: 18mm
|
||||
printBackground: true
|
||||
css: |-
|
||||
* { box-sizing: border-box; }
|
||||
body { font-family: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif; font-size: 11px; line-height: 1.55; color: #1c1c1c; }
|
||||
h1 { font-size: 23px; color: #b8730a; margin-bottom: 2px; }
|
||||
h1 + p.sub { color: #777; font-size: 11px; margin-top: 0; margin-bottom: 18px; }
|
||||
h2 { font-size: 15px; color: #1c1c1c; border-bottom: 2px solid #f5a623; padding-bottom: 4px; margin-top: 26px; break-after: avoid; page-break-after: avoid; }
|
||||
h3 { font-size: 12.5px; color: #b8730a; margin-top: 16px; margin-bottom: 4px; break-after: avoid; page-break-after: avoid; }
|
||||
p { orphans: 3; widows: 3; margin: 6px 0; }
|
||||
ul { margin: 6px 0 6px 0; padding-left: 18px; }
|
||||
li { margin: 4px 0; orphans: 2; widows: 2; break-inside: avoid; page-break-inside: avoid; }
|
||||
strong { color: #b8730a; }
|
||||
.card { break-inside: avoid; page-break-inside: avoid; background: #fafafa; border: 1px solid #ececec; border-left: 3px solid #f5a623; border-radius: 5px; padding: 9px 13px; margin: 9px 0; }
|
||||
.card h3 { margin-top: 0; }
|
||||
.flow { break-inside: avoid; page-break-inside: avoid; background: #f6f9fe; border: 1px solid #e2ecf8; border-left: 3px solid #3d7fd6; border-radius: 5px; padding: 9px 13px; margin: 9px 0; }
|
||||
.flow h3 { color: #2c5fa0; }
|
||||
.rel { break-inside: avoid; page-break-inside: avoid; margin: 5px 0; padding: 5px 10px; border-left: 2px solid #e0c089; background: #fffdf7; border-radius: 3px; }
|
||||
.intro { break-inside: avoid; page-break-inside: avoid; background: #fff7e8; border: 1px solid #f0dcb0; border-radius: 5px; padding: 11px 14px; margin: 10px 0 4px 0; }
|
||||
.note { color: #555; font-size: 10px; font-style: italic; }
|
||||
table { border-collapse: collapse; width: 100%; font-size: 10px; margin: 6px 0; break-inside: avoid; page-break-inside: avoid; }
|
||||
th, td { border: 1px solid #ccc; padding: 4px 7px; text-align: left; vertical-align: top; }
|
||||
th { background: #fff7e8; }
|
||||
.pagebreak { page-break-after: always; }
|
||||
---
|
||||
|
||||
# Das HiveGrid-Datenmodell — einfach erklärt
|
||||
|
||||
<p class="sub">Projekt-zentrisches CRM/Pipeline-Modell · Stand 14.06.2026 · für Design & Produkt (nicht-technisch)</p>
|
||||
|
||||
<div class="intro">
|
||||
<strong>Die Grundidee in einem Satz:</strong> Es gibt <strong>ein zentrales Objekt — das Projekt</strong>. Alles andere ist entweder eine Vorstufe davor (der Lead), eine Brille darauf (die Pipeline), ein Beteiligter (Kontakte, Mitarbeiter) oder etwas, das daran hängt (Termine, Rechnungen, Checklisten, Aufgaben, Dokumente). „Deal" und „Auftrag" sind <strong>keine eigenen Dinge</strong> mehr, sondern nur Namen von Pipelines — also verschiedene Sichten auf dasselbe Projekt.
|
||||
</div>
|
||||
|
||||
## Die Bausteine
|
||||
|
||||
<div class="card">
|
||||
<h3>Lead — die Vorstufe</h3>
|
||||
Ein Sammelbecken für eingehende Anfragen aus allen Quellen (Formular, Website, Social Media, Liste, CSV, manuell, E-Mail, Anruf). Felder dürfen hier noch leer sein. Der wichtigste Punkt ist die <strong>Weiterverarbeitungsfreigabe</strong> (Ja / Nein / Unklar) — sie ist die Grenze zwischen „nur eine Anfrage" und „echtes Projekt".
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Projekt — der Kern</h3>
|
||||
Der eigentliche Arbeitsdatensatz. Trägt alle festen Angaben (Name, Quelle, Priorität, Start/Deadline, Auftragsvolumen, Adressen, zuständige Person, Projektleiter …) und beliebige <strong>selbst definierte Felder</strong>. Jedes Projekt läuft in <strong>genau einer Pipeline</strong> und steht dort auf <strong>genau einem Status</strong>.
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Pipeline — die Brille</h3>
|
||||
Eine frei benennbare Ansicht auf Projekte („Vertrieb", „Aufträge", „Wartungsverträge" …). Der Admin legt pro Pipeline fest:
|
||||
<ul>
|
||||
<li>welche <strong>Status-Schritte</strong> (Spalten) es gibt,</li>
|
||||
<li>welche <strong>Felder sichtbar oder Pflicht</strong> sind (auch je Status),</li>
|
||||
<li><strong>wer</strong> die Pipeline sehen und bearbeiten darf.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Kontakt — Personen & Organisationen</h3>
|
||||
Ein Oberbegriff: ein Kontakt ist <strong>entweder eine Privatperson oder eine Organisation</strong>. Dazu kommen ein Status (Kontakt / Kunde / Bestandskunde) und mehrere Erreichbarkeiten. <strong>Hauptkontakt</strong> und <strong>Sekundärkontakt</strong> sind keine Eigenschaft des Kontakts selbst, sondern eine <strong>Beziehung</strong> zwischen Kontakten.
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Anhänge am Projekt (Sub-Bereiche)</h3>
|
||||
Termine, <strong>Rechnungen</strong>, Checklisten (mit Punkten), die <strong>Abnahme</strong> (ein eigenes, nach Unterschrift gesperrtes Protokoll) und — <strong>ab Version 2</strong> — KWP-/Schnittstellen-Felder. „Mängel" ist dabei einfach eine Checkliste mit dem Namen „Mängel".
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Querschnitt — hängt überall dran</h3>
|
||||
<strong>Aufgaben, Aktivitäten (der Verlauf), Dokumente und Tags</strong> können an jeder Sache hängen — an einem Projekt, einem Kontakt oder einem Lead.
|
||||
</div>
|
||||
|
||||
<div class="pagebreak"></div>
|
||||
|
||||
## Die Beziehungen — in einfachen Sätzen
|
||||
|
||||
<h3>Vom Lead zum Projekt</h3>
|
||||
<div class="rel">Ein Lead wird zu <strong>höchstens einem</strong> Projekt.</div>
|
||||
<div class="rel">Ein Projekt entsteht aus <strong>höchstens einem</strong> Lead — kann aber auch direkt ohne Lead angelegt werden.</div>
|
||||
<div class="rel">Ein Lead kann mit <strong>einem</strong> Kontakt verknüpft werden; der Kontakt bleibt eigenständig.</div>
|
||||
|
||||
<h3>Projekt und Pipeline</h3>
|
||||
<div class="rel">Ein Projekt liegt in <strong>genau einer</strong> Pipeline.</div>
|
||||
<div class="rel">Eine Pipeline enthält <strong>beliebig viele</strong> Projekte.</div>
|
||||
<div class="rel">Eine Pipeline hat <strong>mehrere</strong> Status-Schritte; ein Projekt steht immer auf <strong>genau einem</strong> Status-Schritt.</div>
|
||||
<div class="rel">Eine Pipeline bestimmt selbst, <strong>welche</strong> Felder sichtbar oder Pflicht sind und <strong>wer</strong> sie sehen darf.</div>
|
||||
|
||||
<h3>Kontakte</h3>
|
||||
<div class="rel">Ein Kontakt ist <strong>entweder</strong> eine Privatperson <strong>oder</strong> eine Organisation.</div>
|
||||
<div class="rel">Ein Kontakt kann <strong>mehrere</strong> E-Mail-Adressen und <strong>mehrere</strong> Telefonnummern haben.</div>
|
||||
<div class="rel">Eine Organisation kann <strong>mehrere</strong> Hauptkontakte und <strong>mehrere</strong> Sekundärkontakte haben.</div>
|
||||
<div class="rel">Eine Privatperson kann <strong>selbst</strong> Hauptkontakt sein und zusätzlich <strong>mehrere</strong> Sekundärkontakte haben.</div>
|
||||
<div class="rel">Ein Kontakt kann an <strong>mehreren</strong> Projekten beteiligt sein, und ein Projekt kann <strong>mehrere</strong> Kontakte haben — jeweils mit einer Rolle (Auftraggeber, Bauherr, Rechnungsempfänger, Ansprechpartner).</div>
|
||||
|
||||
<h3>Beteiligte und Adressen</h3>
|
||||
<div class="rel">Ein Projekt hat <strong>eine</strong> zuständige Person und <strong>einen</strong> Projektleiter.</div>
|
||||
<div class="rel">Ein Projekt kann <strong>mehrere</strong> Monteure haben, und ein Monteur kann an <strong>mehreren</strong> Projekten arbeiten.</div>
|
||||
<div class="rel">Ein Projekt hat <strong>eine</strong> Projektadresse und <strong>optional je eine</strong> separate Rechnungs- und Bauherradresse.</div>
|
||||
|
||||
<h3>Anhänge am Projekt</h3>
|
||||
<div class="rel">Ein Projekt kann <strong>beliebig viele</strong> Termine, Rechnungen, Checklisten, Aufgaben und Dokumente haben — jedes davon gehört zu <strong>genau einem</strong> Projekt.</div>
|
||||
<div class="rel">Eine Checkliste besteht aus <strong>mehreren</strong> Punkten; jeder Punkt gehört zu <strong>genau einer</strong> Checkliste.</div>
|
||||
<div class="rel">Eine Abnahme gehört zu <strong>genau einem</strong> Projekt, bindet <strong>eine</strong> Mängel-Checkliste ein und sammelt <strong>mehrere</strong> Unterschriften (Kunde und Monteur). Nach der Unterschrift ist sie gesperrt.</div>
|
||||
<div class="rel">Ein Projekt kann <strong>mehrere</strong> KWP-/Schnittstellen-Felder tragen — <strong>erst ab Version 2</strong> (in Version 1 noch nicht enthalten; KWP-Anbindung kommt nach dem Launch).</div>
|
||||
|
||||
<h3>Eigene Felder & Querschnitt</h3>
|
||||
<div class="rel">Ein Betrieb kann <strong>beliebig viele</strong> eigene Felder definieren; jedes davon lässt sich pro Pipeline ein-/ausblenden und zur Pflicht machen.</div>
|
||||
<div class="rel">Aufgaben, Aktivitäten, Dokumente und Tags können an <strong>jeder</strong> Sache hängen — Projekt, Kontakt oder Lead.</div>
|
||||
|
||||
## Was das für den Nutzer bedeutet
|
||||
|
||||
<div class="card">
|
||||
<strong>1. Der Betrieb baut sich sein CRM selbst.</strong> Jeder SHK-Betrieb legt eigene Pipelines an, benennt sie, blendet Felder ein/aus, macht Felder zur Pflicht und legt fest, wer reinschauen darf — ohne Entwickler.
|
||||
</div>
|
||||
<div class="card">
|
||||
<strong>2. Keine Brüche, keine Doppelerfassung.</strong> Ein Auftrag ist derselbe Datensatz wie der frühere „Deal" — er wechselt nur die Pipeline. Der Verlauf bleibt lückenlos vom ersten Kontakt bis zur Abnahme.
|
||||
</div>
|
||||
<div class="card">
|
||||
<strong>3. Ein klarer Status statt zwei.</strong> „Status" heißt immer: wo steht das Projekt in <em>dieser</em> Pipeline. Kein verwirrender zweiter Gesamtstatus.
|
||||
</div>
|
||||
<div class="card">
|
||||
<strong>4. Flexible Kontaktwelt.</strong> Privatkunden, Firmen mit mehreren Ansprechpartnern, Sekundärkontakte — alles abbildbar, und ein Kontakt taucht überall im richtigen Zusammenhang auf.
|
||||
</div>
|
||||
<div class="card">
|
||||
<strong>5. Rechtssichere Abnahme & Rechnungen am Projekt.</strong> Die Abnahme bleibt unveränderlich mit Unterschrift; Rechnungen lassen sich direkt am Projekt führen.
|
||||
</div>
|
||||
|
||||
## Die Abläufe — so fühlt es sich an
|
||||
|
||||
<div class="flow">
|
||||
<h3>A · Anfrage wird zum Projekt</h3>
|
||||
Anfrage landet als Lead in der Inbox. Der Sachbearbeiter prüft und setzt die Weiterverarbeitungsfreigabe auf <strong>Ja</strong> → ein Projekt entsteht, die bekannten Daten werden übernommen, der Kunde wird als Kontakt verknüpft. Bei <strong>Nein/Unklar</strong> bleibt es ein Lead.
|
||||
</div>
|
||||
|
||||
<div class="flow">
|
||||
<h3>B · Projekt wandert durch den Vertrieb</h3>
|
||||
Im Kanban der Vertriebs-Pipeline zieht man das Projekt von Spalte zu Spalte (= Status). Bei „gewonnen" taucht <strong>dasselbe</strong> Projekt in der Auftrags-Pipeline auf — mit deren Feldern und Schritten. Keine Übergabe, kein Neuanlegen.
|
||||
</div>
|
||||
|
||||
<div class="flow">
|
||||
<h3>C · Admin richtet eine neue Pipeline ein</h3>
|
||||
Beispiel „Wartungsverträge": Spalten definieren, festlegen welche Felder sichtbar/pflichtig sind und welche Rollen Zugriff haben. Ab sofort können Projekte dort laufen.
|
||||
</div>
|
||||
|
||||
<div class="flow">
|
||||
<h3>D · Monteur auf der Baustelle</h3>
|
||||
Öffnet das Projekt mobil → Abnahme-Checkliste abarbeiten, Mängel mit Foto und Schweregrad erfassen → Kunde und Monteur unterschreiben auf dem Display → Protokoll wird gesperrt und als PDF abgelegt. Funktioniert <strong>offline</strong>.
|
||||
</div>
|
||||
|
||||
<div class="flow">
|
||||
<h3>E · Büro arbeitet am Projekt</h3>
|
||||
Rechnung am Projekt anlegen, Termin einplanen, Aufgabe an einen Kollegen zuweisen, Dokument anhängen — alles hängt am selben Projekt.
|
||||
</div>
|
||||
|
||||
<div class="flow">
|
||||
<h3>F · Kontaktpflege mit Rückschreiben</h3>
|
||||
In der Projektansicht steht die Telefonnummer des Auftraggebers; man ändert sie direkt dort → die Änderung wird <strong>auf den Kontakt zurückgeschrieben</strong> (das Feld „gehört" dem Kontakt, wird nur im Projekt angezeigt). Der Verlauf hält fest, wer wann was geändert hat.
|
||||
</div>
|
||||
|
||||
<div class="intro">
|
||||
<strong>Kurz:</strong> ein Datensatz, viele konfigurierbare Brillen. „Vertrieb" und „Auftrag" werden über die Pipeline-Konfiguration unterschieden statt über getrennte Datentöpfe — flexibler für den Betrieb. <span class="note">Die sorgfältig durchdachte Stelle dabei sind Sichtbarkeit & Rechte pro Pipeline — voll ausgebaut: einzelne Felder lassen sich <strong>pro Rolle/Gruppe</strong> ein- oder ausblenden (z.B. das Auftragsvolumen nur für den Vertrieb).</span>
|
||||
</div>
|
||||
Binary file not shown.
@@ -0,0 +1,84 @@
|
||||
---
|
||||
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 | **Stripe-Konto + Live-Verifizierung** (Geschäftsdaten, Bankkonto, ggf. Webseite-Anforderungen) | P20 | 🟠 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 (Stripe Test-Mode, 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.
@@ -0,0 +1,92 @@
|
||||
# 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,162 @@
|
||||
# HiveGrid CRM: Datenlogik und UX-Entscheidungen
|
||||
|
||||
Konsolidierte Grundlage fuer CRM-Kern, Pipeline-Views, Kontakte und Relations
|
||||
|
||||
| Feld | Inhalt |
|
||||
| --- | --- |
|
||||
| Projekt | HiveGrid CRM / Pipeline-Grundstruktur |
|
||||
| Dokumenttyp | Produkt- und UX-Entscheidungsbriefing |
|
||||
| Stand | Nach Developer-Ruecksprache: keine Aenderungen erforderlich |
|
||||
| Hinweis | Die Screenshots wurden als Arbeitskontext genutzt, sind aber nicht Teil dieses finalen Dokuments, da mehrere Details inzwischen ueberholt sind. |
|
||||
|
||||
**Ziel:** Dieses Dokument beschreibt die fachliche Datenlogik, Relationen und groben UX-Entscheidungen. Es trifft keine technischen Infrastrukturentscheidungen und ersetzt keine spaetere Detailumsetzung.
|
||||
|
||||
## 1. Executive Summary
|
||||
|
||||
Das CRM-Modell besteht aus einer klaren Vorstufe und einem zentralen Arbeitskern: **LeadInput** sammelt und qualifiziert eingehende Leads. Nach Weiterverarbeitung/Freigabe entsteht ein **Projekt**. Ab diesem Zeitpunkt ist Projekt der zentrale Datensatz, auf den Pipelines, Status, Kontakte, Aufgaben, Checklisten und weitere Arbeitsbereiche schauen.
|
||||
|
||||
Pipelines sind keine eigenen Objektarten. Namen wie Deal oder Auftrag sind nur Beispiele fuer frei konfigurierbare Views. Der Admin entscheidet, welche Pipelines existieren, wer sie sehen darf und welche Felder dort sichtbar oder verpflichtend sind.
|
||||
|
||||
Kontakt ist der Oberbegriff fuer Personen und Organisationen. Ob ein Kontakt Kunde ist, wird ueber einen Kontaktstatus abgebildet. Hauptkontakt und Sekundaerkontakt beschreiben die Kontaktart bzw. Rolle im jeweiligen Kontext.
|
||||
|
||||
| Bereich | Entscheidung | Auswirkung fuer Screens |
|
||||
| --- | --- | --- |
|
||||
| LeadInput | Eigenes Tool und Vorstufe vor Projekt. | Lead-Daten koennen spaetere Projektfelder vorbereiten, werden aber erst nach Freigabe vererbt. |
|
||||
| Projekt | Zentraler Arbeitsdatensatz nach Weiterverarbeitung. | Projekt-Detail wird der wichtigste Kontext fuer Pipeline-Arbeit. |
|
||||
| Pipeline | Frei konfigurierbare View auf Projekte. | Pipeline-Name, Zugriff, Felder und Pflichtlogik sind adminseitig steuerbar. |
|
||||
| Kontakte | Kontakt ist Oberbegriff; Typen sind Privatperson oder Organisation. | Organisationen und Personen werden ueber klare Listen und Verknuepfungen erreichbar. |
|
||||
| Inline Edit | Verknuepfte Daten duerfen direkt inline bearbeitet werden. | Edits schreiben auf den verknuepften Datenpunkt zurueck; Verlauf/Rollback sichert nachtraeglich ab. |
|
||||
|
||||
## 2. LeadInput und Projekt
|
||||
|
||||
### Grundlogik
|
||||
|
||||
**LeadInput** ist ein eigenes Tool. Dort werden Leads aus unterschiedlichen Quellen gesammelt, z. B. Formular, Website, Social Media, Leadliste, CSV-Import oder manuelle Erfassung.
|
||||
|
||||
LeadInput kann bereits Datenpunkte enthalten, die spaeter auch im Projekt relevant sind. Viele Felder koennen noch leer sein. Wenn eine Quelle oder API bereits passende Daten liefert, koennen diese frueh dem richtigen Datenpunkt zugeordnet werden.
|
||||
|
||||
Bei Weiterverarbeitung werden relevante Lead-Daten in ein Projekt vererbt. Die fachliche Trennung liegt zwischen **Lead** und **Projekt**, nicht zwischen Deal und Projekt.
|
||||
|
||||
### Weiterverarbeitungsfreigabe
|
||||
|
||||
Jeder Lead braucht den Datenpunkt **Weiterverarbeitungsfreigabe**. Die genaue DSGVO-/Prozesslogik kann spaeter durch Developer bzw. Datenschutz abgestimmt werden. Fuer diese Strukturentscheidung ist wichtig, dass der Datenpunkt existiert.
|
||||
|
||||
| Wert | Bedeutung fuer die Produktlogik |
|
||||
| --- | --- |
|
||||
| Ja | Lead darf in ein Projekt ueberfuehrt werden; relevante Daten koennen vererbt werden. |
|
||||
| Nein | Normale Projektanlage soll nicht stattfinden. |
|
||||
| Unklar / Pruefen | Weiterverarbeitung ist fachlich nicht eindeutig freigegeben; genaue Behandlung wird spaeter festgelegt. |
|
||||
|
||||
## 3. Projekt und Pipelines
|
||||
|
||||
### Projekt als Kern
|
||||
|
||||
Projekt ist der zentrale Arbeitsdatensatz. Alle Pipeline-Views, Aufgaben, Kontakte, Checklisten, Termine, Rechnungen und Integrationsdaten beziehen sich auf diesen Kern.
|
||||
|
||||
### Pipelines als Views
|
||||
|
||||
- Eine Pipeline ist eine frei benennbare Ansicht auf Projekte.
|
||||
- Begriffe wie Deal oder Auftrag sind nur Beispielnamen.
|
||||
- Ein Projekt ist genau einer Pipeline zugeordnet.
|
||||
- Eine Mehrfachsichtbarkeit wuerde ueber Duplikation laufen und waere dann ein eigenes Projekt.
|
||||
- Der UI-Begriff **Status** meint den Status innerhalb der aktuellen Pipeline.
|
||||
- Ein separater globaler Projektstatus wird vorerst nicht benoetigt.
|
||||
|
||||
### Admin-Konfiguration
|
||||
|
||||
Admins koennen Pipelines anlegen, benennen und konfigurieren. Dazu gehoert:
|
||||
|
||||
- Zugriff: Welche Personen oder Rollen duerfen die Pipeline sehen?
|
||||
- Feldsichtbarkeit: Welche Datenpunkte sind in der Pipeline sichtbar?
|
||||
- Pflichtfelder: Welche Felder sind pro Pipeline oder Status verpflichtend?
|
||||
- Statuswerte: Welche Spalten oder Schritte hat die Pipeline?
|
||||
|
||||
Nicht sichtbare Felder verschwinden nicht. Sie bleiben im Hintergrund erhalten und koennen z. B. fuer Admins oder andere Pipeline-Kontexte sichtbar sein.
|
||||
|
||||
## 4. Projektattribute und Unterbereiche
|
||||
|
||||
Projekt kann viele direkte Attribute haben. Gleichzeitig sollten wiederholbare oder eigenstaendige Bereiche nicht in ein einziges flaches Formular gezwungen werden.
|
||||
|
||||
| Direkte oder direkt sichtbare Projektattribute | Verknuepfte Bereiche / Unterbereiche |
|
||||
| --- | --- |
|
||||
| Projektname, Quelle, Promotion, Projekttyp, Status, Prioritaet, Start, Deadline, Auftragsvolumen, potenzieller Auftragswert, zustaendige Person, Projektleiter, Monteur, Projektadresse, separate Rechnungsadresse, separate Bauherradresse, projektbezogene Kommunikationsdaten. | Kontakte, Termine, Rechnungen, Checklisten, Aufgaben, Aktivitaeten, Dokumente, API-/KWP-Felder. |
|
||||
|
||||
### Maengel
|
||||
|
||||
**Maengel** werden nicht als eigenes Modul verstanden. Sie werden ueber Checklisten abgebildet, z. B. als Checkliste mit dem Namen Maengel.
|
||||
|
||||
### API-/KWP-Felder
|
||||
|
||||
API-/KWP-Felder sind im View-Kontext sichtbarkeitssteuerbare Felder. Ob sie in einer Pipeline sichtbar sind, entscheidet der Admin. Separat zu klaeren bleibt nur, welche Felder editierbar oder rein synchronisiert sind.
|
||||
|
||||
## 5. Kontaktmodell
|
||||
|
||||
**Kontakt** ist der Oberbegriff. Ein Kontakt kann eine Privatperson oder Organisation sein. Ob daraus Kunde oder spaeter Bestandskunde wird, laeuft ueber den Kontaktstatus.
|
||||
|
||||
| Begriff | Bedeutung |
|
||||
| --- | --- |
|
||||
| Kontakt | Oberbegriff fuer CRM-Kontakte. |
|
||||
| Kontakttyp | Privatperson oder Organisation. |
|
||||
| Kontaktstatus | Klaert, ob der Kontakt z. B. Kontakt, Kunde oder Bestandskunde ist. Werte spaeter final definieren. |
|
||||
| Kontaktart | Hauptkontakt oder Sekundaerkontakt im jeweiligen Kontext. |
|
||||
| Organisation | Top-Level-Kontakt fuer Unternehmen, Einrichtungen oder andere Organisationen. |
|
||||
|
||||
### Organisationen
|
||||
|
||||
Es gibt keine harte Grundunterscheidung zwischen Unternehmen und oeffentlicher Einrichtung. Der Grundtyp bleibt **Organisation**. Falls spaeter benoetigt, kann ein optionales Organisationsmerkmal oder Rechtsformfeld ergaenzt werden, z. B. GmbH, KG, oeffentliche Einrichtung oder sonstige Organisation.
|
||||
|
||||
### Hauptkontakt und Sekundaerkontakte
|
||||
|
||||
- Beim Erstellen einer Organisation soll ein Hauptkontakt mit angelegt bzw. direkt sichtbar sein.
|
||||
- Mehrere Hauptkontakte sollen moeglich sein.
|
||||
- Sekundaerkontakte koennen zusaetzlich als Liste im Kontext erscheinen.
|
||||
- Bei Privatpersonen kann die Privatperson selbst als Hauptkontakt wirken.
|
||||
- Weitere Sekundaerkontakte koennen auch bei Privatpersonen verknuepft werden.
|
||||
|
||||
Ob diese Verknuepfung technisch Parent, Relation oder Link heisst, ist fuer die UX zweitrangig. Wichtig ist, dass die Kontakte miteinander verknuepft und im richtigen Kontext sichtbar sind.
|
||||
|
||||
## 6. Listen, Navigation und Ansichten
|
||||
|
||||
### Listen
|
||||
|
||||
Fuer die Navigation sind zwei Einstiege sinnvoll:
|
||||
|
||||
- **Unternehmen** oder **Organisationen**: Einstieg fuer Organisationsdatensaetze.
|
||||
- **Kontakte**: Einstieg fuer Personen und Ansprechpartner.
|
||||
|
||||
Personen sollen direkt suchbar sein, aber auch ueber Unternehmen bzw. Organisationen erreichbar bleiben. Die Kontaktliste sollte nach Unternehmen/Organisation filterbar sein.
|
||||
|
||||
### Aggregierte und spezifische Ansichten
|
||||
|
||||
Pipeline-/Projektansichten sind aggregierte Arbeitsansichten. Sie duerfen Projekt-, Kontakt- und Organisationsdaten zusammen anzeigen, wenn das fuer den Arbeitskontext sinnvoll ist.
|
||||
|
||||
Spezifische Ansichten wie Organisation oder Kontakt zeigen primaer die eigenen Daten. Verknuepfte Projekte, Kontakte oder Pipelines erscheinen dort als Referenz oder Liste, nicht als komplett fremdes Hauptformular.
|
||||
|
||||
### Inline-Bearbeitung und Verlauf
|
||||
|
||||
Verknuepfte Daten duerfen direkt inline bearbeitet werden. Ein Feld kann in einer Projektansicht sichtbar sein, fachlich aber zu Kontakt oder Organisation gehoeren. Der Edit schreibt dann auf den verknuepften Datenpunkt zurueck.
|
||||
|
||||
Die genaue visuelle Loesung ist UI-Ausfuehrung. Verlauf und Rollback sollen nachvollziehbar machen, was wann und von wem geaendert wurde.
|
||||
|
||||
## 7. Backlog
|
||||
|
||||
Folgende Module sind vorgemerkt, werden aber nicht in den ersten CRM-/Pipeline-Kern gezogen:
|
||||
|
||||
- Baustelle
|
||||
- Supporttickets
|
||||
- Leistungspositionen
|
||||
- Zeiterfassung
|
||||
- Materialbedarf
|
||||
- Abnahme
|
||||
|
||||
## 8. Offene Punkte fuer spaetere Screens
|
||||
|
||||
1. Heisst die Organisationsliste im UI **Unternehmen** oder **Organisationen**?
|
||||
2. Braucht es ein optionales Organisationsmerkmal/Rechtsform-Feld?
|
||||
3. Welche Kontaktstatus-Werte werden final benoetigt?
|
||||
4. Welche Pipeline-Statuswerte braucht die erste konkrete Pipeline?
|
||||
5. Welche Projektkopf-Felder sind in einer konkreten View sichtbar?
|
||||
6. Welche API-/KWP-Felder sind nur synchronisiert und welche editierbar?
|
||||
|
||||
Ende des konsolidierten Stands. Screenshots wurden bewusst nicht eingebunden, da sie nur als Arbeitskontext dienten und teilweise nicht mehr dem aktuellen Modell entsprechen.
|
||||
|
||||
@@ -0,0 +1,283 @@
|
||||
# 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-scaleway, 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-verkaufsfall-anlage → Phase 8 verschoben (2026-06-10, Dependency-Inversion): braucht die Deal-Entity (M060) — Deal-Verhalten gehört in die Deal-Phase. P7 liefert den Extension-Point (Lead-Status `qualified` + Event), P8 verdrahtet die Auto-Anlage.
|
||||
|
||||
## 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-verkaufsfall-anlage, M059-sales-pipeline-konfiguration, M060-verkaufsfall-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-NAMEN bleiben als Datei-Referenz, ihr **Inhalt ist projekt-zentrisch re-gemappt** — „Verkaufsfall"/„Deal" = ein `Projekt`-Kern in der Sales-Pipeline-Sicht (kein eigenes Deal-Objekt), `M060-verkaufsfall-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.
|
||||
> M049 (aus Phase 7, 2026-06-10): Auto-Verkaufsfall-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: M149-custom-widgets + M150-export-report → v2. Suche v1 = **Keyword-only** (Meilisearch); pgvector/Hybrid-RRF → v2 mit HiveMind (AD-5 sequenziert).
|
||||
> 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-pandadoc-docusign, 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 + Stripe-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-hell-dunkel-modus, M153-subscriptions-stripe, 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-test-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 Stripe-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:** Stripe/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-Verkaufsfall aus qualifiziertem Lead (M049, hierher verschoben); SHK-Pipelines + Gründe selbst seeden (`M059→M158`, `M062→M158`); Deal-Anlage-Option ins Lead-Promotion-Modal (P6) verdrahten |
|
||||
| **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** | Stripe 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, Stripe 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.
@@ -0,0 +1,102 @@
|
||||
# HiveGrid 2.0
|
||||
|
||||
## 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 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 ist ein Git-Downstream der ToolCTRL-Boilerplate (~35–45 % Abdeckung: Fundament high, Fachdomäne greenfield).
|
||||
|
||||
> 🔴 **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).
|
||||
|
||||
## 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.
|
||||
|
||||
## 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/`.
|
||||
|
||||
### 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.)
|
||||
|
||||
### 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). -->
|
||||
|
||||
**USP-Säulen (Differenzierung, volle Tiefe day-1 — AD-16):**
|
||||
- [ ] 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)
|
||||
|
||||
**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)
|
||||
|
||||
**Fundament-Kern:**
|
||||
- [ ] Auth/Multi-Tenancy (M27), Apps-Engine/Adapter (M33a), Audit-Log (M21), Notifications (M22), i18n (M30), Feature-Flags (M32), Plattform-Admin (M37)
|
||||
|
||||
**Breite (AD-13):**
|
||||
- [ ] HR-Hub (M14), Customer-Portal (M15), Email (M09/M10), Telefonie (M12), Team-Chat (M13), Booking/Forms/Angebot (M05/M06/M07), Files/Suche/Calendar/Tasks (M23/M24/M25/M26), Billing (M28), Onboarding (M29), Branding (M31), Dashboard (M20), Public-API (M34), DSGVO-Export (M35), Mobile-PWA (M36 — PWA-only, kein nativer Client), Help-Center/Desk (M38/M39)
|
||||
|
||||
### Out of Scope
|
||||
|
||||
<!-- 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)
|
||||
- **Volle Migrations-Pipelines pro Altsystem** — sauberer Start, KWP-Sync füllt nach; HubSpot/Quiply als Read-only-Archiv, nur punktuelle CSV-Importe (AD-14)
|
||||
- ~~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).
|
||||
- **Boilerplate-Reuse:** Geteilte Pakete behalten `@toolctrl/*`-Namen (`packages/ui-app`, `ui-subframe`, `ui-mock`, `@toolctrl/search`, `@toolctrl/foundation`). Neue HiveGrid-Querschnittsdienste im `@hivegrid/*`-Namespace (activity, audit, notifications, entitlements, search, i18n).
|
||||
- **Phase-0-Pflichten (vor jedem Fachmodul):** (1) Boilerplate als Code-Basis einziehen — Repo ist heute Docs-only, (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.
|
||||
|
||||
## 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 ✓)
|
||||
- **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
|
||||
- **Tech-Stack**: React Router 7, Node 22.12.x (dev/test) / node:20 (runtime), Prisma/Postgres, Redis; **Subframe-UI ist Pflicht** für jede Route
|
||||
- **Repo/Naming**: Git-Downstream der @toolctrl-Boilerplate, upstream-Remote erhalten, `@toolctrl/*`-Naming behalten (AD-10)
|
||||
- **Go-Live**: Big-Bang — erst live mit vollständigem Phase-1-Produkt (AD-19); interne Bau-Reihenfolge nach AD-11
|
||||
|
||||
## Key Decisions
|
||||
|
||||
Vollständige Extraktion mit Scope/Begründung: `.planning/intel/decisions.md`. Quelle: `docs/ARCHITECTURE-DECISIONS.md`.
|
||||
|
||||
| Decision | Kern | Status |
|
||||
|----------|------|--------|
|
||||
| AD-1 | Mandanten-Trennung via echtes Postgres-RLS | ✓ locked |
|
||||
| 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-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 |
|
||||
| AD-9 | Realtime: WebSocket (Chat) + SSE (Read-Updates) | ✓ locked |
|
||||
| AD-10 | Naming: `@toolctrl/*` behalten, Docs anpassen | ✓ locked |
|
||||
| AD-11 | Bau-Strategie: Hybrid (Fundament-Kern → SHK-Kernpfad → Breite) | ✓ locked |
|
||||
| AD-12 | SHK-Defaults als deklaratives Seed, Noah validiert | ✓ locked |
|
||||
| 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-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 |
|
||||
|
||||
---
|
||||
*Erzeugt: 2026-06-07 via `/gsd:ingest-docs` (Stufe 1 — WHAT) aus 38 Docs (37 SPEC + 1 ADR). ROADMAP folgt in Stufe 2.*
|
||||
Binary file not shown.
@@ -0,0 +1,45 @@
|
||||
# .planning/ — START HIER (Live-Planung 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).
|
||||
|
||||
**Stand:** 2026-06-15
|
||||
|
||||
## 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.
|
||||
|
||||
## Kern-Planung (gepflegt)
|
||||
| Datei | Inhalt |
|
||||
|---|---|
|
||||
| PROJECT.md | Charter + Architektur-Entscheidungen (Kurzfassung; voll in `docs/ARCHITECTURE-DECISIONS.md`) |
|
||||
| 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 |
|
||||
|
||||
## Datenmodell — ✅ APPROVED & LOCKED (Projekt-zentrisch, AD-20)
|
||||
| Datei | Rolle |
|
||||
|---|---|
|
||||
| **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) |
|
||||
| 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-FIRST-PLAYBOOK.md** — Designer-first-Methodik + Archetypen
|
||||
|
||||
## Externe Abhängigkeiten
|
||||
- **EXTERNALS-CHECKLISTE.md** — Konten/APIs (KWP, Mistral, Mailjet, AirCall, Stripe, …)
|
||||
|
||||
## 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).
|
||||
Binary file not shown.
@@ -0,0 +1,408 @@
|
||||
# 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 KI-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.)*
|
||||
|
||||
> ✅ **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`.
|
||||
|
||||
## v1 Requirements
|
||||
|
||||
### Modul 1 — CRM-Kern
|
||||
|
||||
- [ ] **REQ-crm-datenmodell**: Typisierte First-Class-Prisma-Tabellen für alle CRM-Kernentitäten (Kontakt als Oberbegriff mit Kontakttyp Privatperson/Organisation, KontaktRelation, Lead, Activity, CustomField, Tag) mit RLS-Policies auf allen Tabellen.
|
||||
- [ ] **REQ-crm-listen-views**: Kontakt- und Organisations-Listen mit server-seitiger Filter-, Sortier- und Paginierungslogik, Bulk-Actions und CSV-Export.
|
||||
- [ ] **REQ-crm-detail-views**: Kontakt-, Organisations- und Lead-Detailansichten mit Inline-Edit, Activity-Stream, verknüpften Entitäten und Custom-Feldern.
|
||||
- [ ] **REQ-lead-projekt-konvertierung**: Lead → Projekt bei `Weiterverarbeitungsfreigabe` (ja/nein/unklar); relevante Lead-Daten werden ins Projekt vererbt, der Kontakt wird separat verknüpft (kein Promotions-Modal, AD-20). *(Pivot 13.06.: ersetzt das frühere REQ-crm-lead-promotion / 4-Optionen-Modal.)*
|
||||
- [ ] **REQ-crm-activity-stream**: Zentrale append-only Activity-Tabelle (Event-Sourcing) als chronologische Stream-View pro Entität, filterbar nach Typ/Actor/Zeitraum.
|
||||
- [ ] **REQ-crm-custom-felder**: CustomFieldDefinition + CustomFieldValue pro Tenant für Kontakt/Lead/Projekt/Rechnung, mit Admin-Verwaltungs-Route, pro Pipeline via PipelineFieldConfig schaltbar und SHK-Branchen-Template-Defaults.
|
||||
- [ ] **REQ-crm-duplikat-erkennung**: Live-Match-Check beim Anlegen und Bulk-Duplikat-Tool für Admins mit Side-by-Side-Merge.
|
||||
- [ ] **REQ-crm-tags**: Tag-System mit ad-hoc-Erstellung, Farbgebung, Entity-übergreifender Verwaltung und Listen-Filter-Integration.
|
||||
- [ ] **REQ-crm-permissions**: Permission-Bundle crm.* (read_own, read_all, write, delete, admin) mit Owner-Check und server-seitigem Permission-Filter.
|
||||
|
||||
### 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-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.
|
||||
- [ ] **REQ-lead-permissions**: Permission-Bundle leads.* mit Owner-Check-Logik und permission-awarern Server-side-Filtern in allen Listen.
|
||||
|
||||
### Modul 3 — Projekt & Pipelines (Teil 1: Kern + Pipeline-Engine)
|
||||
|
||||
> *(Pivot 13.06., AD-20: ein `Projekt`-Kern; „Deal"/„Auftrag" = Pipeline-Typen (typ_hint), keine eigenen Entitäten. Single Source: ENTITY-MODEL.md.)*
|
||||
|
||||
- [ ] **REQ-projekt-kern-datenmodell**: Ein typisierter `Projekt`-Kern (Superset-Tabelle, Deal- + Auftrags-Felder) mit RLS und HiveNumberSeq für fortlaufende Projekt-Nummern; Pipeline (typ_hint sales/auftrag/custom) + PipelineStage (= Status, pipeline-intern; stage_kind offen/gewonnen/verloren) als konfigurierbare Views.
|
||||
- [ ] **REQ-pipeline-rechte-config**: Pipeline-Feld-Config- und Rechte-Layer schon v1 komplex — PipelineAccess (wer sieht/bearbeitet Pipeline) + PipelineFieldConfig (Feld sichtbar/pflicht je Pipeline+Status) + PipelineFieldVisibility (Field-Level-Rechte je Rolle/Gruppe/User, z.B. Auftragsvolumen nur für Vertrieb).
|
||||
- [ ] **REQ-projekt-kanban-listen-view**: Ein konfigurierbarer Kanban-View (Drag-&-Drop, Stage-Wechsel) und Listen-View mit Filter, Bulk-Actions, Real-Time-Updates und Reverse-Window für gewonnen/verloren.
|
||||
- [ ] **REQ-projekt-pipeline-wechsel**: Projekt-Anlage aus mehreren Quellen, Stage-Wechsel-Validation und Pipeline-Wechsel statt Won-Handoff (ein Projekt wechselt nur die Pipeline — kein zweiter Datensatz entsteht); Auto-Archive-Cron für abgeschlossene Projekte.
|
||||
- [ ] **REQ-projekt-forecast-kpis**: Forecast-Berechnung, KPIs pro Vertriebler, Stage-Conversion-Rates und Verlust-Grund-Auswertung mit Aggregat-Cache.
|
||||
|
||||
### Modul 4 — Projekt & Pipelines (Teil 2: Auftrags-Features + Sub-Areas)
|
||||
|
||||
> *(Pivot 13.06., AD-20: Auftrags-Welt = Pipeline-View auf denselben `Projekt`-Kern. Material/Zeiterfassung/Leistungspositionen/Baustelle/Support → v2.)*
|
||||
|
||||
- [ ] **REQ-projekt-sub-areas**: Sub-Areas am Projekt-Kern (Termine, Aufgaben, Aktivitäten, Dokumente, Checklisten, ProjektMitglied/Monteur-Zuweisung) + Plantafel-Ansicht für Ressourcen-Scheduling pro Monteur/Tag, offline-fähig.
|
||||
- [ ] **REQ-rechnung-sub-entity**: `Rechnung` als einfaches Sub-Entity am Projekt-Kern (Liste/Anlegen/Verknüpfen) mit fortlaufender Rechnungsnummer (HiveNumberSeq, lückenlos/GoBD), Status (entwurf/gestellt/bezahlt/storniert) und PDF-Anhang. *(Pivot 13.06., E3 — einziger echter v1-Scope-Zuwachs.)*
|
||||
- [ ] **REQ-projekt-abnahme**: AbnahmeProtokoll (+ AbnahmeSignatur) als immutable Sub-Area direkt am Projekt mit Touch-Unterschrift, Offline-Sync und M05-Form-Template-Unterstützung; „Mängel" als Checkliste (typ=maengel).
|
||||
|
||||
### Modul 5 — Form Builder
|
||||
|
||||
- [ ] **REQ-form-datenmodell**: Form, FormField, FormSubmission und FormAction als Datenmodell mit 12 Feld-Typen und konfigurierbaren Post-Submit-Aktionen. *(Scope-Schnitt 12.06.: FormLink — personalisierte Links mit Tracking/Ablauf/Limit — + JS-Snippet → v2; öffentliche URL, QR-Code und iFrame-Embed bleiben.)*
|
||||
- [ ] **REQ-form-editor**: Drag-&-Drop-Form-Editor mit Echtzeit-Vorschau, Conditional Logic, SHK-Form-Templates und iFrame-Embed-Code.
|
||||
- [ ] **REQ-form-actions**: Form-Actions nach Submission (Lead/Deal/Task anlegen, Webhook, Email, Automation-Trigger) mit Field-Mapping und ActionLog.
|
||||
|
||||
### Modul 6 — Booking
|
||||
|
||||
- [ ] **REQ-booking-datenmodell**: BookingPage, AvailabilityRule, AvailabilityException und Appointment als Datenmodell für öffentlich erreichbare Buchungsseiten.
|
||||
- [ ] **REQ-booking-slot-kalkulierung**: Slot-Berechnung unter Berücksichtigung von Verfügbarkeitsregeln, Ausnahmen, Kalender-Sync (M25) und Puffer, Timezone-aware.
|
||||
- [ ] **REQ-booking-integrationen**: Lead-Inbox-Integration, Activity-Eintrag, Bestätigungs-Email und iFrame-Embed-Code nach Terminbuchung.
|
||||
|
||||
### Modul 7 — Angebot + Signatur
|
||||
|
||||
- [ ] **REQ-signatur-datenmodell**: DealSignatureDocument, DealSignatureSigner und SignatureProviderConnection für Multi-Signer-Workflows mit PandaDoc/DocuSign.
|
||||
- [ ] **REQ-signatur-provider**: PandaDoc/DocuSign-Integration via Apps-Engine (M33a) mit OAuth-Connect-Flow, Webhook-Verarbeitung und Status-Updates.
|
||||
|
||||
### Modul 9 — Email-Inbox
|
||||
|
||||
- [ ] **REQ-email-datenmodell**: EmailIntegrationMailbox, EmailIntegrationMessage, TenantSendingDomain und TenantInboundAddress für bidirektionalen Gmail/Outlook-Sync.
|
||||
- *(→ v2, Scope-Schnitt 2026-06-11)* **REQ-email-sync-strategie**: Bidirektionaler Sync Gmail/Outlook über ProviderAdapter-Interface mit Auto-Matching von Absendern zu Contact/Lead.
|
||||
- *(→ v2, Scope-Schnitt 2026-06-11)* **REQ-email-inbox-view**: Inbox-View, Thread-View und Compose mit Permission-Scoping und CRM-Kontext-Verknüpfung.
|
||||
|
||||
### Modul 10 — Email-Marketing
|
||||
|
||||
- [ ] **REQ-marketing-datenmodell**: Campaign, OutboundEmail, EmailTemplate, RecipientSegment und EmailSuppressionList als Datenmodell mit DSGVO-konformem Tracking.
|
||||
- [ ] **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)
|
||||
|
||||
- [ ] **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.
|
||||
|
||||
### Modul 13 — Team-Chat
|
||||
|
||||
- [ ] **REQ-chat-datenmodell**: TeamChat, TeamChatMessage, Threads, Reactions und TeamChatRead als Datenmodell für drei Channel-Typen (public, private, entity-linked).
|
||||
- [ ] **REQ-chat-realtime**: WebSocket-basiertes Real-Time-Messaging mit Presence, Typing-Indicator, Read-Receipts und Redis-Pub/Sub für Scale-Out.
|
||||
- [ ] **REQ-chat-features**: Link-Previews, File-Uploads, @Mentions, Chat-Verlaufs-Suche und Entity-linked Channels im Deal/Projekt-Detail.
|
||||
|
||||
### Modul 14 — HR-Hub
|
||||
|
||||
- [ ] **REQ-hr-datenmodell**: HrEmployeeProfile, EmployeeVacationRequest, EmployeeSickLeaveReport, EmployeePayslip und HrRequest als Datenmodell mit AES-256-GCM-Verschlüsselung für sensible Daten.
|
||||
- [ ] **REQ-hr-passwort-safe**: Verschlüsselter Passwort-Safe pro Mitarbeiter mit KMS-backed Envelope-Encryption, Audit-Trail und DSGVO-Export.
|
||||
- [ ] **REQ-hr-urlaub-krank**: Urlaubs-Anfrage-Workflow (mehrstufiger Approval) und Krankmeldungs-Erfassung mit Abwesenheits-Kalender-Integration.
|
||||
|
||||
### Modul 15 — Customer-Portal
|
||||
|
||||
- *(→ 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.
|
||||
|
||||
### 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-flow-editor**: Graph-basierter visueller Flow-Editor mit KI-Erstellung per natürlicher Sprache (DE), Dry-Run und 24h-Undo.
|
||||
- [ ] **REQ-automation-schutz**: Loop-Guard, Rate-Limit, Idempotenz-Key, Resume-Mode und Trigger-Volumen-Metering pro Tenant.
|
||||
|
||||
### Modul 18 — ~~KI-Layer~~ → MCP-Server ([[AD-26]])
|
||||
|
||||
> ⛔ **KI→MCP-Pivot ([[AD-26]]):** HiveGrid hostet kein eigenes LLM/RAG/Whisper mehr, sondern wird Remote-MCP-Server. Die vier KI-Requirements unten sind **entfernt bzw. zurückgestellt**; an ihre Stelle tritt `REQ-mcp-server` (siehe unten). Verbindliche Bau-Spec: [[VR-MCP]]/[[VD-MCP]].
|
||||
|
||||
- [ ] **REQ-mcp-server**: Remote-MCP-Server (Streamable HTTP, `@modelcontextprotocol/sdk`), der HiveGrid-Daten als **Read-Ressourcen** und freigegebene Schreib-Operationen als **Action-Tools** für externe KI-Clients bereitstellt. **Auth = API-Key + Scopes + Rate-Limit aus der Public-API** ([[VR-P22]]); Tenant wird aus dem Token abgeleitet, jeder Zugriff läuft durch `withTenantScope()`/RLS. Jede Action ist `withPermission()`-gegated, erzwingt bei Schreib-Operationen eine **Confirmation** und wird via M001-Audit protokolliert (Actor-Kind „MCP/Agent"). Keine neuen KI-Entitäten — Nutzung von `ApiKey`/`Credential` (ggf. kleine `McpGrant`/Scope-Tabelle).
|
||||
- ~~**REQ-ki-llm-gateway**: EU-only LLM-Gateway (Mistral La Plateforme primär; …) mit Token-Tracking und Pay-as-you-go-AI-Credits.~~ → **entfernt (KI→MCP, [[AD-26]])** — kein eigenes LLM-Gateway.
|
||||
- ~~**REQ-ki-rag-embeddings**: RAG-Pipeline mit pgvector, Outbox-Pattern für Embedding-Jobs und RLS-gefiltertem Top-K-Retrieval.~~ → **zurückgestellt (KI→MCP, [[AD-26]]; v3-Kandidat)**.
|
||||
- ~~**REQ-ki-whisper**: Whisper-Transkription für Anruf-Aufzeichnungen über EU-Endpoint mit Token-Tracking und AiCredits-Deduktion.~~ → **zurückgestellt (KI→MCP, [[AD-26]]; v3-Kandidat)**.
|
||||
- ~~**REQ-ki-hivemind**: HiveMind-KI-Assistent mit kontextuellem RAG-Chat, Conversation-History und Promptfoo-basiertem Sicherheits-Testing.~~ → **zurückgestellt (KI→MCP, [[AD-26]]; v3-Kandidat)**.
|
||||
|
||||
### 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.
|
||||
|
||||
### Modul 20 — Dashboard
|
||||
|
||||
- [ ] **REQ-dashboard-datenmodell**: Dashboard, DashboardLayout und WidgetInstance als Datenmodell mit Role-Default-Layouts (SHK-Template geseedet). *(Scope-Schnitt 12.06.: 3 feste Rollen-Layouts GF/Büro/Monteur; Drag&Drop + User-Layout-Persistenz → v2.)*
|
||||
- [ ] **REQ-dashboard-widgets**: Widget-Katalog mit Datenquellen aus Sales, Projekte, Tasks, HR und KI; Realtime-Updates via WebSocket/SSE und Aggregat-Cache.
|
||||
|
||||
### 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.
|
||||
|
||||
### 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.)*
|
||||
|
||||
### Modul 23 — Files
|
||||
|
||||
- [ ] **REQ-files-datenmodell**: File, FileChunk, FileUploadProgress und FileEntityLink als Datenmodell mit S3-kompatiblem Object-Storage-Backend (Hetzner, Infra-ADR-009) und RLS auf Storage-Pfaden. *(Scope-Schnitt 12.06.: FileVersion → v2.)*
|
||||
- [ ] **REQ-files-upload-preview**: Chunked-Upload (TUS), Preview-Generierung (PDF→PNG, Bild→WebP, **HEIC→JPG** — Pflicht für iPhone-Monteur-Fotos) und Customer-Portal-Upload-Unterstützung. *(Scope-Schnitt 12.06.: Versionierung, Office-/Video-Previews, Resume-Upload, OCR → v2.)*
|
||||
|
||||
### Modul 24 — Globale Suche
|
||||
|
||||
- [ ] **REQ-suche-datenmodell**: SearchIndexEntry, RecentSearch und Outbox-Pattern für Index-Jobs nach Entity-Mutationen. *(Scope-Schnitt 11.06., AD-5 sequenziert: pgvector-Embedding-Spalte → v2 mit HiveMind; Outbox-Events sind der v1-Andock-Adapter.)* **⚠️ KI→MCP-Pivot ([[AD-26]]): Die KI/Embedding-Hälfte ruht — RAG/pgvector entfällt; das `embedding`-Feld bleibt ungenutzt. Meilisearch-Keyword-Suche bleibt unverändert.**
|
||||
- [ ] **REQ-suche-hybrid**: Keyword-Suche via Meilisearch mit permission-awarem SearchAdapter-Interface (INTEGRATION-CONTRACTS §8). *(Scope-Schnitt 11.06., AD-5 sequenziert: pgvector/Hybrid-RRF-Fusion → v2 mit HiveMind.)* **⚠️ KI→MCP-Pivot ([[AD-26]]): pgvector/Hybrid-RRF-Fusion ruht (RAG 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.
|
||||
|
||||
### Modul 25 — Calendar-Sync
|
||||
|
||||
- [ ] **REQ-kalender-datenmodell**: CalendarConnection, CalendarEvent, CalendarEventMapping und CalendarSyncCursor für bidirektionalen Google/Outlook-Sync mit verschlüsselten OAuth-Tokens.
|
||||
- [ ] **REQ-kalender-sync-adapter**: CalendarAdapter-Interface (GoogleCalendarAdapter + OutlookAdapter) mit Auto-Token-Refresh, Webhook-Subscriptions und bidirektionaler HiveGrid-Terminanlage.
|
||||
|
||||
### Modul 26 — Tasks
|
||||
|
||||
- [ ] **REQ-tasks-datenmodell**: Task mit Status, Priorität, Fälligkeit, Entitäts-Verknüpfung (Contact/Company/Lead/Deal/Project) und TaskWatcher.
|
||||
- [ ] **REQ-tasks-reminder-archivierung**: Reminder-System via M22 (konfigurierbare Vorlaufzeit) und Auto-Archivierung abgeschlossener Tasks nach 30 Tagen per Cron.
|
||||
|
||||
### Modul 27 — Auth / Multi-Tenancy / Permissions
|
||||
|
||||
- [ ] **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.
|
||||
- [ ] **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 Stripe-Integration, Frozen-Modus (Read-Only-Middleware), AI-Credits-Konto und Stripe-Webhook-Verarbeitung.
|
||||
- [ ] **REQ-billing-trial-dunning**: 14-Tage-Trial ohne Kreditkarte, Dunning-Email-Sequenz (Tag 1/3/7) bei fehlgeschlagener Zahlung und anschließender Frozen-Modus.
|
||||
|
||||
### 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 (5 Contacts, 3 Deals, 2 Projekte, Tasks) mit Lösch-Funktion via is_demo_data-Flag. *(Scope-Schnitt 12.06.: KI-Walkthrough → v2 mit Wizard-UI; Settings-Knopf statt Wizard-Schritt, einfaches Löschen.)*
|
||||
|
||||
### 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.)*
|
||||
|
||||
### 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.)*
|
||||
|
||||
### Modul 32 — Feature-Flags
|
||||
|
||||
- [ ] **REQ-feature-flags-system**: Platform-Admin-Feature-Flag-System (FeatureFlag + TenantFeatureFlag) mit Redis-Cache, FeatureFlagFilter für automatische Aktivierung und AdminAuditLog.
|
||||
|
||||
### 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, Stripe), Connection-Health-Monitoring und Settings-UI.
|
||||
|
||||
### Modul 34 — Public API & Webhooks
|
||||
|
||||
- *(→ v2, Scope-Schnitt 2026-06-11)* **REQ-public-api-read**: Phase-1 Read-Only REST-API für Contacts, Deals, Leads, Projects, Tasks und Companies mit API-Key-Auth, Rate-Limit und Auto-genierter OpenAPI-Spec.
|
||||
- *(→ v2, Scope-Schnitt 2026-06-11)* **REQ-public-webhooks**: Incoming Lead-Push Webhooks und ausgehende Webhook-Subscriptions mit HMAC-SHA256-Signatur, Retry-Logik und WebhookDelivery-Logging.
|
||||
|
||||
### 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-tenant-deletion**: Tenant-Account-Löschung mit Crypto-Shredding (Per-Tenant-DEK löschen), Stripe-Subscription-Cancel und vollständiger Storage/Cache-Bereinigung.
|
||||
|
||||
### Modul 36 — Mobile-PWA (PWA-only, kein nativer Client)
|
||||
|
||||
- *(→ v2, Scope-Schnitt 2026-06-11; PWA-only, AD-17)* **REQ-mobile-pwa**: Installierbare PWA (iOS Safari ≥ 16, Android Chrome ≥ 10) mit Service-Worker, Add-to-Homescreen, App-Manifest und Kamera-Upload über Web-APIs. *(Expo/Capacitor/native App verworfen — PWA-only, AD-17; nativer Client + App-Store → frühestens v3.)*
|
||||
- *(→ v2, Scope-Schnitt 2026-06-11)* **REQ-mobile-offline-sync**: Voller Offline-Betrieb mit IndexedDB-lokalem Daten-Subset, OfflineSyncQueue, KWP-gewinnt-Konfliktauflösung und Offline-Indikatoren.
|
||||
- *(→ v2, Scope-Schnitt 2026-06-11; PWA-only, AD-17)* **REQ-mobile-push**: Web-Push (VAPID) mit NotificationDevice-Registrierung und Token-Rotation. *(APNs/FCM/nativer Push verworfen — Web-Push-only, AD-17.)*
|
||||
|
||||
### Modul 37 — Plattform-Admin
|
||||
|
||||
- [ ] **REQ-plattform-admin-identität**: Admin-Welt auf `admin.hivegrid.de` (Host-Routing, Cookie-Domain-Trennung zu app.*) mit TOTP-Pflicht + MFA-Step-up; Admin-User ohne Tenant-Workspace. *(Scope-Schnitt 12.06.: getrennte AdminUser-Identität/AdminSession/AdminRBAC = M038/M039 → v2; v1 = Boilerplate-Modell User-Extension + `admin-mfa-gate`.)*
|
||||
- [ ] **REQ-plattform-admin-features**: Tenant-Management, Subscription-Overrides, Feature-Flag-Verwaltung, BullMQ-Queue-Monitoring und Support-Inbox aus M39.
|
||||
|
||||
### Modul 38 — Help-Center (öffentlich)
|
||||
|
||||
- *(→ v2, Scope-Schnitt 2026-06-11)* **REQ-help-center**: Dateibasiertes Markdown-Help-Center mit Build-generiertem Index, client-seitiger FlexSearch-Suche, Deep-Links aus der App und SSR-SEO.
|
||||
|
||||
### Modul 39 — Help-Desk / Support
|
||||
|
||||
- [ ] **REQ-feedback-widget**: In-App Feedback-Widget (Bug/Feature/Frage/Sonstiges) mit Rate-Limit, Screenshot-Anhang via M23 und Platform-Admin-Support-Inbox in M37.
|
||||
|
||||
### 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-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.
|
||||
- [ ] **REQ-integration-view-model-pflicht**: Jede Route gibt im Loader ein View-Model zurück; UI-Components empfangen nur VM + Action-Callbacks, kein direkter DB-Zugriff.
|
||||
- [ ] **REQ-integration-smoke-tests**: Jede neue Route bekommt einen Smoke-Test in e2e/smoke/{modul}.spec.ts gegen packages/ui-mock.
|
||||
|
||||
## v2 Requirements
|
||||
|
||||
**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`):**
|
||||
- **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
|
||||
- ~~**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
|
||||
- **Help:** REQ-help-center — v1 = Minimal-FAQ; REQ-feedback-widget bleibt v1
|
||||
- **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
|
||||
|
||||
**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
|
||||
- **Als Dünnungs-Notes (REQ bleibt v1):** Notification-Bündelung/Quiet-Hours (M117), Sprach-Wechsler/EN-Templates (v1 DE-only, i18n-ready Pflicht), getrennte AdminUser-Identität (M038/M039; Auflagen: kein Tenant-Workspace, admin.hivegrid.de-Host-Routing + Cookie-Trennung), Datei-Versionierung/Office-Video-Preview/OCR (HEIC→JPG bleibt!), Dashboard-Drag&Drop (3 feste Rollen-Layouts), Audit-Retention-Konfigurierbarkeit/Legal-Hold
|
||||
|
||||
Bereits zuvor v2 (in Phase-1-Specs referenziert, nicht vollständig spezifiziert):
|
||||
|
||||
- **M11 WhatsApp**: Von M13 (Team-Chat) und M18 (KI-Layer/send-whatsapp-Action) referenziert; vollständige Spec und Implementierung verschoben auf Phase 2.
|
||||
- **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-signatur-provider Fallback**: Einfacher PDF-Upload mit manueller Signatur-Erfassung als Fallback ohne externen Signatur-Provider — Phase 2.
|
||||
- **DeepL-Übersetzungs-Pipeline (M30)**: Automatische Übersetzungsvorschläge via DeepL für Locale-Files — Phase 2.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
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 |
|
||||
| Volle Migrations-Pipelines pro Altsystem | Sauberer Start; KWP-Sync füllt nach; HubSpot/Quiply als Read-only-Archiv, nur punktuelle CSV-Importe (AD-14) |
|
||||
| ~~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 |
|
||||
|
||||
## Traceability
|
||||
|
||||
Phase-Mapping aus ROADMAP.md (Stufe 2, revidiert auf 21 Phasen). Bau-Reihenfolge nach AD-11; jede Zeile genau einer Phase zugeordnet (100 % Coverage).
|
||||
|
||||
| Requirement | Phase | Status |
|
||||
|-------------|-------|--------|
|
||||
| REQ-integration-sidebar | Phase 1 | Pending |
|
||||
| REQ-integration-routes | Phase 1 | Pending |
|
||||
| REQ-integration-activity-wiring | Phase 1 | Pending |
|
||||
| REQ-integration-audit-wiring | Phase 1 | Pending |
|
||||
| REQ-integration-notification-wiring | Phase 1 | Pending |
|
||||
| REQ-integration-view-model-pflicht | Phase 1 | Pending |
|
||||
| REQ-integration-smoke-tests | Phase 1 | Pending |
|
||||
| REQ-auth-multi-tenancy | Phase 2 | Pending |
|
||||
| REQ-auth-methoden | Phase 2 | Pending |
|
||||
| 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-notification-datenmodell | Phase 1 | Pending |
|
||||
| REQ-notification-versand-pipeline | Phase 3 | Pending |
|
||||
| REQ-i18n-architektur | Phase 1 | Pending |
|
||||
| REQ-i18n-outbound | Phase 3 | Pending |
|
||||
| REQ-feature-flags-system | Phase 1 | Pending |
|
||||
| REQ-files-datenmodell | Phase 4 | Pending |
|
||||
| REQ-files-upload-preview | Phase 4 | Pending |
|
||||
| REQ-tasks-datenmodell | Phase 4 | Pending |
|
||||
| REQ-tasks-reminder-archivierung | Phase 4 | Pending |
|
||||
| REQ-apps-engine-datenmodell | Phase 5 | Pending |
|
||||
| REQ-apps-engine-lifecycle | Phase 5 | Pending |
|
||||
| REQ-crm-datenmodell | Phase 6 | Pending |
|
||||
| REQ-crm-listen-views | Phase 6 | Pending |
|
||||
| REQ-crm-detail-views | Phase 6 | Pending |
|
||||
| REQ-lead-projekt-konvertierung | Phase 6 | Pending |
|
||||
| REQ-crm-activity-stream | Phase 6 | Pending |
|
||||
| REQ-crm-custom-felder | Phase 6 | Pending |
|
||||
| REQ-crm-duplikat-erkennung | Phase 6 | Pending |
|
||||
| REQ-crm-tags | Phase 6 | Pending |
|
||||
| REQ-crm-permissions | Phase 6 | Pending |
|
||||
| REQ-lead-inbox-liste | Phase 7 | Pending |
|
||||
| REQ-lead-quellen-auto-anlage | Phase 7 | Pending |
|
||||
| REQ-lead-status-workflow | Phase 7 | Pending |
|
||||
| REQ-lead-anti-spam | Phase 7 | Pending |
|
||||
| REQ-lead-statistiken | Phase 7 | Pending |
|
||||
| REQ-lead-permissions | Phase 7 | Pending |
|
||||
| REQ-projekt-kern-datenmodell | Phase 8 | Pending |
|
||||
| REQ-pipeline-rechte-config | Phase 8 | Pending |
|
||||
| REQ-projekt-kanban-listen-view | Phase 8 | Pending |
|
||||
| REQ-projekt-pipeline-wechsel | Phase 8 | Pending |
|
||||
| REQ-projekt-forecast-kpis | Phase 8 | Pending |
|
||||
| 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-dashboard-datenmodell | Phase 11 | Pending |
|
||||
| REQ-dashboard-widgets | Phase 11 | Pending |
|
||||
| REQ-automation-datenmodell | Phase 12 | Pending |
|
||||
| REQ-automation-trigger-library | Phase 12 | Pending |
|
||||
| REQ-automation-action-library | Phase 12 | Pending |
|
||||
| REQ-automation-flow-editor | Phase 12 | Pending |
|
||||
| REQ-automation-schutz | Phase 12 | Pending |
|
||||
| ~~REQ-ki-llm-gateway~~ → entfernt ([[AD-26]]) | ~~Phase 13~~ | Entfällt (KI→MCP) |
|
||||
| REQ-mcp-server *(neu, [[AD-26]])* | v2-P4 (MCP) / [[VR-MCP]] | Pending |
|
||||
| REQ-email-datenmodell | Phase 14 | Pending |
|
||||
| REQ-marketing-datenmodell | Phase 14 | Pending |
|
||||
| REQ-marketing-double-optin | Phase 14 | Pending |
|
||||
| REQ-marketing-versand | Phase 14 | Pending |
|
||||
| REQ-telefonie-datenmodell | Phase 15 | Pending |
|
||||
| REQ-telefonie-provider-adapter | Phase 15 | Pending |
|
||||
| REQ-chat-datenmodell | Phase 15 | Pending |
|
||||
| REQ-chat-realtime | Phase 15 | Pending |
|
||||
| REQ-chat-features | Phase 15 | Pending |
|
||||
| REQ-kalender-datenmodell | Phase 16 | Pending |
|
||||
| REQ-kalender-sync-adapter | Phase 16 | Pending |
|
||||
| REQ-booking-datenmodell | Phase 16 | Pending |
|
||||
| REQ-booking-slot-kalkulierung | Phase 16 | Pending |
|
||||
| REQ-booking-integrationen | Phase 16 | Pending |
|
||||
| REQ-form-datenmodell | Phase 16 | Pending |
|
||||
| REQ-form-editor | Phase 16 | Pending |
|
||||
| REQ-form-actions | Phase 16 | Pending |
|
||||
| REQ-signatur-datenmodell | Phase 16 | Pending |
|
||||
| REQ-signatur-provider | Phase 16 | Pending |
|
||||
| REQ-hr-datenmodell | Phase 17 | Pending |
|
||||
| REQ-hr-passwort-safe | Phase 17 | Pending |
|
||||
| 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-dsgvo-export | Phase 21 | Pending |
|
||||
| REQ-dsgvo-tenant-deletion | Phase 21 | Pending |
|
||||
| REQ-feedback-widget | Phase 21 | Pending |
|
||||
|
||||
**Coverage:**
|
||||
- v1 requirements: 90 total (Scope-Schnitte 2026-06-11/12: 19 → v2; **Pivot-Neuzählung 16.06.: REQ-crm-lead-promotion entfällt −1, REQ-rechnung-sub-entity NEU +1 → Netto unverändert 90**)
|
||||
- Mapped to phases: 90 (100 %)
|
||||
- Unmapped: 0
|
||||
|
||||
**Pro-Phase-Verteilung:**
|
||||
|
||||
| Phase | Requirements |
|
||||
|-------|--------------|
|
||||
| Phase 1 — Fundament & Walking-Skeleton | 11 |
|
||||
| Phase 2 — Identität & Mandantentrennung | 4 |
|
||||
| Phase 3 — Querschnitts-Oberflächen | 4 |
|
||||
| Phase 4 — Files & Tasks | 4 |
|
||||
| Phase 5 — Apps-Engine & Integrations-Framework | 2 |
|
||||
| Phase 6 — CRM-Kern | 9 |
|
||||
| Phase 7 — Lead-Inbox | 6 |
|
||||
| Phase 8 — Projekt & Pipelines (Teil 1: Kern + Pipeline-Engine) | 5 |
|
||||
| Phase 9 — Projekt & Pipelines (Teil 2: Auftrags-Features + Sub-Areas) | 3 |
|
||||
| Phase 10 — KWP-Integration | 0 (→ v2, erstes v2-Modul) |
|
||||
| Phase 11 — Globale Suche & Dashboard | 5 |
|
||||
| Phase 12 — Automation-Engine | 5 |
|
||||
| Phase 13 — KI-Layer | 1 |
|
||||
| Phase 14 — Email & Marketing | 4 |
|
||||
| Phase 15 — Telefonie & Team-Chat | 5 |
|
||||
| Phase 16 — Kalender, Booking, Forms & Signatur | 10 |
|
||||
| Phase 17 — HR-Hub | 3 |
|
||||
| Phase 18 — Customer-Portal | 0 (→ v2) |
|
||||
| Phase 19 — Plattform-Admin | 2 |
|
||||
| Phase 20 — Billing, Onboarding & Branding | 4 |
|
||||
| Phase 21 — DSGVO & Launch-Reife | 3 |
|
||||
| **Summe** | **90** |
|
||||
|
||||
---
|
||||
*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 (90 v1, davon 3 KWP = erstes v2-Modul), 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; Req-Summe neu gezählt = 90 (Netto unverändert: −1 lead-promotion / +1 rechnung).** *
|
||||
Binary file not shown.
@@ -0,0 +1,238 @@
|
||||
# Roadmap: HiveGrid 2.0 — v2 (Mo 13.07. – Fr 31.07.2026)
|
||||
|
||||
> **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.
|
||||
|
||||
## 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**, **HiveMind/RAG** 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.
|
||||
|
||||
**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.
|
||||
|
||||
### ⚠️ Zwei Gaps (vor Bau zu schließen)
|
||||
- **HalloPetra (M105):** kommt in **keiner Spec** vor. M12 ist eine reine AirCall-Spec. HalloPetra wäre ein **zweiter Telefonie-Provider** über das vorhandene `TelephonyProviderInterface` — mechanisch klar, inhaltlich unspezifiziert. → eigene Vorlauf-Spec (API-Vertrag) nötig.
|
||||
- **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.
|
||||
|
||||
### 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.
|
||||
|
||||
---
|
||||
|
||||
## Phasen-Übersicht
|
||||
|
||||
| v2-Phase | Titel | MS | Owner | Slot | UI |
|
||||
|---|---|---|---|---|---|
|
||||
| v2-P1 | Public-API & Webhooks | M161-163, M027 | Raffael | W1 | yes |
|
||||
| v2-P2 | Postfach-Sync (Email-Inbox) | M096-098 | Akeshan | W1 | yes |
|
||||
| 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-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.
|
||||
|
||||
### Nummern-Mapping: v2-Px ↔ ROADMAP-Phase 22–34 ↔ ex-Pn (C-2)
|
||||
|
||||
> Drei Nummernkreise zeigen auf dieselben Phasen: diese Datei (`v2-Px`), die v1-`ROADMAP.md` (fortlaufend `Phase 22–34`, die **Plane-Tickets nutzen 22–34**) und die alte v1-Roadmap-Nummern (`ex-Pn`, soweit ein v1-Platzhalter existierte). **Insb. KWP = v2-P5 = Phase 32 = ex-P10.**
|
||||
|
||||
| v2-Px (diese Datei) | ROADMAP.md Phase | ex-Pn | Titel |
|
||||
|---|---|---|---|
|
||||
| v2-P1 | Phase 22 | — | Public-API & Webhooks |
|
||||
| v2-P2 | Phase 23 | — | Postfach-Sync (Email-Inbox) |
|
||||
| v2-P3 | Phase 24 | — | Self-Service-Billing & Onboarding-Wizard |
|
||||
| v2-P4 | Phase 25 | — | KI-Tiefe — HiveMind/RAG |
|
||||
| **v2-P5** | **Phase 32** | **ex-P10** | **KWP-Integration (RECUT)** |
|
||||
| v2-P6 | Phase 26 | ex-P18 | Customer-Portal |
|
||||
| v2-P7 | Phase 27 | — | Mobile-PWA-Ausbau |
|
||||
| v2-P8 | Phase 28 | — | Plattform-Admin-Tiefe |
|
||||
| v2-P9 | Phase 29 | — | Help-Center & Help-Desk |
|
||||
| v2-P10 | Phase 30 (+ Phase 34 HR-Drittanbieter, M138) | — | Komfort & Querschnitt / Dashboard-Deluxe |
|
||||
| v2-P11 | Phase 31 (DSGVO) + Phase 33 (HalloPetra, M105) | — | Telefonie-Erweiterung & DSGVO-Vollausbau |
|
||||
|
||||
---
|
||||
|
||||
## Phase Details
|
||||
|
||||
### 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)
|
||||
**Success Criteria:**
|
||||
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 (`POST /webhooks/incoming/{tenant}/{slug}`) legen Leads an (API-Key/HMAC/URL-Token + Payload-Mapping + Auto-Match).
|
||||
3. Ausgehende WebhookSubscriptions: HMAC-SHA256-Signatur, Idempotenz-ID, Retry mit exp. Backoff (max 5), Auto-Disable nach 10 Fehlern.
|
||||
4. OpenAPI-3.1 auto-generiert (`/api/v1/openapi.json`) + Swagger-UI; Rate-Limit (1k/h Key, 10k/h Tenant) mit `X-RateLimit-*` + Klartext-429.
|
||||
**Screens (David):** API-Key-Verwaltung (Erweiterung) · Incoming-Webhook-Slug-Verwaltung + Ingestion-Log · Outgoing-Subscription-Liste/Detail (Secret-einmal-sichtbar, Delivery-Stats, Replay/Test) · API-Request-Logs + Usage-Aggregat
|
||||
**Recut/Risiko:** Bewusst **Read-only + Webhooks** (Voll-CRUD/GraphQL/3-Legged-OAuth = später). Vor Bau: OpenAPI-Tooling wählen, HMAC-Format dokumentieren.
|
||||
|
||||
### 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/Deal/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.
|
||||
2. Push-Sync (kein Primär-Polling) spiegelt Mails; Initial-Sync 90 Tage, resumebar mit Progress.
|
||||
3. Auto-Match: From-Adresse → Contact/Lead, Subject-Pattern (`[Deal #123]`), 1-offener-Deal-Heuristik; manueller Override sticht.
|
||||
4. Inbox-Liste (Filter/Suche/Bulk) + Detail mit Thread, sicherem HTML-Render (CSP, externe Bilder blockiert), Reply/Forward via Mailbox.
|
||||
5. `email.read_own` vs. `email.read_all` filtern Liste + Activity-Stream.
|
||||
**Screens (David):** Mailbox-Connect-Settings (Sync-Status/Reconnect) · Inbox-Liste · Mail-Detail (Thread/Verknüpfungs-Editor/Reply) · Outbound-Compose
|
||||
**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.
|
||||
**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-Stripe-Checkout + Webhook-Handler + StripeWebhookLog · 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)
|
||||
**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).
|
||||
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.
|
||||
**Screens (David):** Onboarding-Wizard (10 Steps, Vollbild) · Erste-Schritte-Checkliste-Widget + Detail · Demo-Daten-Verwaltung · Self-Service-Plan-Wechsel-Flow (Web) · Add-On-Kauf-Flächen
|
||||
**Recut/Risiko:** Self-Service ist v2, weil **konkrete Preise feststehen müssen** (in v1 EXT-14 fixiert) und das Wizard-/Abo-Baukasten-Delta Komplexität trägt — **nicht** mehr wegen Apple-Store-Auflagen (PWA-only → kein App-Store, Plan-Wechsel direkt im Web). Wizard-Framework ist großteils v1-fähig; v2-Delta = weitere Branchen + ~~KI-Coach~~ (entfällt — [[AD-26]]) + Migration-Importer.
|
||||
|
||||
### v2-P4: MCP-Server *(ex „KI-Tiefe — HiveMind/RAG", umgeschnitten via [[AD-26]])*
|
||||
> ⛔ **KI→MCP-Pivot ([[AD-26]]):** HiveGrid hostet kein eigenes LLM/RAG/Whisper mehr. Diese Phase liefert stattdessen einen **Remote-MCP-Server**, über den externe KI-Clients (Claude, ChatGPT-Connectors u.a.) HiveGrid-Daten lesen und freigegebene Aktionen ausführen. Verbindliche Bau-Spec: [[VR-MCP]] (Backend) / [[VD-MCP]] (Screens). Die alten HiveMind/RAG/Whisper-Inhalte stehen darunter durchgestrichen als **v3-Kandidat (zurückgestellt)**.
|
||||
**Owner:** Raffael · **Slot:** W1→W2 (Start 18./19.07.) · **Goal:** Ein produktiver, tenant-gescopeter Remote-MCP-Server stellt HiveGrid-Daten als Read-Ressourcen und freigegebene Aktionen als Action-Tools bereit — auditiert, permission-gegated, ohne eigenes LLM.
|
||||
**Milestones:** kein M0xx (v2-Neuschnitt) → siehe [[VR-MCP]]/[[VD-MCP]]
|
||||
**Source-Specs:** [[VR-MCP]] / [[VD-MCP]] · [[AD-26]]
|
||||
**Depends on:** v1-`ApiKey`-Auth + Scopes + Rate-Limit aus der Public-API ([[VR-P22]]) · v1-`withTenantScope()`/RLS · v1-`withPermission()` (M004) · v1-M001-Audit · `@modelcontextprotocol/sdk`
|
||||
**Success Criteria:**
|
||||
1. Remote-MCP-Server (Streamable HTTP, `@modelcontextprotocol/sdk`) exponiert Read-Ressourcen (Kontakte/Firmen/Leads/Projekte/Aufträge u.a.) und Action-Tools (definierte Schreib-Aktionen).
|
||||
2. Authentifizierung per **API-Key + Scopes + Rate-Limit** aus der Public-API ([[VR-P22]]); Tenant wird aus dem Token abgeleitet, jeder Zugriff läuft durch `withTenantScope()`/RLS.
|
||||
3. Jede Action ist `withPermission()`-gegated, verlangt bei schreibenden Operationen eine **Confirmation** und wird via M001-Audit protokolliert (Actor-Kind „MCP/Agent").
|
||||
4. Tenant-Admin verwaltet MCP-Zugänge/Scopes (UI aus [[VD-MCP]]); keine neuen KI-Entitäten — Nutzung von `ApiKey`/`Credential` (ggf. kleine `McpGrant`/Scope-Tabelle).
|
||||
**Screens (David):** siehe [[VD-MCP]] (MCP-Connection-Verwaltung, Scope-Auswahl, Audit-/Aktivitäts-Sicht der MCP-Zugriffe).
|
||||
**Recut/Risiko:** Kein LLM-Hosting → **kein Provider-AVV** und kein DSGVO-Provider-Constraint mehr; Sicherheit liegt vollständig in Tenant-Scope/RLS, Scope-Minimierung und Confirmation-Grenze für Schreib-Aktionen.
|
||||
|
||||
~~**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-`@toolctrl/storage` + FileEntityLink · v1-Extension-Points an Auftrag/Abnahme/Material (P9) · v1-P12 Automation (`kwp.push_auftrag`-Action) · AVV/Subprozessoren (P11)
|
||||
**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`.
|
||||
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).
|
||||
|
||||
### 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.
|
||||
**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>/…`
|
||||
**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.
|
||||
|
||||
### 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).
|
||||
2. Sync-on-Reconnect drainiert Queue idempotent (lokale UUID als Key), Append-only konfliktfrei, Status-Updates LWW mit Konflikt-Resolution.
|
||||
3. Installierbar: Web-App-Manifest + Add-to-Homescreen + Standalone-Display; Web-Push (VAPID); Kamera/Foto via Web-APIs (lokaler Resize); 2FA bleibt.
|
||||
4. Account-Löschung erreichbar; Force-Update via Service-Worker-Versionierung; Deeplinks.
|
||||
**Screens (David — mobile-first PWA-Shell, Touch-Paradigma):** Login + Setup · mobile Navigation (Baustelle/Büro) · Sync-Queue + Konflikt-Resolution · Mobile-Settings (Pre-Cache/Storage/Geräte) · Web-Push-Pre-Prompt + Force-Update-Modal · Install-Hinweis (A2HS)
|
||||
**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)
|
||||
**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.
|
||||
|
||||
### 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 RAG (Help-Artikel als Korpus) · v2-P10 i18n (Sprachsegment)
|
||||
**Success Criteria:**
|
||||
1. Markdown mit Frontmatter, Build-Time-Index (Volltext + Kategorien + Sitemap), Build-Fail bei kaputten Referenzen.
|
||||
2. Öffentliche Routen `/help/{lang}/{category}/{slug}` ohne Auth (vor Auth-Middleware), SEO-Defaults, Suche.
|
||||
3. Deep-Link Route→Artikel (Hilfe-Icon pro App-Route, Fallback Help-Home).
|
||||
4. Feedback-Widget (überall) → `Feedback` mit Auto-Kontext (tenant/user/route/browser/app-version), Screenshot-Option, Rate-Limit 10/h.
|
||||
5. Plattform-Admin: Feedback-Liste + Detail (Status-Lifecycle/Assignee/Notes/Attachments) mit Audit.
|
||||
**Screens (David):** Help-Home (Hero/Suche/Kategorien) · Kategorie-Seite · Artikel-Detail (TOC/verwandt/Vote) · Such-Ergebnisse · Feedback-Modal (in v1 schon klein da → ausbauen) · Admin-Feedback-Liste/Detail
|
||||
**Recut/Risiko:** Bewusst klein (Git-PRs, kein Editor-UI, kein volles Ticket-System in Phase 1). v2-später: DB-Pflege, KI-RAG-Suche, Mehrsprachigkeit, kontextuelle Inline-Hilfe, SLA/CSAT/Live-Chat. Support-Mailbox-Sync (Mails→Feedback) nutzt M9.
|
||||
|
||||
### 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.
|
||||
2. Notifications: Bündelung (gleicher event_type_group in 5-Min-Window → 1 Push/Mail mit count), Quiet-Hours (queued, Urgent-Override), Pro-User-Präferenzen Event×Kanal.
|
||||
3. i18n: Sprach-Wechsler (Profil + Public), EN-Locale befüllt (DeepL DE→EN mit Review), vollständige Build-Validierung, Fallback DE; Empfänger-Sprach-Auflösung Outbound.
|
||||
4. HR: Onboarding-Checklisten pro neuem MA (Forms/Tasks/Reminders) + Drittanbieter via Apps-Engine.
|
||||
**Screens (David):** Dashboard-Edit-Modus (Grid + Widget-Picker + Config) · Notification-Präferenzen-Editor + Quiet-Hours · Sprach-Wechsler + Tenant-Default · HR-Onboarding-Checklisten + Drittanbieter-Setup
|
||||
**Recut/Risiko:** ⚠️ **Gap M138:** Memberspot/Boobora nicht spezifiziert → eigene Drittanbieter-Spec (gleiche „API-Vertrag offen"-Abhängigkeit wie KWP). M20/M22/M30 großteils v1-fähig — v2-Delta = Custom-Dashboards/Export, Bundle/Quiet-Hours, EN+DeepL. Chat-Auto-Übersetzung (M30) koppelt an M13 + EU-LLM (P4).
|
||||
|
||||
### 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 · pgvector (Embedding-Löschung beim Hard-Delete)
|
||||
**Success Criteria:**
|
||||
1. HalloPetra als zusätzlicher Provider hinterm `TelephonyProviderInterface` ohne Kern-Umbau; Webhook-Auto-Match → Activity + Automation-Trigger.
|
||||
2. Click-to-Call + Inbound + Logging providerunabhängig (E.164-Normalisierung, Match-Confidence, Notiz-Editor).
|
||||
3. AVV-Versionierung mit dynamischem PDF + elektronischer Akzeptanz, Re-Akzeptanz bei Updates (14-Tage-Frist → Read-Only).
|
||||
4. Subprozessoren-Liste mit Drittland-Warnung + 14-Tage-Widerspruchs-Workflow.
|
||||
5. User-Daten-Export (Art. 15/20) + Tenant-Voll-Export (ZIP, async, 7-Tage-Window) + Tenant-Lösch-Workflow (30-Tage-Grace + Hard-Delete-Cron).
|
||||
**Screens (David):** Telefonie-Setup (Provider-Connect, User-Bindings, Test) · Call-Session-Detail · DSGVO/Privacy-Hub (Export-Jobs, Tenant-Lösch-Multi-Step + Slug-Confirm, Subprozessoren, AVV-Download/History) · User-Daten-Export/Account-Löschung · Admin: Subprozessoren + AVV-Versions-Verwaltung
|
||||
**Recut/Risiko:** ⚠️ **Gap HalloPetra:** keine Spec — API-Vertrag (Auth/Webhook-Events/Recording/Call-Lifecycle) erst erheben (eigener Vorlauf-Task). AVV-PDF-Inhalt anwaltlich finalisieren (in v1 EXT-03 beauftragt). Voicemail-Transkription via Whisper koppelt an P4.
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
- **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.
|
||||
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.*
|
||||
@@ -0,0 +1,589 @@
|
||||
# Roadmap: HiveGrid 2.0
|
||||
|
||||
## 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.
|
||||
|
||||
> 🔴 **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`.
|
||||
|
||||
## Phases
|
||||
|
||||
**Phase Numbering:**
|
||||
- Integer phases (1, 2, 3): Planned milestone work
|
||||
- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)
|
||||
|
||||
Decimal phases appear between their surrounding integers in numeric order.
|
||||
|
||||
- [ ] **Phase 1: Fundament & Walking-Skeleton** - Boilerplate einziehen, EU-Sterilisation, Querschnitts-Neubauten + Service-Kerne (Audit, Notifications, i18n, Feature-Flags), Integration-Contracts als Bau-Vertrag
|
||||
- [ ] **Phase 2: Identität & Mandantentrennung** - Auth, Multi-Tenancy, RLS-Baseline, RBAC, Sessions (API-Keys → v2 mit Public-API)
|
||||
- [ ] **Phase 3: Querschnitts-Oberflächen** - Audit-Viewer/Export, Notification-Center/Settings, Sprach-Settings DE-only (Service-Kerne liegen in Phase 1)
|
||||
- [ ] **Phase 4: Files & Tasks** - Nutzerseitige Plattform-Primitive: Datei-Verwaltung (chunked Upload, Preview inkl. HEIC→JPG) und Tasks
|
||||
- [ ] **Phase 5: Apps-Engine & Integrations-Framework** - DataConnection, Adapter-Registry, OAuth/API-Key-Connect-Lifecycle
|
||||
- [ ] **Phase 6: CRM-Kern** - Typisiertes CRM-Datenmodell, Listen/Detail-Views, Custom-Felder, Tags, Activity-Stream, Duplikate
|
||||
- [ ] **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 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, Sprach-zu-Automation
|
||||
- [ ] **Phase 13: KI-Layer** - EU-LLM-Gateway, Multi-Provider-Fallback, Promptfoo, Sprach-zu-Automation-Unterbau (HiveMind/RAG/Whisper → v2, Andock-Adapter in v1)
|
||||
- [ ] **Phase 14: Email & Marketing** - Sende-Domain-Verifikation, BCC-Logging-Brücke, DSGVO-konforme Marketing-Kampagnen (Postfach-Sync → v2)
|
||||
- [ ] **Phase 15: Telefonie & Team-Chat** - AirCall-Click-to-Call/Inbound, Real-Time-Team-Chat mit entity-linked Channels
|
||||
- [ ] **Phase 16: Kalender, Booking, Forms & Signatur** - Kalender-Sync, öffentliche Buchungsseiten, Form-Builder, Angebots-Signatur
|
||||
- [ ] **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** - Stripe-Billing/Trial/Dunning (Abo-Baukasten-Recut), Auto-SHK-Provisionierung, Theme-Preference
|
||||
- [ ] **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 = 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.
|
||||
|
||||
**Block 1 — sofort baubar (alle Infos vorhanden):**
|
||||
- [ ] **Phase 22: Public-API & Webhooks** - Versionierte Read-REST-API + signierte Webhooks + Tenant-API-Keys mit Scopes/Rate-Limit
|
||||
- [ ] **Phase 23: Postfach-Sync (Email-Inbox)** - Bidirektionale Gmail/Outlook-Inbox mit CRM-Matching, Threading, Versand über User-Mailbox
|
||||
- [ ] **Phase 24: Self-Service-Billing & Onboarding-Wizard** - Self-Service-Abo-Zusammenstellung (Web-Checkout) + geführter branchen-getriebener Wizard
|
||||
- [ ] **Phase 25: KI-Tiefe — HiveMind/RAG** - RAG über Tenant-Daten, EU-Whisper, pgvector-Hybrid-Suche, autonomer HiveMind-Agent (Action-Boundary)
|
||||
- [ ] **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 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)
|
||||
- [ ] **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)
|
||||
|
||||
## Phase Details
|
||||
|
||||
### Phase 1: Fundament & Walking-Skeleton
|
||||
**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 ToolCTRL-Boilerplate ist als Git-Downstream eingezogen, baut lokal durch und der upstream-Remote bleibt mergebar erhalten (AD-10). *Planner-Hinweis: Ist-Stand prüfen — laut ADR-Text „Docs-only", real ist die Codebase seit 2026-06-04 eingezogen; bereits Erledigtes nicht neu planen.*
|
||||
2. GitHub/Google-OAuth-Reste und `User.githubId/googleId` sind entfernt; keine US-Kern-Abhängigkeit mehr im Auth-Pfad (EU-Sterilisation).
|
||||
3. `logActivity()`, Search-Registry, Subframe-Adapter und Mass-Action-Schutz existieren als aufrufbare Querschnittsdienste mit Smoke-Test.
|
||||
4. Die Service-Kerne existieren als aufrufbare Dienste mit Smoke-Test: AuditEvent mit SHA-256-Hash-Kette via Prisma-Middleware (default-on), `notify()` mit Kanal-Abstraktion (In-App/Email; Push-Kanal als Stub bis v2), `packages/i18n` mit Build-Lint gegen Hard-Strings und Resolution User → Tenant → DE, Feature-Flag-Engine mit `tenantHasFlag()` + Redis-Cache (Admin-UI folgt in P19).
|
||||
5. **Entitlement-Gate-Pflicht (Konnektor-Prinzip):** Das Gate-Muster `tenantHasModule('<modul>')` existiert mit Beispiel-Anwendung an der Walking-Skeleton-Route — jede Modul-Phase registriert damit ihren Feature-Konnektor (Sidebar/Routes/Actions plan-gebunden schaltbar). Vorlage: `archive/hivegrid-cloud/app/config/pricing-plans.ts`.
|
||||
6. Eine Beispiel-Route gibt im Loader ein View-Model zurück, ist in der Sidebar registriert und hat einen grünen Smoke-Test gegen `packages/ui-mock`.
|
||||
7. Die verbindlichen URL-Schemata (App, Admin, Portal, Forms, Booking, Help, API) sind als geprüfte Konvention dokumentiert.
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 2: Identität & Mandantentrennung
|
||||
**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
|
||||
**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; 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).
|
||||
**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
|
||||
**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.)*
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 4: Files & Tasks
|
||||
**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
|
||||
**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.
|
||||
3. Ein Nutzer kann Tasks mit Status, Priorität, Fälligkeit und Entitäts-Verknüpfung (Contact/Company/Lead/Deal/Project) anlegen, sich als Watcher eintragen und einen Reminder (via notify()) erhalten.
|
||||
4. Abgeschlossene Tasks werden nach 30 Tagen per Cron auto-archiviert.
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 5: Apps-Engine & Integrations-Framework
|
||||
**Goal**: Externe Systeme werden über ein einziges, typsicheres Integrations-Framework angebunden — der Vertrag, über den später Gmail, Outlook, AirCall, PandaDoc, Stripe 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, PandaDoc) oder API-Key-Connect (KWP, Stripe) 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
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 6: CRM-Kern
|
||||
> 🔴 **Pivot-Note (AD-20, 13.06.):** Kontaktmodell wird umgebaut: `Kontakt` = Oberbegriff mit `Kontakttyp` (Privatperson/Organisation), `Kontaktstatus` (Kontakt/Kunde/Bestandskunde), `Kontaktart` (Haupt-/Sekundärkontakt als Rolle/Relation). Zwei Listen-Einstiege (Unternehmen/Organisationen + Kontakte). Custom-Fields + Pipeline-Feld-Config-Layer. SC/Reqs werden mit dem ER-Modell neu gefasst.
|
||||
|
||||
**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.
|
||||
3. Eine Detailansicht zeigt Inline-Edit, Activity-Stream (append-only Event-Sourcing), verknüpfte Entitäten und Custom-Felder; SHK-Branchen-Custom-Felder sind als Template geseedet.
|
||||
4. Beim Anlegen warnt ein Live-Match-Check vor Duplikaten; ein Lead wird bei `Weiterverarbeitungsfreigabe` zum `Projekt` konvertiert (Lead-Daten vererbt, Kontakt separat verknüpft — kein Promotions-Modal, AD-20).
|
||||
5. crm.*-Permission-Bundle (read_own/read_all/write/delete/admin) filtert serverseitig nach Owner; ein Nutzer ohne read_all sieht nur eigene Datensätze.
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 7: Lead-Inbox
|
||||
> 🔴 **Pivot-Note (AD-20, 13.06.):** Lead/LeadInput ist Vorstufe mit Datenpunkt `Weiterverarbeitungsfreigabe` (Ja/Nein/Unklar). **Lead → Projekt** statt Lead→Contact-Promotion (4-Optionen-Modal entfällt); Kontakt wird separat verknüpft. Vererbung relevanter Lead-Daten ins Projekt bei Freigabe. SC/Reqs werden mit dem ER-Modell neu gefasst.
|
||||
|
||||
**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-Verkaufsfall) → Phase 8 (braucht Deal-Entity); 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).
|
||||
3. Der Status-Workflow (new|qualified|converted|lost|spam) erlaubt nur definierte Übergänge; ein DSGVO-Auto-Lösch-Cron räumt alte Leads ab.
|
||||
4. Rate-Limiting/Anomalie-Detection schiebt verdächtige Leads in Quarantäne und benachrichtigt den Tenant-Admin.
|
||||
5. Eine Statistiken-Page zeigt KPI-Kacheln, Quellen-Aufschlüsselung und Trends, permission-aware (leads.*-Bundle mit Owner-Check).
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 8: Sales-Pipeline → **Projekt & Pipelines (Teil 1: Kern + Pipeline-Engine)**
|
||||
> 🔴 **Pivot-Note (AD-20, 13.06.):** P8+P9 verschmelzen konzeptionell zu „Projekt & Pipelines". P8 baut den **`Projekt`-Kern** (typisierte Superset-Tabelle + CustomFields) + die **Pipeline-Engine** (frei konfigurierbare Views: Pipeline anlegen/benennen, Zugriff je Rolle, Feld-Sichtbarkeit + Pflichtfelder pro Pipeline/Status, Statuswerte) + konfigurierbaren **Kanban** (ein Board statt Sales-Kanban + Projekt-Kanban). „Deal"/„Auftrag" = Pipeline-Typen. Forecast/Volumen-Field-Level-Rechte bleiben als Pipeline-typ-bedingte Features. SC/Reqs werden mit dem ER-Modell neu gefasst.
|
||||
|
||||
**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-Verkaufsfall, aus Phase 7 hierher)
|
||||
**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).
|
||||
3. Ein qualifizierter Lead erzeugt automatisch ein Projekt in der Sales-Pipeline (M049, konsumiert das `lead.qualified`-Event aus P7); ein gewonnenes Projekt wechselt nur die Pipeline (Auftrags-Sicht in Phase 9) — kein Won-Handoff, kein zweiter Datensatz; ein Auto-Archive-Cron räumt abgeschlossene Projekte.
|
||||
4. Forecast, KPIs pro Vertriebler, Stage-Conversion-Rates und Verlust-Grund-Auswertung werden mit Aggregat-Cache berechnet.
|
||||
5. Pipeline-Field-Level-Rechte (PipelineFieldVisibility, z.B. Auftragsvolumen nur für Vertrieb) blenden Felder für Nutzer ohne Recht aus.
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 9: Auftrags-/Projektpipeline → **Projekt & Pipelines (Teil 2: Auftrags-Features + Sub-Areas)**
|
||||
> 🔴 **Pivot-Note (AD-20, 13.06.):** Kein separates Project-Objekt mehr — die Auftrags-Welt ist eine **Pipeline-View auf denselben `Projekt`-Kern** (kein Won-Handoff, das Projekt wechselt nur die Pipeline/erhält Auftrags-Felder). P9 liefert die auftragsspezifischen Features: **Plantafel** (Scheduling pro Monteur), **Sub-Areas** am Projekt (Termine, **Rechnungen = neues Sub-Entity v1**, Checklisten, Aufgaben, Aktivitäten, Dokumente) und die **Abnahme als Checklisten/Protokoll-Sub-Area** (v1, rechtlich bindend, Touch-Signatur, offline; Mängel = Checkliste). Material/Zeiterfassung/Leistungspositionen/Baustelle/Support → v2-Backlog. SC/Reqs werden mit dem ER-Modell neu gefasst.
|
||||
|
||||
**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)
|
||||
**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.
|
||||
3. Ein Monteur kann ein immutables AbnahmeProtokoll (+ AbnahmeSignatur) als Sub-Area am Projekt mit Touch-Unterschrift erfassen — auch offline, mit späterem Sync und M05-Form-Template-Unterstützung; „Mängel" = Checkliste (typ=maengel).
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### 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.
|
||||
|
||||
**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.
|
||||
**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)
|
||||
**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.
|
||||
**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).
|
||||
|
||||
### 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)
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Self-hosted Meilisearch liefert permission-aware Keyword-Treffer über den SearchAdapter. *(Scope-Schnitt 11.06.: pgvector/Hybrid-RRF → v2 mit HiveMind; AD-5 sequenziert.)*
|
||||
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.
|
||||
4. Ein Nutzer sieht ein rollenbasiertes Dashboard (3 feste Rollen-Layouts GF/Büro/Monteur, SHK-Default geseedet) mit Widgets aus Sales, Projekte, Tasks, HR und KI. *(Scope-Schnitt 12.06.: Drag&Drop-Grid + User-Layout-Persistenz → v2; Widget-Registry bleibt voll — Inversion `M064→M147`.)*
|
||||
5. Dashboard-Widgets aktualisieren sich live (WebSocket/SSE) mit Aggregat-Cache.
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 12: Automation-Engine
|
||||
**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 und Sprach-zu-Automation-Erstellung.
|
||||
**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).
|
||||
2. Ein Nutzer erstellt eine Automation per natürlicher Sprache (DE), 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.
|
||||
**Plans**: TBD
|
||||
**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.
|
||||
**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.~~
|
||||
3. ~~Promptfoo-Suite (A.14) testet die ausgelieferten KI-Funktionen.~~
|
||||
4. ~~v2-Andock-Adapter existieren: `RetrievalProvider`-Interface, Outbox-Index-Events (via P11), Bestätigungs-Grenze als wiederverwendbares Muster.~~
|
||||
**Plans**: ~~TBD~~ → entfällt
|
||||
**UI hint**: ~~yes~~ → entfällt
|
||||
|
||||
### Phase 14: Email & Marketing
|
||||
**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
|
||||
**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).
|
||||
3. Marketing-Kampagnen versenden DSGVO-konform (Double-Opt-In, Suppression-Check, One-Click-Unsubscribe) über BullMQ mit Rate-Limiting und Bounce-Handling.
|
||||
4. Der Versand läuft über eine SMTP-Provider-Abstraktion (Mailjet — AD-6 gelockt 11.06.) ohne US-Kern-Abhängigkeit.
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 15: Telefonie & Team-Chat
|
||||
**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
|
||||
**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.
|
||||
3. Chat unterstützt @Mentions, File-Uploads (via Files), Link-Previews und Chat-Verlaufs-Suche.
|
||||
4. Entity-linked Channels erscheinen im Deal-/Projekt-Detail und verknüpfen die Konversation mit der CRM-/Projekt-Entität.
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 16: Kalender, Booking, Forms & Signatur
|
||||
**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
|
||||
**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).
|
||||
3. Ein Nutzer baut Formulare per Drag-&-Drop mit 12 Feld-Typen, Conditional Logic, SHK-Templates und iFrame-Embed; Post-Submit-Actions (Lead/Deal/Task, Webhook, Email, Automation-Trigger) feuern mit Field-Mapping und ActionLog.
|
||||
4. Angebote durchlaufen Multi-Signer-Signaturen via PandaDoc/DocuSign über die Apps-Engine mit Webhook-Verarbeitung und Status-Updates.
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 17: HR-Hub
|
||||
**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
|
||||
**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.
|
||||
3. Ein mehrstufiger Urlaubs-Approval-Workflow und Krankmeldungs-Erfassung speisen einen Abwesenheits-Kalender.
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### 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)
|
||||
**v1-Andockpunkte (bleiben):** P4-Portal-Upload-Vorbereitung (FileEntityLink), `portal.hivegrid.de` im P1-URL-Schema.
|
||||
**Plans**: — (v2)
|
||||
|
||||
### Phase 19: Plattform-Admin
|
||||
**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 + Stripe-Positionen — Abo-Baukasten-Mechanik; Self-Service-UI → v2)
|
||||
**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.)*
|
||||
3. Ein Admin überwacht BullMQ-Queues und bearbeitet eine Support-Inbox; AdminAuditLog protokolliert plattformweite Aktionen (tenantId=null) über die Audit-Hash-Kette.
|
||||
**Plans**: TBD
|
||||
**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 Stripe-Billing und kann sein Theme wählen.
|
||||
**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
|
||||
**Success Criteria** (what must be TRUE):
|
||||
1. Billing läuft über Stripe 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.
|
||||
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 (5 Contacts, 3 Deals, 2 Projekte, Tasks) lassen sich per Settings-Knopf provisionieren und via is_demo_data-Flag löschen. *(Scope-Schnitt 12.06.: KI-Walkthrough → v2 mit Wizard; 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.)*
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 21: DSGVO & Launch-Reife
|
||||
**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), Stripe-Cancel 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).
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
---
|
||||
|
||||
## v2 — Phase Details (22–34)
|
||||
|
||||
> Detail-Quelle mit allen Success-Criteria/Screens/Recut-Hinweisen: `.planning/ROADMAP-V2.md`. Dependency-Prinzip wie v1: keine Vorwärts-Abhängigkeiten; spätere Phasen integrieren sich rückwirkend.
|
||||
|
||||
### 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`
|
||||
**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.
|
||||
3. OpenAPI-3.1 auto-generiert + Swagger-UI; Rate-Limit (1k/h Key, 10k/h Tenant) mit `X-RateLimit-*` + Klartext-429.
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### 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)
|
||||
**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, 1-offener-Deal-Heuristik) mit manuellem Override; Inbox-Liste + Detail mit Thread, sicherem HTML-Render, Reply/Forward.
|
||||
3. `email.read_own`/`read_all` filtern Liste + Activity-Stream.
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
**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 (Stripe/Billing-Fundament)
|
||||
**Retro-Integration**: KI-Walkthrough-Coach wird von Phase 25 rückwirkend in den Wizard eingehängt (kein harter Forward-Dep).
|
||||
**Milestones**: M157 (+ M28-Self-Service-Delta, Block P)
|
||||
**Source-Specs**: `_bmad-output/specs/M28-subscriptions-billing.md` (Block P), `M29-onboarding.md`
|
||||
**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).
|
||||
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
|
||||
**UI hint**: yes
|
||||
**Risiko**: Grund für Self-Service-v2 sind die noch fehlenden konkreten Preise (v1 EXT-14, Kostenmatrix mit Partner) — **nicht** Apple-Store-Auflagen (PWA-only, kein App-Store, Cut #14/AD-17); Web-Checkout direkt.
|
||||
|
||||
### Phase 25: KI-Tiefe — HiveMind/RAG (v2)
|
||||
> ⛔ **KI→MCP-Pivot ([[AD-26]]): Phase 25 (HiveMind/RAG) zurückgestellt → ersetzt durch MCP-Server ([[VR-MCP]] / [[VD-MCP]]).** HiveGrid hostet kein eigenes RAG/Embedding/Whisper, sondern wird Remote-MCP-Server für externe KI-Clients. v2-P4 ist auf MCP umgeschnitten (siehe [[ROADMAP-V2]] v2-P4). Die HiveMind/RAG/Whisper-Inhalte unten sind als **v3-Kandidat zurückgestellt** und nur historisch erhalten.
|
||||
**Goal**: ~~Aus dem v1-LLM-Gateway wird semantische Tiefe — RAG über Tenant-Daten, EU-Whisper, perspektivisch der autonome HiveMind-Agent.~~ **→ ersetzt durch Remote-MCP-Server ([[VR-MCP]]).**
|
||||
**Depends on**: ~~Phase 13 (LLM-Gateway)~~ (entfällt — [[AD-26]]), Phase 11 (Outbox/Suche)
|
||||
**Retro-Integration**: ~~Phase 29 (Help) registriert seine Artikel rückwirkend als RAG-Korpus~~ → RAG entfällt; Help-Artikel können optional als MCP-Resource exponiert werden.
|
||||
**Milestones**: ~~M087 (+ Whisper-EU, pgvector-Hybrid-Suche, zweiter EU-Provider)~~ → gelöscht ([[AD-26]]); neuer v2-Neuschnitt = [[VR-MCP]] (kein M0xx-Milestone)
|
||||
**Source-Specs**: ~~`_bmad-output/specs/M18-ki-layer.md` (RAG/HiveMind/Whisper-Teile)~~ (entfällt — [[AD-26]])
|
||||
**Success Criteria** ~~(what must be TRUE)~~ — **zurückgestellt (v3-Kandidat), überholt durch [[AD-26]]**:
|
||||
1. ~~Embedding-Pipeline → `TenantEmbedding` (pgvector), Re-Embed per Hash-Diff, Permission-Pre-Filter vor Vector-Search; hybride globale Suche (Volltext+Vektor, RRF).~~
|
||||
2. ~~Whisper-EU transkribiert Voice-Notes async; Multi-Provider-Failover (Mistral→Scaleway→AlephAlpha) + Promptfoo in CI.~~
|
||||
3. ~~HiveMind-Agent liefert proaktive Vorschläge mit Action-Boundary (keine schreibenden Aktionen ohne Bestätigung), Audit-Trail, Scheduled-Actions.~~
|
||||
**Plans**: ~~TBD~~ → siehe [[VR-MCP]]/[[VD-MCP]]
|
||||
**UI hint**: yes
|
||||
**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`
|
||||
**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
|
||||
**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)
|
||||
**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.
|
||||
3. Web-Push (VAPID) aktiviert den in P1 ruhenden notify()-Push-Kanal; Account-Löschung erreichbar; Force-Update via Service-Worker-Versionierung.
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes (mobile-first PWA-Shell, Touch-Paradigma)
|
||||
**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).
|
||||
**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)
|
||||
**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.
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 29: Help-Center & Help-Desk (v2)
|
||||
**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**: liefert HelpArticle-Embeddings als RAG-Korpus an Phase 25.
|
||||
**Milestones**: M172, M173, M174, M175
|
||||
**Source-Specs**: `_bmad-output/specs/M38-help-center.md`, `M39-help-desk.md`
|
||||
**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.
|
||||
3. Plattform-Admin: Feedback-Liste + Detail (Status-Lifecycle/Assignee/Notes) mit Audit.
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
### Phase 30: Dashboard-Deluxe & Querschnitt (v2)
|
||||
**Goal**: Querschnitts-Komfort — anpassbare Dashboards/Export, Notification-Bündelung/Quiet-Hours, Sprach-Wechsler/EN.
|
||||
**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`
|
||||
**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.
|
||||
**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`
|
||||
**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.
|
||||
3. User-Daten-Export (Art. 15/20) + Tenant-Voll-Export (ZIP, async, 7-Tage-Window) + Tenant-Lösch-Workflow (30-Tage-Grace + Hard-Delete-Cron).
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
**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)**
|
||||
**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.
|
||||
**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.
|
||||
|
||||
### 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.**
|
||||
**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/Deal, Activity + Automation-Trigger; Click-to-Call + Inbound providerunabhängig.
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes (Setup-/Binding-Flächen)
|
||||
|
||||
### Phase 34: HR-Drittanbieter-Onboarding (v2)
|
||||
**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.**
|
||||
**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).
|
||||
**Plans**: TBD
|
||||
**UI hint**: yes
|
||||
|
||||
## Progress
|
||||
|
||||
**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.
|
||||
|
||||
| Phase | Plans Complete | Status | Completed |
|
||||
|-------|----------------|--------|-----------|
|
||||
| 1. Fundament & Walking-Skeleton | 0/TBD | Not started | - |
|
||||
| 2. Identität & Mandantentrennung | 0/TBD | Not started | - |
|
||||
| 3. Querschnitts-Oberflächen | 0/TBD | Not started | - |
|
||||
| 4. Files & Tasks | 0/TBD | Not started | - |
|
||||
| 5. Apps-Engine & Integrations-Framework | 0/TBD | Not started | - |
|
||||
| 6. CRM-Kern | 0/TBD | Not started | - |
|
||||
| 7. Lead-Inbox | 0/TBD | Not started | - |
|
||||
| 8. Sales-Pipeline | 0/TBD | Not started | - |
|
||||
| 9. Auftrags-/Projektpipeline | 0/TBD | Not started | - |
|
||||
| 10. KWP-Integration | 0/TBD | Not started | - |
|
||||
| 11. Globale Suche & Dashboard | 0/TBD | Not started | - |
|
||||
| 12. Automation-Engine | 0/TBD | Not started | - |
|
||||
| 13. KI-Layer | 0/TBD | Not started | - |
|
||||
| 14. Email & Marketing | 0/TBD | Not started | - |
|
||||
| 15. Telefonie & Team-Chat | 0/TBD | Not started | - |
|
||||
| 16. Kalender, Booking, Forms & Signatur | 0/TBD | Not started | - |
|
||||
| 17. HR-Hub | 0/TBD | Not started | - |
|
||||
| 18. Customer-Portal | → v2 | Deferred (11.06.) | - |
|
||||
| 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.) — | | | |
|
||||
| 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) | - |
|
||||
| 25. KI-Tiefe — HiveMind/RAG | 0/TBD | Not started (v2) | - |
|
||||
| 26. Customer-Portal ⭐ | 0/TBD | Not started (v2, ex-P18) | - |
|
||||
| 27. Mobile-PWA-Ausbau | 0/TBD | Not started (v2) | - |
|
||||
| 28. Plattform-Admin-Tiefe | 0/TBD | Not started (v2) | - |
|
||||
| 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. | - |
|
||||
| 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.*
|
||||
*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-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.*
|
||||
Binary file not shown.
@@ -0,0 +1,187 @@
|
||||
# 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 (Veto möglich): P11-Suche wird v1 Keyword-only** (Meilisearch); pgvector/Hybrid-RRF → v2 mit HiveMind. AD-5 wird sequenziert (Keyword v1, Hybrid v2). REQ-suche-hybrid wird entsprechend 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).
|
||||
- **Stripe (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!), Stripe-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).
|
||||
- **Stripe: 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 Stripe-Positionen. **M154-Recut:** Seat-Typ-Modell ersetzt durch Entitlement-Schicht = Feature-Flag-Engine (P1) × `packages/entitlements` × daten-getriebene Stripe-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` × Stripe-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** · Stripe (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), Stripe-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/Stripe + Onboarding-Wizard (P20-Teile, ~7 MS)
|
||||
- [ ] USP-Tiefe P12/P13 (RAG/HiveMind/Whisper dünnen?)
|
||||
|
||||
## Entscheidung #11 — Boilerplate-Recheck-Runde (2026-06-12)
|
||||
|
||||
Basis: Sweep über alle 37 Reports in `docs/boilerplate-mapping/` + 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.
@@ -0,0 +1,206 @@
|
||||
---
|
||||
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 + Stripe-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 · Stripe-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 → Stripe-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.
@@ -0,0 +1,134 @@
|
||||
---
|
||||
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 | **Stripe-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 (Stripe 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.
@@ -0,0 +1,561 @@
|
||||
---
|
||||
pdf_options:
|
||||
format: A4
|
||||
margin: 13mm
|
||||
printBackground: true
|
||||
css: |-
|
||||
body { font-family: -apple-system, "Segoe UI", Helvetica, Arial, sans-serif; font-size: 9px; color: #1f2937; line-height: 1.4; }
|
||||
h1 { font-size: 21px; margin: 0 0 2px; color: #0f172a; }
|
||||
p.lead { color: #475569; font-size: 10.5px; margin: 0 0 4px; }
|
||||
p.meta { color: #64748b; font-size: 8.5px; margin: 0 0 10px; }
|
||||
h2 { font-size: 14px; color: #b45309; border-bottom: 2.5px solid #f5a623; padding-bottom: 4px; margin: 0 0 8px; page-break-before: always; break-before: page; break-after: avoid; page-break-after: avoid; }
|
||||
h2.idx { page-break-before: always; }
|
||||
h3 { font-size: 10.5px; margin: 12px 0 3px; color: #0f766e; break-after: avoid; page-break-after: avoid; }
|
||||
h3.gate { color: #b91c1c; }
|
||||
table { font-size: 8.5px; border-collapse: collapse; width: 100%; margin: 0 0 5px; break-inside: avoid; page-break-inside: avoid; }
|
||||
thead { display: table-header-group; }
|
||||
tr { break-inside: avoid; page-break-inside: avoid; }
|
||||
td, th { border: 1px solid #e2e8f0; padding: 3px 6px; text-align: left; vertical-align: top; break-inside: avoid; page-break-inside: avoid; }
|
||||
th { background: #fff7e8; color: #92400e; font-size: 8px; text-transform: uppercase; letter-spacing: 0.3px; }
|
||||
td:nth-child(1) { font-family: "SF Mono", Menlo, monospace; font-weight: 600; color: #0f172a; white-space: nowrap; width: 70px; }
|
||||
td:nth-child(2) { white-space: nowrap; width: 62px; color: #334155; }
|
||||
td:nth-child(3) { white-space: nowrap; width: 42px; color: #64748b; }
|
||||
tr.b2 td:nth-child(1) { color: #b91c1c; }
|
||||
strong { color: #b45309; }
|
||||
---
|
||||
|
||||
# HiveGrid 2.0 — Sprint-Tagesplan (ticket-genau)
|
||||
|
||||
> ⛔ **KI→MCP-Pivot ([[AD-26]], 2026-06-22) — Tagesplan-Delta:** **R-P13** (KI-Layer) + **D-P13** + **EXT-11** (Mistral-Key) + Milestones **M083–M088** entfallen. **R-P12b** ist neues letztes v1-Glied (Sprach→Automation gestrichen → reiner Flow-Editor); der **09.07.** wird Härtungstag (Freeze/Launch unverändert). In v2: **VR-P25/VD-P25** (HiveMind/RAG) zurückgestellt → **[[VR-MCP]]/[[VD-MCP]]** (MCP-Server) im Slot 18.–20.07. Die KI-Zeilen in den Tabellen unten sind insoweit überholt — autoritativ sind [[AD-26]] + die Ticket-Docs.
|
||||
|
||||
<p class="lead">Jedes Ticket an seinem Start-Tag · ID · Wer · Fenster (Start→Ziel) · Aufgabe · 152 Sprint-Tickets (v1: 110 · v2: 42) + 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
|
||||
*→ Gate W1 (Fr 19.06.)*
|
||||
### Di 16.06. · 24 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-INFRA1 | Akeshan | 17.06. | Infra-Live: Staging + Coolify-Apps + PG/Redis/PgBouncer |
|
||||
| D-D0a | David | 18.06. | D0 Design-System + App-Shell (A1) |
|
||||
| D-WEB | David | 16.06. | Website-Screens + Brand-Tokens |
|
||||
| EXT-02 | Raffael | 16.06. | Mailjet Sende-Domain (SPF/DKIM/DMARC) + Warm-up |
|
||||
| EXT-03 | Dejan | 19.06. | Anwalt: AVV + DSGVO-Auskunft + Website-Rechtstexte |
|
||||
| EXT-04 | Raffael | 17.06. | KWP: Callback-URLs melden + bnWin.net 8.1 N3 |
|
||||
| EXT-05 | Raffael | 16.06. | Noah: 4 Gate-Freitags-Slots blocken |
|
||||
| EXT-06 | Raffael | 17.06. | Hetzner-Projekt HiveGrid: S3+Token + DEK-Master-Key |
|
||||
| EXT-07 | Raffael | 26.06. | Stripe-Konto + Live-Verifizierung |
|
||||
| EXT-08 | Raffael | 30.06. | AirCall-Konto + Sandbox + Webhooks |
|
||||
| EXT-09 | Raffael | 03.07. | PandaDoc-Sandbox (Provider-Wahl) |
|
||||
| EXT-10 | Raffael | 18.06. | Google-Cloud OAuth + Calendar-Scope-Antrag |
|
||||
| EXT-11 | Raffael | 18.06. | Mistral API-Key |
|
||||
| EXT-12 | Raffael | 19.06. | Geo-IP + HIBP prüfen/anbinden |
|
||||
| H-LISTE | Haris | 17.06. | Zielkundenliste SHK (KWP-Nutzer-Fokus) |
|
||||
| H-PAIN | Haris | 17.06. | Painpoint-Gespräch mit Noah |
|
||||
| J-SETUP | Dejan | 16.06. | Domain/Hosting/Stack + Setup |
|
||||
| J-STRUKTUR | Dejan | 17.06. | Seitenstruktur + Davids Screens einbauen |
|
||||
| N-KWP | Dejan/Haris | 17.06. | KWP-Mail freigeben + bnWin.net 8.1 N3 anstoßen |
|
||||
| N-PAIN | Dejan/Haris | 17.06. | Painpoint-Input liefern (mit Haris) |
|
||||
| N-SLOTS | Dejan/Haris | 16.06. | 4 Gate-Freitags-Slots bestätigen |
|
||||
| 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)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-INFRA2 | Akeshan | 18.06. | DNS + Wildcard-TLS + zentrale Dienste anbinden |
|
||||
| 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)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| 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-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 |
|
||||
<h3 class="gate">Fr 19.06. · 2 Ticket(s)</h3>
|
||||
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-P4b | Akeshan | 19.06. | P4 Tasks + polymorphe EntityLink-Tabelle |
|
||||
| R-P2b | Raffael | 19.06. | P2 RLS-Härtung (Gate-Beweis) + RBAC + User-Lifecycle |
|
||||
|
||||
## Woche 2 · Sa 20.–Fr 26.06. — Plattform + CRM · 27 Tickets
|
||||
*→ Gate W2 + Noah-Demo 1 (Fr 26.06.)*
|
||||
### Sa 20.06. · 9 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-P3 | Akeshan | 21.06. | P3 Querschnitts-Oberflächen (Audit/Notif/Sprache DE) |
|
||||
| D-P2 | David | 21.06. | Screens P2 — Identität & Mandantentrennung |
|
||||
| D-P3 | David | 21.06. | Screens P3 — Querschnitts-Oberflächen |
|
||||
| D-P4 | David | 19.06. | Screens P4 — Files & Tasks |
|
||||
| D-P5 | David | 21.06. | Screens P5 — Apps-Engine |
|
||||
| J-SEO | Dejan | 26.06. | SEO + Conversion + Pricing-Seite vorbereiten |
|
||||
| N-DATEN | Dejan/Haris | 26.06. | SHK-Beispieldaten liefern |
|
||||
| N-LAGER | Dejan/Haris | 26.06. | Lagerist-Frage beantworten (M070-Scope) |
|
||||
| R-P5 | Raffael | 21.06. | P5 Apps-Engine & Integrations-Framework |
|
||||
### Mo 22.06. · 3 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-P19 | Akeshan | 24.06. | P19 Plattform-Admin (admin.hivegrid.de) |
|
||||
| D-CRM | David | 24.06. | CRM-Cluster-Screens |
|
||||
| R-P6 | Raffael | 24.06. | P6 CRM-Kern |
|
||||
### Di 23.06. · 1 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| H-CALLS | Haris | 26.06. | Erste Discovery-Calls |
|
||||
### Mi 24.06. · 3 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| D-FORM | David | 26.06. | Form-Builder-Canvas + öffentliches Formular (Bespoke) |
|
||||
| D-KANBAN | David | 26.06. | Pipeline-Kanban (Bespoke, konfigurierbar) |
|
||||
| EXT-14 | Raffael | 25.06. | Kostenmatrix/Preise mit Partner fixieren |
|
||||
### Do 25.06. · 6 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-P17a | Akeshan | 25.06. | P17 HR-Kern (Stammdaten, Doku, Passwort-Safe) |
|
||||
| D-HR | David | 26.06. | HR-Compose-Screens |
|
||||
| D-KAMP | David | 26.06. | Kampagnen-Editor + Segmente (Bespoke) |
|
||||
| D-P7 | David | 26.06. | Screens P7 — Lead-Inbox |
|
||||
| H-FOUND | Haris | 26.06. | Founding-Member-Angebot strukturieren |
|
||||
| R-P7 | Raffael | 26.06. | P7 Lead-Inbox |
|
||||
<h3 class="gate">Fr 26.06. · 5 Ticket(s)</h3>
|
||||
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-DEMO1 | Akeshan | 26.06. | Demo-Tenant + SHK-Demo-Daten für Noah-Demo 1 |
|
||||
| AK-P17b | Akeshan | 26.06. | P17 HR Urlaub/Krank + Surveys + Self-Service |
|
||||
| D-ADMIN | David | 26.06. | Plattform-Admin-Compose |
|
||||
| H-PAYLINK | Haris | 26.06. | Stripe Payment Link (Founding-Deal) |
|
||||
| N-DEMO1 | Dejan/Haris | 26.06. | Demo 1 abnehmen (CRM klickbar) |
|
||||
|
||||
## Woche 3 · Sa 27.06.–Fr 03.07. — Kern-Kette + Kommunikation · 23 Tickets
|
||||
*→ Gate W3 + Noah-Demo 2 (Fr 03.07.)*
|
||||
### Sa 27.06. · 4 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-P14a | Akeshan | 28.06. | P14 Sende-Domain-Verifikation + BCC-Brücke + Tracking |
|
||||
| D-P14 | David | 29.06. | Screens P14 — Email & Marketing (ohne Kampagnen-Editor) |
|
||||
| D-P8 | David | 29.06. | Screens P8 — Projekt & Pipelines (Kern, ohne Kanban) |
|
||||
| R-P8a | Raffael | 28.06. | P8 Pipeline-Engine + Projekt-CRUD + Auto-Verkaufsfall |
|
||||
### So 28.06. · 2 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-P14b | Akeshan | 29.06. | P14 Email-Marketing (Kampagnen + A/B) |
|
||||
| R-P8b | Raffael | 29.06. | P8 Konfigurierbarer Kanban + Forecast/Reporting |
|
||||
### Mo 29.06. · 4 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| D-ABN | David | 01.07. | Abnahme-Workflow (Bespoke-Mobile) |
|
||||
| D-PLAN | David | 01.07. | Plantafel (Bespoke-Mobile, offline) |
|
||||
| EXT-13 | Raffael | 29.06. | v2-Vorlauf-Externals (Gmail-Scope/Entra) |
|
||||
| J-WEBINAR | Dejan | 03.07. | Webinar-Landing + Anmelde-Flow |
|
||||
### Di 30.06. · 6 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-P15a | Akeshan | 01.07. | P15 Telefonie (AirCall) |
|
||||
| D-CHAT | David | 01.07. | Chat-UI (Bespoke) |
|
||||
| D-P15 | David | 01.07. | Screens P15 — Telefonie (ohne Chat) |
|
||||
| D-P9 | David | 01.07. | Screens P9 — Auftrags-Sub-Areas (ohne Plantafel/Abnahme) |
|
||||
| H-DEMO | Haris | 03.07. | Klick-Demos + echte Produkt-Demos |
|
||||
| R-P9a | Raffael | 01.07. | P9 Projekt-Pipeline + Sub-Areas + Rechnung (Sub-Entity v1) |
|
||||
### Mi 01.07. · 3 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-P15b | Akeshan | 02.07. | P15 Team-Chat (Realtime) |
|
||||
| D-DASH | David | 03.07. | Dashboard (3 Rollen-Layouts) + Cmd+K |
|
||||
| R-P9b | Raffael | 02.07. | P9 Plantafel (offline) + Abnahme-Protokoll (offline) |
|
||||
### Do 02.07. · 1 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| D-BOOK | David | 03.07. | Booking-Page (Public, Polish) + Kalender-View |
|
||||
<h3 class="gate">Fr 03.07. · 3 Ticket(s)</h3>
|
||||
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-P16a | Akeshan | 04.07. | P16 Kalender-Sync (Google) |
|
||||
| N-DEMO2 | Dejan/Haris | 03.07. | Demo 2 abnehmen (Kette E2E) |
|
||||
| R-P11a | Raffael | 04.07. | P11 Globale Suche (Meilisearch, Cmd+K) |
|
||||
|
||||
## Woche 4 · Sa 04.–Fr 10.07. — USP, Härtung, Launch · 20 Tickets
|
||||
*→ Freeze (Do 09.) · LAUNCH (Fr 10.07.)*
|
||||
### Sa 04.07. · 4 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-P16b | Akeshan | 05.07. | P16 Booking (Slots + Verfügbarkeit + Storno) |
|
||||
| D-P16 | David | 07.07. | Screens P16 — Kalender/Signatur (ohne Form/Booking) |
|
||||
| J-WEBTECH | Dejan | 10.07. | Webinar-Technik (Plattform/Aufzeichnung) |
|
||||
| R-P11b | Raffael | 05.07. | P11 Dashboard (3 Rollen-Layouts) |
|
||||
### So 05.07. · 1 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-P16c | Akeshan | 06.07. | P16 Form-Builder (Editor + Submission + Actions) |
|
||||
### Mo 06.07. · 6 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-P16d | Akeshan | 07.07. | P16 Angebot/Signatur (PandaDoc) |
|
||||
| D-P12 | David | 07.07. | Screens P12 — Automation (ohne Flow-Editor) |
|
||||
| D-POLISH | David | 09.07. | Politur extern sichtbarer Flächen + Visual-Reg-Baselines |
|
||||
| H-WEBINAR | Haris | 10.07. | Webinar-Einladungen + Moderation |
|
||||
| J-LAUNCHUPD | Dejan | 10.07. | Launch-Update Website |
|
||||
| R-P12a | Raffael | 07.07. | P12 Automation-Engine + Trigger/Action-Registry + Guards |
|
||||
### Di 07.07. · 1 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| R-P12b | Raffael | 08.07. | P12 Visueller Flow-Editor + Dry-Run + 24h-Undo + Sprach-Andock |
|
||||
### Mi 08.07. · 2 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-P20 | Akeshan | 08.07. | P20 Billing (Stripe Abo-Baukasten) + Onboarding + Branding |
|
||||
| D-P20 | David | 08.07. | Screens P20 — Billing/Onboarding/Branding (ex-D-REST) |
|
||||
<h3 class="gate">Do 09.07. · 5 Ticket(s)</h3>
|
||||
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| AK-P21 | Akeshan | 09.07. | P21 DSGVO (Export + Lösch-Workflow) + Feedback-Widget |
|
||||
| D-P13 | David | 09.07. | Screens P13 — KI-Layer (ex-D-REST) |
|
||||
| D-P21 | David | 09.07. | Screens P21 — DSGVO/Launch (ex-D-REST) |
|
||||
| H-FOLLOW | Haris | 10.07. | Trial-Follow-ups + Bilanz |
|
||||
| R-P13 | Raffael | 09.07. | P13 KI-Layer (Mistral-Gateway) |
|
||||
<h3 class="gate">Fr 10.07. · 1 Ticket(s)</h3>
|
||||
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| N-GONOGO | Dejan/Haris | 10.07. | Voll-Walkthrough + Go/No-Go |
|
||||
|
||||
## v2-Woche 1 · Mo 13.–So 19.07. — Public-API / Postfach / Abo / KI · 11 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) |
|
||||
| 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) |
|
||||
| VEXT-5 | Raffael | 19.07. | Gmail-Restricted-Scope-Verifizierung nachhalten |
|
||||
| VR-P22a | Raffael | 15.07. | Public-API: OpenAPI + Read-Endpoints (M161) |
|
||||
### Mi 15.07. · 1 Ticket(s)
|
||||
|
||||
| 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)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| VD-P25 | David | 20.07. | Screens P25 — KI-Tiefe/HiveMind |
|
||||
### Sa 18.07. · 2 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| VA-P24b | Akeshan | 20.07. | Onboarding-Wizard-UI (M157) |
|
||||
| VR-P25 | Raffael | 20.07. | KI-Tiefe: HiveMind/RAG + Whisper + pgvector-Hybrid (M087) |
|
||||
|
||||
## 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)
|
||||
|
||||
| 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) ⭐ |
|
||||
### Mi 22.07. · 1 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| VR-P32b •B2 | Raffael | 24.07. | KWP: Contract-Sentinel + Konflikt 'KWP gewinnt' (M092/093) |
|
||||
### Do 23.07. · 2 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| 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>
|
||||
|
||||
|
||||
| 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) |
|
||||
### 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.)*
|
||||
### Mo 27.07. · 4 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| VD-P28 | David | 29.07. | Screens P28 — Plattform-Admin-Tiefe (ex-VD-5) |
|
||||
| VEXT-2 •B2 | Raffael | 29.07. | HalloPetra-Spec erheben (API-Vertrag) |
|
||||
| VEXT-3 •B2 | Akeshan | 29.07. | Memberspot/Boobora-Spec erheben (HR-Drittanbieter) |
|
||||
| VR-P28a | Raffael | 29.07. | AdminUser-Welt + AdminRBAC (M038/039) |
|
||||
### Di 28.07. · 3 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| VA-P29 | Akeshan | 30.07. | Help-Center + Help-Desk (M172-175) |
|
||||
| VD-6 | David | 31.07. | Screens: v2-Politur (extern) + Visual-Reg-Baselines |
|
||||
| VJ-2 | Dejan | 28.07. | Help-Center-Inhalte einpflegen |
|
||||
### Mi 29.07. · 7 Ticket(s)
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| VA-P28b | Akeshan | 31.07. | Flag-Massen-Statistik (M033) + interne Lead-Pipeline (M040) |
|
||||
| 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 |
|
||||
| VD-P31 | David | 31.07. | Screens P31 — DSGVO-Vollausbau |
|
||||
| VR-P31 | Raffael | 31.07. | DSGVO-Vollausbau: AVV/Subprozessoren/Auskunft (M166) |
|
||||
| VR-P33 •B2 | Raffael | 31.07. | Telefonie-Erweiterung HalloPetra (M105) |
|
||||
### Do 30.07. · 1 Ticket(s)
|
||||
|
||||
| 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>
|
||||
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| VJ-3 | Dejan | 31.07. | Website-Update: Portal/Mobile-PWA/KWP als Features live |
|
||||
|
||||
## v3-Backlog (zurückgestellt — NICHT im Sprint) · 2
|
||||
*PWA-only (AD-17): native App + App-Store erst v3. Diese Tickets sind keinem Cycle zugeordnet.*
|
||||
|
||||
| Ticket | Wer | bis | Aufgabe |
|
||||
|---|---|---|---|
|
||||
| VEXT-4 | Akeshan | 28.07. | [v3] App-Store-Einreichung Apple + Google (zurückgestellt — PWA-only) |
|
||||
| VJ-1 | Dejan | 27.07. | [v3] App-Store-Metadaten (zurückgestellt — PWA-only) |
|
||||
|
||||
<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 · 42 Tickets
|
||||
|
||||
| Ticket | Start | bis | v | Aufgabe |
|
||||
|---|---|---|---|---|
|
||||
| EXT-02 | 16.06. | 16.06. | v1 | Mailjet Sende-Domain (SPF/DKIM/DMARC) + Warm-up |
|
||||
| EXT-04 | 16.06. | 17.06. | v1 | KWP: Callback-URLs melden + bnWin.net 8.1 N3 |
|
||||
| EXT-05 | 16.06. | 16.06. | v1 | Noah: 4 Gate-Freitags-Slots blocken |
|
||||
| EXT-06 | 16.06. | 17.06. | v1 | Hetzner-Projekt HiveGrid: S3+Token + DEK-Master-Key |
|
||||
| EXT-07 | 16.06. | 26.06. | v1 | Stripe-Konto + Live-Verifizierung |
|
||||
| EXT-08 | 16.06. | 30.06. | v1 | AirCall-Konto + Sandbox + Webhooks |
|
||||
| EXT-09 | 16.06. | 03.07. | v1 | PandaDoc-Sandbox (Provider-Wahl) |
|
||||
| EXT-10 | 16.06. | 18.06. | v1 | Google-Cloud OAuth + Calendar-Scope-Antrag |
|
||||
| EXT-11 | 16.06. | 18.06. | v1 | Mistral API-Key |
|
||||
| EXT-12 | 16.06. | 19.06. | v1 | Geo-IP + HIBP prüfen/anbinden |
|
||||
| R-P1a | 16.06. | 17.06. | v1 | P1 EU-Sterilisation + Contracts + URL-Schemata |
|
||||
| R-P1c | 16.06. | 17.06. | v1 | P1 Hot-Swap-Maschine + Walking-Skeleton + PWA |
|
||||
| R-REFIT | 16.06. | 21.06. | v1 | ER-Modell-Re-Fit P6–P9 (Requirements/Screen-Map/Phase-Sources) |
|
||||
| R-P1b | 17.06. | 18.06. | v1 | P1 Service-Kerne (Audit/notify/i18n/Flags) + Konnektor-Muster |
|
||||
| R-P2a | 18.06. | 19.06. | v1 | P2 Mandant + Auth (Email/PW/HIBP) + Sessions + TOTP |
|
||||
| R-P2b | 19.06. | 19.06. | v1 | P2 RLS-Härtung (Gate-Beweis) + RBAC + User-Lifecycle |
|
||||
| R-P5 | 20.06. | 21.06. | v1 | P5 Apps-Engine & Integrations-Framework |
|
||||
| R-P6 | 22.06. | 24.06. | v1 | P6 CRM-Kern |
|
||||
| EXT-14 | 24.06. | 25.06. | v1 | Kostenmatrix/Preise mit Partner fixieren |
|
||||
| R-P7 | 25.06. | 26.06. | v1 | P7 Lead-Inbox |
|
||||
| R-P8a | 27.06. | 28.06. | v1 | P8 Pipeline-Engine + Projekt-CRUD + Auto-Verkaufsfall |
|
||||
| R-P8b | 28.06. | 29.06. | v1 | P8 Konfigurierbarer Kanban + Forecast/Reporting |
|
||||
| EXT-13 | 29.06. | 29.06. | v1 | v2-Vorlauf-Externals (Gmail-Scope/Entra) |
|
||||
| R-P9a | 30.06. | 01.07. | v1 | P9 Projekt-Pipeline + Sub-Areas + Rechnung (Sub-Entity v1) |
|
||||
| R-P9b | 01.07. | 02.07. | v1 | P9 Plantafel (offline) + Abnahme-Protokoll (offline) |
|
||||
| R-P11a | 03.07. | 04.07. | v1 | P11 Globale Suche (Meilisearch, Cmd+K) |
|
||||
| R-P11b | 04.07. | 05.07. | v1 | P11 Dashboard (3 Rollen-Layouts) |
|
||||
| R-P12a | 06.07. | 07.07. | v1 | P12 Automation-Engine + Trigger/Action-Registry + Guards |
|
||||
| R-P12b | 07.07. | 08.07. | v1 | P12 Visueller Flow-Editor + Dry-Run + 24h-Undo + Sprach-Andock |
|
||||
| R-P13 | 09.07. | 09.07. | v1 | P13 KI-Layer (Mistral-Gateway) |
|
||||
| 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) |
|
||||
| VR-P25 | 18.07. | 20.07. | v2 | KI-Tiefe: HiveMind/RAG + Whisper + pgvector-Hybrid (M087) |
|
||||
| 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) |
|
||||
| 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) |
|
||||
| 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
|
||||
|
||||
| Ticket | Start | bis | v | Aufgabe |
|
||||
|---|---|---|---|---|
|
||||
| AK-INFRA1 | 16.06. | 17.06. | v1 | Infra-Live: Staging + Coolify-Apps + PG/Redis/PgBouncer |
|
||||
| AK-INFRA2 | 17.06. | 18.06. | v1 | DNS + Wildcard-TLS + zentrale Dienste anbinden |
|
||||
| AK-P4a | 18.06. | 19.06. | v1 | P4 Files (chunked Upload, HEIC→JPG, ClamAV) |
|
||||
| AK-P4b | 19.06. | 19.06. | v1 | P4 Tasks + polymorphe EntityLink-Tabelle |
|
||||
| AK-P3 | 20.06. | 21.06. | v1 | P3 Querschnitts-Oberflächen (Audit/Notif/Sprache DE) |
|
||||
| AK-P19 | 22.06. | 24.06. | v1 | P19 Plattform-Admin (admin.hivegrid.de) |
|
||||
| AK-P17a | 25.06. | 25.06. | v1 | P17 HR-Kern (Stammdaten, Doku, Passwort-Safe) |
|
||||
| AK-DEMO1 | 26.06. | 26.06. | v1 | Demo-Tenant + SHK-Demo-Daten für Noah-Demo 1 |
|
||||
| AK-P17b | 26.06. | 26.06. | v1 | P17 HR Urlaub/Krank + Surveys + Self-Service |
|
||||
| AK-P14a | 27.06. | 28.06. | v1 | P14 Sende-Domain-Verifikation + BCC-Brücke + Tracking |
|
||||
| AK-P14b | 28.06. | 29.06. | v1 | P14 Email-Marketing (Kampagnen + A/B) |
|
||||
| AK-P15a | 30.06. | 01.07. | v1 | P15 Telefonie (AirCall) |
|
||||
| AK-P15b | 01.07. | 02.07. | v1 | P15 Team-Chat (Realtime) |
|
||||
| AK-P16a | 03.07. | 04.07. | v1 | P16 Kalender-Sync (Google) |
|
||||
| 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 (PandaDoc) |
|
||||
| AK-P20 | 08.07. | 08.07. | v1 | P20 Billing (Stripe Abo-Baukasten) + 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-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-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) |
|
||||
|
||||
### David · 42 Tickets
|
||||
|
||||
| Ticket | Start | bis | v | Aufgabe |
|
||||
|---|---|---|---|---|
|
||||
| D-D0a | 16.06. | 18.06. | v1 | D0 Design-System + App-Shell (A1) |
|
||||
| D-WEB | 16.06. | 16.06. | v1 | Website-Screens + Brand-Tokens |
|
||||
| D-D0b | 18.06. | 20.06. | v1 | D0 Archetypen A2–A7 + Zustands-Kit + Primitives |
|
||||
| D-FLOW | 18.06. | 03.07. | v1 | Flow-/Node-Editor (Bespoke, Langläufer ab 18.06.) |
|
||||
| D-P2 | 20.06. | 21.06. | v1 | Screens P2 — Identität & Mandantentrennung |
|
||||
| D-P3 | 20.06. | 21.06. | v1 | Screens P3 — Querschnitts-Oberflächen |
|
||||
| D-P4 | 20.06. | 19.06. | v1 | Screens P4 — Files & Tasks |
|
||||
| D-P5 | 20.06. | 21.06. | v1 | Screens P5 — Apps-Engine |
|
||||
| D-CRM | 22.06. | 24.06. | v1 | CRM-Cluster-Screens |
|
||||
| D-FORM | 24.06. | 26.06. | v1 | Form-Builder-Canvas + öffentliches Formular (Bespoke) |
|
||||
| D-KANBAN | 24.06. | 26.06. | v1 | Pipeline-Kanban (Bespoke, konfigurierbar) |
|
||||
| D-HR | 25.06. | 26.06. | v1 | HR-Compose-Screens |
|
||||
| D-KAMP | 25.06. | 26.06. | v1 | Kampagnen-Editor + Segmente (Bespoke) |
|
||||
| D-P7 | 25.06. | 26.06. | v1 | Screens P7 — Lead-Inbox |
|
||||
| D-ADMIN | 26.06. | 26.06. | v1 | Plattform-Admin-Compose |
|
||||
| D-P14 | 27.06. | 29.06. | v1 | Screens P14 — Email & Marketing (ohne Kampagnen-Editor) |
|
||||
| D-P8 | 27.06. | 29.06. | v1 | Screens P8 — Projekt & Pipelines (Kern, ohne Kanban) |
|
||||
| D-ABN | 29.06. | 01.07. | v1 | Abnahme-Workflow (Bespoke-Mobile) |
|
||||
| D-PLAN | 29.06. | 01.07. | v1 | Plantafel (Bespoke-Mobile, offline) |
|
||||
| D-CHAT | 30.06. | 01.07. | v1 | Chat-UI (Bespoke) |
|
||||
| D-P15 | 30.06. | 01.07. | v1 | Screens P15 — Telefonie (ohne Chat) |
|
||||
| D-P9 | 30.06. | 01.07. | v1 | Screens P9 — Auftrags-Sub-Areas (ohne Plantafel/Abnahme) |
|
||||
| D-DASH | 01.07. | 03.07. | v1 | Dashboard (3 Rollen-Layouts) + Cmd+K |
|
||||
| D-BOOK | 02.07. | 03.07. | v1 | Booking-Page (Public, Polish) + Kalender-View |
|
||||
| D-P16 | 04.07. | 07.07. | v1 | Screens P16 — Kalender/Signatur (ohne Form/Booking) |
|
||||
| D-P12 | 06.07. | 07.07. | v1 | Screens P12 — Automation (ohne Flow-Editor) |
|
||||
| D-POLISH | 06.07. | 09.07. | v1 | Politur extern sichtbarer Flächen + Visual-Reg-Baselines |
|
||||
| D-P20 | 08.07. | 08.07. | v1 | Screens P20 — Billing/Onboarding/Branding (ex-D-REST) |
|
||||
| D-P13 | 09.07. | 09.07. | v1 | Screens P13 — KI-Layer (ex-D-REST) |
|
||||
| D-P21 | 09.07. | 09.07. | v1 | Screens P21 — DSGVO/Launch (ex-D-REST) |
|
||||
| VD-P22 | 13.07. | 17.07. | v2 | Screens P22 — Public-API-Keys (ex-VD-5) |
|
||||
| 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-P25 | 16.07. | 20.07. | v2 | Screens P25 — KI-Tiefe/HiveMind |
|
||||
| VD-P26 | 20.07. | 22.07. | 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 |
|
||||
| VD-P28 | 27.07. | 29.07. | v2 | Screens P28 — Plattform-Admin-Tiefe (ex-VD-5) |
|
||||
| VD-6 | 28.07. | 31.07. | v2 | Screens: v2-Politur (extern) + Visual-Reg-Baselines |
|
||||
| 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
|
||||
|
||||
| Ticket | Start | bis | v | Aufgabe |
|
||||
|---|---|---|---|---|
|
||||
| EXT-03 | 16.06. | 19.06. | v1 | Anwalt: AVV + DSGVO-Auskunft + Website-Rechtstexte |
|
||||
| J-SETUP | 16.06. | 16.06. | v1 | Domain/Hosting/Stack + Setup |
|
||||
| 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 |
|
||||
|
||||
### Haris · 12 Tickets
|
||||
|
||||
| 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-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 |
|
||||
| H-PAYLINK | 26.06. | 26.06. | v1 | Stripe Payment Link (Founding-Deal) |
|
||||
| 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 |
|
||||
|
||||
### Dejan/Haris (Noah-Zulieferungen) · 11 Tickets
|
||||
|
||||
| Ticket | Start | bis | v | Aufgabe |
|
||||
|---|---|---|---|---|
|
||||
| N-KWP | 16.06. | 17.06. | v1 | KWP-Mail freigeben + bnWin.net 8.1 N3 anstoßen |
|
||||
| N-PAIN | 16.06. | 17.06. | v1 | Painpoint-Input liefern (mit Haris) |
|
||||
| N-SLOTS | 16.06. | 16.06. | v1 | 4 Gate-Freitags-Slots bestätigen |
|
||||
| N-TXTABN | 17.06. | 17.06. | v1 | Website-Texte abnehmen |
|
||||
| N-DATEN | 20.06. | 26.06. | v1 | SHK-Beispieldaten liefern |
|
||||
| N-LAGER | 20.06. | 26.06. | v1 | Lagerist-Frage beantworten (M070-Scope) |
|
||||
| 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 |
|
||||
Binary file not shown.
@@ -0,0 +1,95 @@
|
||||
---
|
||||
gsd_state_version: 1.0
|
||||
milestone: v1.0
|
||||
milestone_name: milestone
|
||||
status: planning
|
||||
stopped_at: context exhaustion at 75% (2026-06-21)
|
||||
last_updated: "2026-06-21T20:56:25.641Z"
|
||||
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: Boilerplate einziehen + 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, deal.won/lead.qualified-Events, Subscription-Stub, Credits-Konto, VM-Slots) und das maschinenlesbare Audit-Register (40 invertierte Refs). Audit-Kontrakt: Vorwärts-Refs MINUS Register = leer. M049 (Auto-Verkaufsfall) 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-06-21T20:56:25.638Z
|
||||
Stopped at: context exhaustion at 75% (2026-06-21)
|
||||
Resume file: None
|
||||
@@ -0,0 +1,317 @@
|
||||
---
|
||||
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: Stripe-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 · Stripe-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) · Stripe 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 Stripe 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, Stripe 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 · Stripe-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,51 @@
|
||||
# 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`
|
||||
**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.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Macht das Repo zu einer lauffähigen, EU-sterilen Codebasis und stellt die Querschnittsdienste bereit, auf denen alle Folge-Module aufsetzen: `logActivity()` (append-only Activity-Stream), Search-Registry, Subframe-Adapter, Mass-Action-Schutz, Audit-Event mit SHA-256-Hash-Kette (Prisma-Middleware, default-on), `notify()` mit Kanal-Abstraktion (In-App/Email; Push-Stub bis v2), `packages/i18n` (Resolution User → Tenant → DE, Build-Lint gegen Hard-Strings) und die Feature-Flag-Engine mit Entitlement-Gate (`tenantHasModule()` — Konnektor-Prinzip: jede Modul-Phase schaltet Sidebar/Routes/Actions plan-gebunden). Liefert außerdem die verbindlichen URL-Schemata und eine Walking-Skeleton-Route als grünen Smoke-Test-Anker.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| **App-Shell-Baseline** [global, kein eigener Pfad] | Sidebar (Modul-Navigation mit Icons+Labels, **Konnektor-Gating-Zustand** je `tenantHasModule()` — ausgeblendet/gesperrt, Sektionen Arbeit + Verwaltung, Collapse, aktiver Eintrag, Mobile-Drawer/Bottom-Nav 📱) · Topbar (Tenant-Switcher, Cmd+K-Trigger, Notification-Bell mit Unread-Badge, User-Menü mit Hell/Dunkel-Toggle + Logout) · Breadcrumb · **Status-Banner-System** (past_due/frozen/deletion_pending/suspended, stapelbar) · Toast/Inline-Feedback (Erfolg / Klartext-Fehler mit Lösungs-Knopf / Warnung) | A1 |
|
||||
| **Archetypen-Kit A2–A7** [keine Route] | A2 List-View-Kit · A3 Detail-View-Kit (inkl. Activity-Stream-Komponente) · A4 Form/Input-Kit (12 Feldtypen) · A5 Modal/Wizard-Kit · A6 Settings/Connection-Kit · A7 Zustands-Kit (leer/laden/Fehler/keine-Berechtigung/offline) | A2–A7 |
|
||||
| **Basis-Primitives** [keine Route] | Buttons (primär/sekundär/destruktiv/ghost), Badges/Status-Pills, Tags (farbig), Avatare + Avatar-Stapel, Tabs, Dropdown, Date/Time-Picker, Tooltip, KPI-Kachel, Chart-Basis (Linie/Balken/Donut), Drawer, Markdown-Editor + -Renderer, Datei-Dropzone mit Progress, Unterschriften-Feld (Touch) 📱, Emoji-Picker, Mention-Highlight | Primitives |
|
||||
| Walking-Skeleton-Route [Beispiel-Modul-Route] | Eine in der Sidebar registrierte Beispielroute, die das View-Model-im-Loader-Muster + Konnektor-Gating exemplarisch zeigt (grüner Smoke-Test gegen `packages/ui-mock`) — minimal, nur als Compose-Beispiel aus A2 | A2 (minimal) |
|
||||
|
||||
*(Audit-Viewer/Notification-Center/Notification-Settings/Sprach-Settings = Oberflächen → P3. Auth-Screens → P2. Files/Tasks → P4. Hier nur die Service-Kerne + die Shell.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] App-Shell-Baseline mit Sidebar inkl. Konnektor-Gating-Zustand (Modul je `tenantHasModule()` ausgeblendet/gesperrt) — Sektionen Arbeit + Verwaltung, Collapse, Mobile-Variante
|
||||
- [ ] Topbar mit Tenant-Switcher, Cmd+K-Trigger, Notification-Bell (Unread-Badge), User-Menü (Hell/Dunkel-Toggle, Logout) + Breadcrumb
|
||||
- [ ] Status-Banner-System (past_due/frozen/deletion_pending/suspended, je Text + Action-Button, stapelbar) + Toast/Inline-Feedback mit Klartext-Fehler + Lösungs-Knopf (Bauprinzip A.1)
|
||||
- [ ] Archetypen A2–A7 + Basis-Primitives einmal designt, überall komponierbar (inkl. Activity-Stream-Komponente, 4 Zustände, Unterschriften-Feld, Markdown)
|
||||
- [ ] Walking-Skeleton-Route in Sidebar registriert, Loader gibt View-Model zurück, Konnektor-Gate exemplarisch, grüner Smoke-Test
|
||||
- [ ] Service-Kerne aufrufbar (Backend, kein UI): `logActivity()`, Search-Registry, Subframe-Adapter, Mass-Action-Schutz, Audit-Hash-Kette (Prisma-Middleware default-on), `notify()` (In-App/Email, Push-Stub), `packages/i18n` (Resolution User→Tenant→DE, Build-Lint Hard-Strings), Feature-Flag-Engine + `tenantHasModule()` mit Redis-Cache
|
||||
- [ ] EU-Sterilisation: GitHub/Google-OAuth-Reste + `User.githubId/googleId` entfernt, kein US-Kern im Auth-Pfad
|
||||
- [ ] Verbindliche URL-Schemata dokumentiert (App, Admin, Portal, Forms, Booking, Help, API)
|
||||
- [ ] Entitlement-Gate-Muster `tenantHasModule('<modul>')` mit Beispiel-Anwendung an der Walking-Skeleton-Route (Konnektor-Prinzip — jede Folge-Phase registriert ihren Feature-Konnektor)
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Sidebar mit Icon+Label-Navigationseinträgen und drei Konnektor-Zuständen (aktiv/ausgeblendet/gesperrt), Sektions-Gruppierung, Collapse-Steuerung, Mobile-Drawer/Bottom-Nav-Variante, aktiv-Markierung; Topbar mit Tenant-Switcher-Dropdown (zuletzt-genutzt-Liste, Suchfeld ab 5 Tenants), Cmd+K-Such-Trigger, Notification-Bell mit Unread-Badge, User-Menü mit Theme-Toggle; Breadcrumb-Pfad; stapelbares Status-Banner-System mit Text + Action-Button je Tenant-Status; Toast- und Inline-Feedback-Komponente (Erfolg/Fehler-mit-Lösungs-Knopf/Warnung); Daten-Tabelle (sortierbar/paginiert) + Karten-Alternative + Filter-Bar + Bulk-Action-Bar + Spalten-Konfig + CSV-Export-Button + Archiviert-Toggle + Leerzustand-mit-CTA (A2); Detail-Panel mit Inline-Edit-Feld + Related-Panels + Activity-Timeline (Actor-Kind-Marker user/system/automation/ki) + Custom-Felder-Sektion + Tags-Zeile + Sub-Tabs (A3); Form-Kit mit allen 12 Feldtypen + Validierungs-/Klartext-Fehler-Zuständen + Auto-Complete-Picker + Pflichtfeld-Markierung (A4); Modal/Wizard mit Progress + Bestätigungs-Dialog mit Confirm-Phrase-Variante + Side-Panel/Drawer (A5); Settings-Sektions-Layout + Toggle-Zeile mit Klartext + Connection-Card mit Status-Ampel + Key/Secret-Reveal (A6); Zustands-Kit (leer/laden-Skeleton/Fehler-mit-Lösungs-Knopf/keine-Berechtigung/offline 📱) (A7); Basis-Primitives (Buttons in 4 Varianten, Badges/Status-Pills, farbige Tags, Avatare+Stapel, Tabs, Dropdown, Date/Time-Picker, Tooltip, KPI-Kachel, Chart-Basis, Drawer, Markdown-Editor+Renderer, Datei-Dropzone mit Progress, Touch-Unterschriften-Feld, Emoji-Picker, Mention-Highlight); Hell/Dunkel-Theme-Tokens flash-frei.
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (R-P1a/b, AK-P1c) aktualisiert:
|
||||
@@ -0,0 +1,58 @@
|
||||
# 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`
|
||||
**Subframe:** Pflicht je Route. Archetypen aus D0 (A4 Form/Input, A5 Modal/Wizard, A6 Settings, A2 Liste).
|
||||
|
||||
> ⚙️ **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).
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| Signup [`/signup`] | Email, Passwort (Stärke-Anzeige + Breach-Check-Hinweis), 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 (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 |
|
||||
| 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 |
|
||||
|
||||
*(API-Keys → v2. Audit/Notif/Files/Tasks-Oberflächen → P3/P4. Plattform-Admin-Welt → P19.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Self-Service-Signup mit auto-generiertem Tenant-Slug (Reserved-Words geblockt), Auto-SHK-Seed, Landing unter app.hivegrid.de
|
||||
- [ ] Login Email+Passwort (NIST-konform, Have-I-Been-Pwned-Breach-Check mit Klartext-Block) + mCaptcha ab 3. Fehlversuch + Magic-Link-Alternative
|
||||
- [ ] 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)
|
||||
- [ ] 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)
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Auth-Formulare mit Email/Passwort-Feldern, Passwort-Stärke-Anzeige + Breach-Klartext-Block, Checkbox-Reihe (AGB/DSGVO/AVV); mCaptcha-Einbindungs-Slot; TOTP-Code-Eingabe (6-stellig) + Trust-Device-Checkbox + QR-Code-Anzeige für 2FA-Setup; Magic-Link-Hinweis/-Trigger; Tenant-Auswahl-Liste mit zuletzt-genutzt + Suchfeld; „ohne Tenant"-Klartext-Screen mit zwei Aktions-Buttons; Session-Tabelle (Gerät/Browser/IP/Standort/letzte-Aktivität) mit Per-Zeile-Abmelden + „überall abmelden"-Button + Trust-Device-Revoke-Liste; Profil-Settings mit Avatar-Upload, Inline-Edit-Feldern, Passwort-ändern-Block, 2FA-Einrichtungs-Block, Theme-Toggle; Rollen-Liste + Rollen-Editor mit Permission-Bundle-Auswahl und ausklappbaren Advanced-Einzelrechten; Rollen-Lösch-Dialog mit Ersatz-Rollen-Picker/Bulk-Reassign; Gruppen-Liste mit Bulk-Add/Remove; User-Liste mit Status-/2FA-Badges; Einladungs-Modal (Email/Rolle/Gruppen/Nachricht) + Einladungs-Status-Liste; Deaktivierungs-Workflow-Panel das offene Verknüpfungen auflistet + Bulk-Übertragungs-Picker; mehrstufiger Konto-Lösch-Wizard mit optionalem Daten-Export-Schritt, Passwort+2FA-Gate, Countdown-Bestätigung und Block-Klartext für den einzigen-Admin-Edge-Case; Klartext-Fehler- und Empty-/Loading-/Permission-Denied-States.
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (R-P2a/b) aktualisiert:
|
||||
@@ -0,0 +1,55 @@
|
||||
# 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)
|
||||
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste + Drawer, A6 Settings).
|
||||
|
||||
> ⚙️ **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.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Stellt die Bedien-Oberflächen der in P1 gebauten Plattformdienste bereit. Audit-Viewer: gefilterter, permission-gegateter Trail mit Vorher-/Nachher-Diff-Drawer und Compliance-Export (NDJSON/CSV ins Hetzner-Object-Storage, fixe Default-Retention). Notification-Center: In-App-Liste (SSE) mit Read-Status, Deeplink, Bulk; plus Pro-User-Präferenzen (Event-Typen je Modul, In-App/Email-Toggle, Master „alle Emails aus"). Sprach-Settings: v1 DE-only-Hinweis; `Contact.language` als Feld vorhanden, alle Strings laufen durch `t()` mit vollständiger `de`-Locale (`verify:i18n`-Gate grün).
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| Audit-Viewer [`/admin/audit`] | Zeit, Actor (+Kind-Marker User/Automation/KI/Admin), Aktion, Subjekt, **deutscher Summary-Text** · Filter: Zeitraum (Default 30 Tage, max 24 Monate ohne Export), Actor, Kategorie, Subjekt-Typ · Quick-Filter (Klick auf Actor/Subject/Action) · **Detail-Drawer mit Diff-Ansicht** (Feld-für-Feld Vorher/Nachher, sensible Diffs nur „Wert geändert") · Export-Button (CSV/NDJSON, Zweck-Pflichtfeld) | A2+Drawer |
|
||||
| Audit-Export-Jobs [`/admin/audit/exports` + `/new` + `/:id`] | Export-Job-Liste · Anlage (Filter-Kriterien wie Listen-View, Format, Zweck) · Job-Status + Download (signed-URL) | A2 |
|
||||
| Notification-Center [Topbar-Drawer + `/notifications`] | Einträge: Titel, Body, Actor, Zeit, Read-Status, Priorität · Tabs Alle/Ungelesen · Mark-read/unread, Klick→Deeplink · Bulk-Clear · Klartext bei pausierten Emails (Bounce) | A2 |
|
||||
| Notification-Settings [`/settings/notifications`] | Event-Typen nach Modul gruppiert, je **In-App/Email-Toggle** + Priority-Selektor · Master-Toggle „alle Emails aus" (mit Klartext: betrifft auch zukünftige Event-Typen) | A6 |
|
||||
|
||||
**Eingebettete Oberflächen (kein eigener Screen, aber zu designen):**
|
||||
- Per-Subject-Audit-Drawer in jeder Detail-View (filtert auf `subject_type+subject_id`, Permission `audit.read`)
|
||||
- Per-User-Audit-Drawer in `/admin/users/:id` (Aktionen dieses Users)
|
||||
- Sprach-Hinweis „fest DE" im Profil-Screen (P2) — kein eigener Screen
|
||||
|
||||
*(Quiet-Hours/Bündelung/Push-Devices-Liste/Retention-Editor/Legal-Hold/Saved-Views/Sprach-Wechsler → v2.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Audit-Viewer permission-gegated (audit.read), server-side-Filter zwingend (Tabellen werden groß), deutscher Summary-Text je Eintrag, Actor-Kind-Marker
|
||||
- [ ] Diff-Detail-Drawer (Feld-für-Feld Vorher/Nachher; Datenschutz-Maskierung bei sensiblen Inhalten) + „Verlauf dieses Objekts"/„Ähnliche Einträge"
|
||||
- [ ] Compliance-Export als NDJSON/CSV ins S3-kompatible Hetzner-Object-Storage mit Zweck-Pflichtfeld + Export-Job-Status/Download; fixe Default-Retention + Cron-Auto-Löschung; jeder Export selbst auditiert (`audit.exported`)
|
||||
- [ ] Notification-Versand-Pipeline-Oberfläche: In-App-Center via SSE (sofort, ohne Bündelung), Email-Kanal; Push-Kanal als Stub bis v2
|
||||
- [ ] Notification-Center mit Read-Status, Deeplink, Tabs Alle/Ungelesen, Bulk-Clear; Bounce-Klartext „Emails an dich kommen aktuell nicht an"
|
||||
- [ ] Notification-Präferenzen pro User (Event-Typen je Modul, In-App/Email-Toggle, Priority-Threshold, Master „alle Emails aus")
|
||||
- [ ] i18n: alle Oberflächen-Strings durch `t()` mit vollständiger `de`-Locale (`verify:i18n`-Gate grün); `Contact.language`-Feld vorhanden (Outbound-Steuerung ab v2); v1 fest DE — Wechsler/EN-Templates ausdrücklich → v2
|
||||
- [ ] *(→ v2)* ~~Quiet-Hours, Bündelung, Push-Limits, Retention-Policy/Legal-Hold/Saved-Views, Sprach-Wechsler~~
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Audit-Daten-Tabelle (server-paginiert) mit Actor-Kind-Marker (visuell unterscheidbar: User/Automation/KI/Admin), deutschem Summary-Text, Subjekt-Verlinkung; Filter-Bar (Datum-Range-Selektor mit Presets, Actor-, Kategorie-, Subjekt-Typ-Filter) mit Quick-Filter-Klick auf Tabellenwerte; Detail-Drawer mit Feld-für-Feld-Diff-Visualisierung (Hinzufügung/Löschung/Änderung farblich, JSON-Strukturdiff, Maskierungs-Hinweis bei sensiblen Werten) + „Verlauf dieses Objekts"-/„Ähnliche Einträge"-Aktionen; Export-Button der zum Export-Job-Anlage-Dialog führt (Format-Auswahl CSV/NDJSON + Zweck-Pflichtfeld); Export-Job-Liste mit Status-Badge + Download-Link; eingebetteter Per-Subject- und Per-User-Audit-Drawer (wiederverwendbar in Detail-Views); Notification-Liste/-Drawer mit Titel/Body/Actor/Zeit/Read-Status/Prioritäts-Marker, Alle-/Ungelesen-Tabs, Mark-read/unread-Aktion, Deeplink-Klick, Bulk-Clear, Bounce-Klartext-Hinweis; Notification-Bell-Anbindung (Badge liegt in P1-Topbar); Notification-Präferenzen-Editor mit nach Modul gruppierten Event-Typen, je Zeile In-App-/Email-Toggle + Priority-Selektor, Master-„alle-Emails-aus"-Toggle mit Klartext; DE-Sprach-Hinweis-Element; Empty-/Loading-/Permission-Denied-/Fehler-States (Klartext, z. B. leerer Center „Keine Benachrichtigungen — sobald etwas Wichtiges passiert, erscheint es hier").
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (AK-P3) aktualisiert:
|
||||
@@ -0,0 +1,54 @@
|
||||
# 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`
|
||||
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A3 Detail, A4 Form + Dropzone, A5 Modal).
|
||||
|
||||
> ⚙️ **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.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Liefert die nutzerseitigen Plattform-Primitive. Files: chunked Upload (TUS) mit RLS auf Storage-Pfaden (Hetzner S3-kompatibel), Preview-Generierung (PDF→PNG, Bild→WebP, **HEIC→JPG Pflicht**), Anhängen an jede Entität über `FileEntityLink` (polymorph), Tags, Archiv-Flag; Customer-Portal-Upload ist vorbereitet. Tasks: leichtgewichtiges, querliegendes Aufgaben-Modul mit Status/Priorität/Fälligkeit, Entitäts-Verknüpfung (Contact/Company/Lead/Deal/Project), Watcher, Reminder via `notify()` (24h vor / bei / 24h nach Deadline) und Auto-Archivierung erledigter Tasks nach 30 Tagen per Cron. Tasks entstehen manuell, aus Chat, aus Form-Submission und aus Automation-Actions.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| 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 · Inline-Schnell-Vorschau (Hover/Single-Klick) · Archiviert-Toggle (keine Versions-Spalte v1) | A2 |
|
||||
| Upload-View + Datei-Dropzone [`/files/upload`] | 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 mit Zoom / PDF; HEIC→JPG)** mit Fallback-Klartext + Download bei not_supported · Tags · Notizen · verknüpfte Entitäten mit Rolle · Activity (Upload/Verknüpfungs-Änderungen/Downloads) · Download, Ersetzen, Archiv, Vorschau-neu-generieren bei failed (kein Versionsverlauf v1) | A3 |
|
||||
| Task-Liste [`/tasks`] | Titel, Prioritäts-Marker, Fälligkeit (überfällig rot, relativ ≤7 Tage), verknüpfte Entität, Assignee (Person/Gruppe), Status, Quelle-Hinweis · Presets: Meine/Erstellt/Alle (Alle nur mit tasks.read_all) · Such-Funktion · Filter (Status/Priorität/Deadline-Range/Verknüpfungs-Typ/Quelle) · Archiviert-Toggle · Bulk (Status/Priorität/Assignee/Archiv/Löschen) · Inline-Quick-Actions (done/Priorität/Deadline) | A2 — **wiederverwendbare Komponente** |
|
||||
| Task-Detail + Anlage-Modal [`/tasks/:id`, `/tasks/new`] | Titel, Beschreibung (Markdown), Status/Priorität/Fälligkeit inline, Assignee-Picker (Person↔Gruppe), Verknüpfungs-Picker (Auto-Complete Contact/Company/Lead/Deal/Project), Watcher, Quelle (manuell/Chat/Form/Automation mit Link), Activity-Stream der Task, Aktionen (Erledigen/Wieder-öffnen/Duplizieren/Löschen) · Klartext-Banner (überfällig / Assignee deaktiviert / „wird in 30 Tagen archiviert") | A3+A5 |
|
||||
|
||||
**Eingebettet (kein eigener Screen, aber zu designen):**
|
||||
- Files-Browser vorgefiltert als Sub-Sektion in Entity-Detail-Views
|
||||
- Tasks-Tab/Section mit verknüpften Tasks + „Aufgabe anlegen" (Pre-Fill) in jeder Entity-Detail-View
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Chunked Upload (TUS) mit RLS auf Storage-Pfaden (Hetzner Object Storage, ADR-009); Multi-Datei-Queue mit Per-Datei-Progress + Retry
|
||||
- [ ] Preview-Generierung PDF→PNG, Bild→WebP, **HEIC→JPG (Pflicht)** mit Status (pending/generating/ready/failed/not_supported) + Klartext-Fallback
|
||||
- [ ] Datei-Anhängen über FileEntityLink (polymorph) an jede Entität + Rollen-Label; Tags; Archiv-Flag; Bulk-ZIP; Customer-Portal-Upload vorbereitet
|
||||
- [ ] Files-Browser server-side-Filter (Entität/MIME-Gruppe/Tags/Verantwortlicher), Tabelle/Grid-Umschalter, Inline-Schnell-Vorschau
|
||||
- [ ] Tasks mit Status/Priorität/Fälligkeit, Entitäts-Verknüpfung (Contact/Company/Lead/Deal/Project), Person- oder Gruppen-Zuweisung (Constraint: genau eines, Default = Ersteller), Watcher
|
||||
- [ ] Task-Erstellungs-Quellen: manuell, Chat („Mark as Task"), Form-Submission, Automation-Action — je mit Quelle-Marker + Link
|
||||
- [ ] Reminder via notify() (24h vor / bei / 24h nach Deadline, Eskalation Email) an Assignee/Gruppe/Watcher; Auto-Archivierung erledigter Tasks nach 30 Tagen per Cron
|
||||
- [ ] Permission-Bundle tasks.* (read_own mit Owner-Check / read_all / write / admin) — fremde Tasks 404 statt 403, Action-Buttons permission-aware ausgeblendet/ausgegraut
|
||||
- [ ] *(→ v2)* ~~FileVersion + Versions-Verlauf, Office-/Video-Previews, Resume-Upload, OCR~~
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Daten-Tabelle mit Tabelle/Grid-Umschalter, Vorschau-Thumbnail, sortierbaren Spalten, Filter-Bar (Entität/MIME-Gruppe/Tags/Verantwortlicher), Bulk-Action-Bar (Tag/Verknüpfen/Archiv/ZIP), Archiviert-Toggle, Inline-Schnell-Vorschau (Hover/Single-Klick); Datei-Dropzone mit Drag&Drop + Multi-Datei-Upload-Queue mit Per-Datei-Fortschrittsbalken, Fehler-Zustand + Retry, HEIC→JPG-Klartext-Hinweis; Vorschau-Komponente (Bild-Viewer mit Zoom, PDF-Viewer) mit not_supported-Fallback (Klartext + Download) + „Vorschau neu generieren"-Aktion bei failed; File-Detail-Panel mit Stammdaten, Tags-Zeile, Notiz-Feld, verknüpfte-Entitäten-Liste mit Rollen-Label, Activity-Timeline, Aktions-Buttons (Download/Ersetzen/Archiv); Task-Liste (als wiederverwendbare Komponente, embeddable) mit Prioritäts-Marker, Fälligkeits-Anzeige (relativ/absolut, überfällig rot), Quelle-Marker, Scope-Preset-Switcher (Meine/Erstellt/Alle), Such-Feld, Filter (Status/Priorität/Deadline-Range-Presets/Verknüpfungs-Typ/Quelle), Bulk-Auswahl + Bulk-Actions, Inline-Quick-Actions (done/Priorität/Deadline); Task-Detail/-Anlage mit Markdown-Editor, Status-Wechsler, Date-Picker, Assignee-Picker (Person↔Gruppe umschaltbar), Verknüpfungs-Auto-Complete-Picker, Watcher-Verwaltung, Quelle-Anzeige mit Link, Activity-Stream, Aktions-Buttons (Erledigen/Wieder-öffnen/Duplizieren/Löschen mit Klartext-Warnung); Klartext-Banner (überfällig / Assignee deaktiviert / Auto-Archivierungs-Hinweis / gelöschte Verknüpfung); Empty-/Loading-/Permission-Denied-/Fehler-States (Klartext, z. B. „Keine offenen Aufgaben — schöne Sache").
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (AK-P4a/b) aktualisiert:
|
||||
@@ -0,0 +1,52 @@
|
||||
# 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`
|
||||
**Subframe:** Pflicht je Route. Archetypen aus D0 (A6 Settings/Connection-Kit + Connection-Card, A5 Modal/Wizard, A2 Liste).
|
||||
|
||||
> ⚙️ **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, Stripe). 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.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Bindet externe Systeme über ein einziges, typsicheres Integrations-Framework an — der Vertrag, über den später Gmail, Outlook, AirCall, PandaDoc, Stripe und KWP laufen. Ein Admin stellt eine `DataConnection` über OAuth2-Connect oder API-Key-Connect in der Settings-UI her; die type-safe Adapter-Registry erlaubt neue Connection-Typen ohne Kern-Änderung; `AppSyncRun`/`AppSyncItem` protokollieren Sync-Läufe in Klartext; Connection-Health-Monitoring zeigt den Status jeder Verbindung (active/degraded/broken/revoked/pending) mit Klartext-Diagnostik + Lösungs-Hinweisen; OAuth-Tokens sind per-Tenant-DEK-verschlüsselt (AD-8). Mehrere Connections pro App pro Tenant möglich (z. B. drei Gmail-Mailboxen).
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| Integrations-Katalog [`/admin/integrations`] | App-Karten nach Kategorie (ERP / Kommunikation / Kalender / Signatur / Payment / KI) · je App: Logo, Beschreibung, Status-Ampel, Anzahl aktive Connections · Suche + Filter (Kategorie/Status/Phase) | A6 |
|
||||
| App-Detail / Connection-Verwaltung [`/admin/integrations/:app`] | Pro DataConnection: Status-Indikator (grün active / gelb degraded / rot broken / grau revoked|pending), Klartext-Status-Hinweis, letzter Sync-Zeitpunkt, Re-Sync-Funktion, Reconnect (bei degraded/broken), Disconnect, Sync-History-Liste (AppSyncRun mit Klartext-Summary) · mehrere Connections pro App | A6+A2 |
|
||||
| Connection-Setup-Wizard [Modal/Flow] | Voraussetzungen-Check → Credential-Formular (auto-generiert aus `connection_schema`) → Validation/Health-Check → Initial-Sync-Option · OAuth2-Redirect-Variante + API-Key-Eingabe-Variante (mit Reveal) | A5+A6 |
|
||||
| Sync-History / Sync-Run-Detail [`…/syncs`, `…/syncs/:id`] | Liste der AppSyncRuns (Datum, kind pull/push/webhook/manual, Status, items_total/succeeded/failed, Klartext-Summary) · Filter (Datum/Status/Operation) · Run-Detail mit AppSyncItem-Liste (entity↔external_id, operation, Status, Klartext-Fehler) + AppSyncRunLog | A2/A3 |
|
||||
|
||||
*(Konkrete App-spezifische Setup-Komponenten = in den Modul-Phasen P14/P15/P16/P20. KWP-Sync-UI = v2/P32.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] DataConnection per OAuth2-Connect-Flow (Gmail, Outlook, AirCall, PandaDoc, Google Calendar) ODER API-Key-Connect (KWP, Stripe) 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
|
||||
- [ ] OAuth-Tokens per-Tenant-DEK-verschlüsselt gespeichert (AD-8); Token-Refresh-Worker; degraded/broken → Klartext-Notification an Tenant-Admin (via notify())
|
||||
- [ ] Lifecycle: Connect-Wizard (Voraussetzungen → auto-generiertes Credential-Formular → Validation → Initial-Sync), Reconnect (gleiche Connection-ID, kein History-Verlust), Disconnect (Multi-Step-Confirm + Cleanup, Status revoked statt Hard-Delete)
|
||||
- [ ] 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
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
App-Katalog als Karten-Grid gruppiert nach Kategorie, je Karte App-Logo + Beschreibung + Status-Ampel + Anzahl-aktive-Connections, Such-Feld + Filter (Kategorie/Status/Phase); Connection-Card (App-Logo, Status-Ampel grün/gelb/rot/grau, Klartext-Status-Hinweis, letzte-Sync-Zeit, Buttons Verbinden/Re-Sync/Reconnect/Trennen) — als wiederverwendbares Element für mehrere Connections pro App; Setup-Wizard (mehrstufig, Progress) mit Voraussetzungen-Check-Schritt, auto-generiertem Credential-Formular aus JSON-Schema (Text-/Key-/Secret-Felder mit Reveal-Toggle), OAuth2-Redirect-Trigger-Variante, Validation-/Health-Check-Schritt, optionalem Initial-Sync-Schritt; Disconnect-Bestätigungs-Dialog (Multi-Step, Klartext „Beim Trennen werden alle Sync-Jobs gestoppt …"); Sync-History-Liste (Datum/kind/Status/items-Zähler/Klartext-Summary) mit Filter nach Datum/Status/Operation; Sync-Run-Detail mit AppSyncItem-Tabelle (entity↔external_id, operation, Status, Klartext-Fehler) + Log-Einträgen mit Severity; manueller Re-Sync-Trigger mit Klartext-Progress-Anzeige bei langen Läufen; Status-/Klartext-Banner für degraded/broken/Schema-Drift mit Lösungs-Knopf (Reconnect/Anleitung); Empty-/Loading-/Permission-Denied-/Fehler-States (Klartext).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (R-P5) aktualisiert:
|
||||
@@ -0,0 +1,52 @@
|
||||
# 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`
|
||||
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A3 Detail, A5 Modal, A6 Settings).
|
||||
|
||||
> 🔴 **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.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Kontakte, Firmen und Leads als **typisierte First-Class-Entitäten** verwalten — mit Custom-Feldern, Tags, append-only Activity-Stream und Live-Duplikat-Schutz. Es ist das Fundament der Kern-Kette (Lead → Projekt). Der Boilerplate-Entity-Builder ist entfernt (AD-2); Konfigurierbarkeit über `CustomFieldDefinition`/`CustomFieldValue`.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| Kontakt-Liste [`/contacts`] | Avatar+Name, Firma, Email, Telefon, Tags, Verantwortlicher, letzte Activity · Filter (Verantwortlicher/Tags UND-ODER/Firma/Datum) · Bulk (Tag/Zuweisen/Archiv/CSV) | A2 |
|
||||
| Firmen-/Organisationen-Liste [`/contacts/companies`] | Name, Branche/Org-Merkmal, Kontakt-Anzahl, Verantwortlicher, letzte Activity | A2 |
|
||||
| **Kontakt-Detail** [`/contacts/:id`] | Stammdaten inline-editierbar · verknüpfte Firmen + Rolle (haupt/sekundär) · Tags · Panels (Projekte/Dateien/Tasks) · Custom-Felder · Notizen (Markdown) · **Activity-Stream** (inkl. BCC-gelogte Mails + Anrufe) · Quick-Actions (Anrufen/Email/Termin/Task/Tag) | A3 — Muster-Template für alle Detail-Views |
|
||||
| Firma-/Org-Detail [`/contacts/companies/:id`] | Analog + Kontakt-Verknüpfungen mit Primär-Markierung + Rolle | A3 |
|
||||
| Custom-Felder [`/admin/custom-fields`] | Felder je Entity-Typ, Typ, Nutzungs-Anzahl, Quelle (SHK-Template/eigen), Sortierung, Archiv | A2 |
|
||||
| Tag-Verwaltung [`/admin/tags`] | Name, Farbe, Verknüpfungs-Anzahl, Merge | A2 |
|
||||
| Duplikat-Tool [`/admin/duplicates`] | Duplikat-Paare + Match-Kriterium · Side-by-Side-Merge (Feld-für-Feld) | A5 + Side-by-Side |
|
||||
|
||||
*(Lead-Inbox/Lead-Detail/Lead-Statistiken → P7. Audit/Notif/Files/Tasks-Oberflächen → P3/P4.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Alle CRM-Kernentitäten typisiert mit RLS (Contact, Company, Lead, KontaktRelation, Activity, CustomField, Tag) — Entity-Builder entfernt (AD-2)
|
||||
- [ ] Kontakt-Oberbegriff: Kontakttyp (Privatperson/Organisation), Kontaktstatus (Kontakt/Kunde/Bestandskunde), Kontaktart (Haupt-/Sekundärkontakt als Relation)
|
||||
- [ ] Server-seitig Filtern/Sortieren/Paginieren + Bulk-Actions + CSV-Export
|
||||
- [ ] Detail mit Inline-Edit, Activity-Stream (append-only Event-Sourcing), verknüpfte Entitäten, Custom-Felder
|
||||
- [ ] SHK-Branchen-Custom-Felder als Template geseedet
|
||||
- [ ] Live-Match-Check (Duplikat-Warnung) beim Anlegen
|
||||
- [ ] `crm.*`-Permission-Bundle (read_own/read_all/write/delete/admin) — serverseitiger Owner-Filter
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Daten-Tabelle (sortierbar, paginiert), Filter-Bar (Multi-Select Tags UND/ODER), Bulk-Action-Toolbar, Detail-Panel mit Inline-Edit-Feldern, Tag-Chips (farbig), Relations-Liste mit Rollen-Badge, Activity-Timeline (Actor-Kind-Marker), Custom-Feld-Renderer je Typ, Quick-Action-Buttons, Duplikat-Banner/Hinweis, Side-by-Side-Merge-Ansicht, Empty-/Loading-/Permission-Denied-States (Klartext).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (R-P6) aktualisiert:
|
||||
@@ -0,0 +1,52 @@
|
||||
# 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`
|
||||
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A3 Detail, A5 Modal, A6 Settings, KPI-Kit).
|
||||
|
||||
> 🔴 **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.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Eingehende Leads aus allen Quellen (Form-Submission, eingehende Email, AirCall-Inbound, manueller Eintrag, Custom-Quellen) landen in einem Triage-Arbeitsplatz, werden automatisch angelegt, gegen Spam/Anomalien geschützt und sind auswertbar. Lead ist die **Vorstufe** des `Projekt`-Kerns: bei Weiterverarbeitungsfreigabe wird der Lead zum Projekt (Lead → Projekt, Domäne 5), der Kontakt separat verknüpft. Das `lead.qualified`-Event ist Extension-Point für P8 (Auto-Verkaufsfall M049).
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| **Lead-Inbox** [`/leads`] | Tabelle/Karten: Identität (Name, sonst Email/Telefon, sonst Quelle+Datum), **Quelle**, Status, Verantwortlicher, Eingegangen (relativ <7 T), letzte Activity, 80-Zeichen-Message-Vorschau · Marker „Mögliches Duplikat" / „Spam-Verdacht" / „Auto-promoviert" · Filter (Status [Default new+qualified], Quelle, Verantwortlicher inkl. „Nicht zugewiesen", Eingegangen-Range, Tags, Lead-Custom-Felder) · Toggle „Spam ausblenden" (Default ein) + „Konvertierte einblenden" (Default aus) · Quick-Actions inline: Zuweisen, Status, **Zu Projekt machen** (bei Freigabe), Spam · Bulk · Real-time-Refresh | A2 + Triage-Akzente |
|
||||
| **Lead-Detail** [`/leads/:id`] | Stammdaten inline-editierbar · Quellen-Detail (Form-Name/Submission-ID/Submitter-IP bzw. Email-Header bzw. Anruf-Aufzeichnungs-Link) · **Weiterverarbeitungsfreigabe-Feld (ja/nein/unklar)** · Spam-Score mit Klartext-Begründung · **Match-Hinweise** (existierende Kontakte gleiche Email/Telefon, Soft-Match Name+Adresse) mit Direkt-Übergängen · Re-Submission-Verlauf · Status-Wechsler (new/qualified/converted/lost/spam) · DSGVO-Auto-Lösch-Hinweis mit Datum · Triage-Quick-Actions (Annehmen, Antworten, Anrufen, Notiz, Task, Termin) · Sub-Sektionen Übersicht/Konversation/Activity-Stream/Custom-Felder | A3 |
|
||||
| **Lead → Projekt** [bei Freigabe, kein Modal-Zwang] | Bei `weiterverarbeitung_freigabe=ja`: Projekt aus Lead anlegen · Daten-Vererbungs-Vorschau (welche Lead-Felder ins Projekt fließen) · Ziel-Pipeline + Start-Status wählen · **Kontakt separat verknüpfen** (neuer Kontakt ODER bestehenden zuordnen, Auto-Email/Telefon-Match-Hinweis) · Mängel-Banner bei fehlenden Pflichtdaten (z.B. Name) | A5 — Kern-Moment der Kette! (ersetzt das alte 4-Optionen-Promotion-Modal) |
|
||||
| Lead-Statistiken [`/leads/statistics`] | KPI-Kacheln (Eingegangen, Konversion Lead→Projekt, Konversion Lead→Won, Reaktionszeit, Spam-Quote, Open-Leads >24h) · Aufschlüsselung nach Quelle/Verantwortlichem/Tag/Wochentag/Status · Trend-Charts mit Vorperioden-Vergleich · Date-Range-Selektor + Vergleichs-Toggle · Drill-Down → vorgefilterte Inbox · permission-aware (Verantwortlichen-Aufschlüsselung nur mit `leads.read_all`) | A2 + KPI-Kit |
|
||||
| Quellen-Verwaltung [`/admin/lead-sources`] | Quellen-Liste: Name, Typ (System/Custom), 30-Tage-Lead-Count, Status · Custom-Quelle anlegen (Name, Display-Label, optional Default-Verantwortlicher/Default-Tags) · Edit/Archivieren · **Webhook-URL mit Token** (für Fremd-Website-Leads) | A2 / A6 |
|
||||
| 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.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Lead-Inbox als Arbeitsplatz: Status-Filter, Triage-Quick-Actions, Bulk-Operationen, Real-time-Refresh
|
||||
- [ ] **Lead → Projekt bei Weiterverarbeitungsfreigabe** (kein Contact-Promotion-Modal); Vererbung relevanter Lead-Daten ins Projekt; Kontakt separat verknüpft
|
||||
- [ ] Multi-Quellen-Auto-Anlage (Form/Email/AirCall-Inbound/manuell/Custom) mit `lead.created`-/`lead.qualified`-Events (Automation + P8-Extension-Point)
|
||||
- [ ] Status-Workflow (new|qualified|converted|lost|spam) mit definierten Übergängen; DSGVO-Auto-Lösch-Cron (spam 30 T, lost konfigurierbar)
|
||||
- [ ] Anti-Spam: Rate-Limiting/Anomalie-Detection, Quarantäne-Modus, Tenant-Admin-Notification bei Auto-Pause
|
||||
- [ ] Statistiken-Page mit KPI-Kacheln, Quellen-Aufschlüsselung, Trends — permission-aware
|
||||
- [ ] `leads.*`-Permission-Bundle (read_own/read_all/write/delete/admin) mit Owner-Check; nicht-eigene Leads bei `read_own` unsichtbar (404, nicht 403)
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Triage-Daten-Tabelle/Karten-Umschalter (sortierbar, cursor-paginiert 50/Page), Filter-Bar (Multi-Select Status/Quelle/Verantwortlicher, Date-Range, Tags, Custom-Feld-Filter), Toggle-Chips (Spam ausblenden / Konvertierte einblenden), Hinweis-Marker (Duplikat/Spam/Auto-promoviert), Inline-Quick-Action-Picker (Zuweisen/Status), Bulk-Action-Toolbar mit Klartext-Bestätigungen, Detail-Panel mit Inline-Edit, Weiterverarbeitungsfreigabe-Auswahl (ja/nein/unklar), Spam-Score-Anzeige mit Begründung, Match-Hinweis-Liste mit Sprung-Links, Re-Submission-Verlauf, DSGVO-Lösch-Countdown-Hinweis, Status-Wechsler, „Lead → Projekt"-Flow (Daten-Vererbungs-Vorschau + Pipeline-/Status-Wahl + separater Kontakt-Verknüpfungs-Picker mit Match), KPI-Kacheln, Bar-/Line-Charts mit Vorperioden-Delta, Drill-Down-Verlinkung, Webhook-URL-Feld mit Copy + Token, Anti-Spam-Toggle-Zeilen, Empty-/Loading-/Fehler-/Permission-Denied-States (Klartext + Lösungs-Knopf).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (R-P7) aktualisiert:
|
||||
@@ -0,0 +1,51 @@
|
||||
# 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`
|
||||
**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.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Baut den `Projekt`-Kern als eine typisierte Tabelle (Superset der Felder, dazu `CustomFieldValue`) und die Pipeline-Engine als frei konfigurierbare Views: Pipeline anlegen/benennen/duplizieren, Statuswerte (Stages) je Pipeline, Zugriff je Rolle/User/Gruppe (`PipelineAccess`), Feld-Sichtbarkeit + Pflichtfelder pro Pipeline+Status (`PipelineFieldConfig`). Darauf der EINE konfigurierbare Kanban (ein Board für alle Pipeline-Typen) plus Listen-View, Projekt-Detail, fortlaufende Projekt-Nummern (HiveNumberSeq), Forecast/KPIs und Lost-Reasons. Konsumiert das `lead.qualified`-Event aus P7 (Auto-Verkaufsfall M049 = Projekt in Sales-Pipeline). Auftrags-Features + Sub-Areas folgen in P9.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| **Pipeline-Kanban (konfigurierbar)** [`/projects` bzw. `/projects/pipelines/:id`] | Spalten = Stages der gewählten Pipeline (in Reihenfolge): Stage-Name, Projekt-Anzahl, Aggregat-Volumen (gegated), Win-% · Projekt-Karten: Titel, Volumen (gegated über PipelineFieldConfig + Field-Level-Perms), Verantwortlicher-Avatar, Close-/Zeitraum-Datum, max. 3 Tags, Stuck-/Überzogen-Marker · **Drag&Drop** Stage-Wechsel mit Validation · Drop in `gewonnen`-Stage → Bestätigung · Drop in `verloren`-Stage → Lost-Reason-Pflicht · **Pipeline-Switcher** (zwischen sales/auftrag/custom-Pipelines) · Filter (Verantwortlicher/Tags/Volumen-Range/Datum) + „nur meine" · Bulk-Select · Pagination pro Spalte (100+) · Real-Time (SSE) | **BESPOKE** (ein Board für ALLE Pipeline-Typen) |
|
||||
| Projekt-Liste [`/projects/list`] | Projekt-Nummer, Titel, Pipeline, Status (Stage), Volumen (gegated), verknüpfter Kontakt/Firma, Zeitraum/Close-Datum, letzte Activity · Cross-Pipeline-Sicht mit Pipeline-Spalte + -Filter · sortierbare Header, Spalten-Konfig, Bulk, CSV-Export, Pagination | A2 |
|
||||
| **Projekt-Detail** [`/projects/:id`] | Stammdaten inline-editierbar (Nummer, Name, Beschreibung, Volumen/potenzieller Wert, Pipeline, Stage, Zeitraum, Adressen-Slots) · verknüpfte Kontakte mit Rolle (auftraggeber/bauherr/rechnungsempfaenger/ansprechpartner) · Lead-Herkunft-Hinweis (`konvertiert_aus_lead_id`) · **Status-Visualisierung als klickbare Stage-Bar** (pipeline-intern) · Stage-Historie mit Verweildauer · Gewonnen/Verloren-Banner mit 24h-Rückgängig · Tags · Custom-Felder (pro Pipeline via PipelineFieldConfig geschaltet) · Activity-Stream · Quick-Actions (Anrufen/Email/Termin/Task/Notiz) · Sub-Area-Tabs (Termine/Aufgaben/Aktivitäten/Dokumente — Rechnungen/Checklisten/Abnahme in P9) | A3 (Muster-Detail-View) |
|
||||
| **Pipeline-Config-Admin** [`/admin/pipelines` bzw. `/admin/pipelines/:id`] | Pipelines-Liste (Name, typ_hint, Stage-Anzahl, aktive Projekte, Status) · Editor: Stages mit Drag&Drop je Name/stage_kind (offen/gewonnen/verloren)/Win-%/Farbe · **PipelineAccess** (wer darf sehen/bearbeiten: Rolle/User/Gruppe, kann_sehen/kann_bearbeiten) · **PipelineFieldConfig** (pro Feld — System ODER `custom:<id>` — Sichtbarkeit + Pflicht + Reihenfolge, optional je Status) · Validation min. 1 gewonnen + 1 verloren · neue Pipeline anlegen/duplizieren/archivieren | A2 + A6 |
|
||||
| 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.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] **EIN `Projekt`-Kern** (typisierte Superset-Tabelle, Deal- + Auftrags-Felder, + CustomFieldValue) mit fortlaufenden Projekt-Nummern (HiveNumberSeq); RLS + Soft-Delete
|
||||
- [ ] **Pipeline-Engine:** Pipeline anlegen/benennen/duplizieren/archivieren (`typ_hint` sales/auftrag/custom); Stages = die Statuswerte; min. 1 gewonnen + 1 verloren
|
||||
- [ ] **PipelineAccess** (Sichtbarkeit/Bearbeitung je Rolle/User/Gruppe) + **PipelineFieldConfig** (Feld-Sichtbarkeit + Pflicht + Reihenfolge je Pipeline/Status); nicht sichtbare Felder bleiben erhalten
|
||||
- [ ] **EIN konfigurierbarer Kanban** (Drag&Drop, Stage-Wechsel-Validation, gewonnen/verloren-Workflow, Real-Time SSE) + Listen-View mit Filter/Bulk/CSV
|
||||
- [ ] Lead→Projekt-Eingang (P7) + `lead.qualified`→Auto-Projekt in Sales-Pipeline (M049); Pipeline-Wechsel statt Won-Handoff (kein zweiter Datensatz)
|
||||
- [ ] Forecast, KPIs pro Verantwortlichem, Stage-Conversion-Rates, Lost-Reason-Auswertung mit Aggregat-Cache
|
||||
- [ ] Field-Level-Sichtbarkeit (Volumen/Aggregate) primär über PipelineFieldConfig; `deals.read_volume_*`/`read_aggregates` als Permission-Backstop — Volumen ohne Recht zeigt „—"
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Kanban-Board (Spalten = Stages, horizontal scrollbar/responsive), Drag&Drop-Karten, Stage-Spalten-Header mit Aggregat (Count + Volumen + Win-%), Projekt-Karte (Titel, gegatetes Volumen, Avatar, Datum, Tag-Chips, Stuck-Marker), Pipeline-Switcher, Filter-Bar + „nur meine"-Quick-Filter, Bulk-Action-Toolbar, gewonnen/verloren-Bestätigungs-Dialog (Lost-Reason-Pflicht), 24h-Rückgängig-Banner, Daten-Tabelle (sortierbar, paginiert, Spalten-Konfig, CSV), Detail-Panel mit Inline-Edit, klickbare Status-/Stage-Bar, Stage-Historie mit Verweildauer, Lead-Herkunft-Hinweis, Relations-Liste mit Rollen-Badge, Custom-Feld-Renderer je Typ, Tag-Chips, Activity-Timeline, Quick-Action-Buttons, Pipeline-Editor (Stage-Drag&Drop, stage_kind/Win-%/Farbe), PipelineAccess-Matrix (Principal × sehen/bearbeiten), PipelineFieldConfig-Liste (Feld × sichtbar/pflicht/Reihenfolge je Status), Lost-Reasons-CRUD-Liste, KPI-Kacheln/Charts (Forecast/Conversion/Lost-Verteilung), „Volumen verborgen (—)"-Zustand, Empty-/Loading-/Fehler-/Permission-Denied-States (Klartext).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (R-P8a/b) aktualisiert:
|
||||
@@ -0,0 +1,53 @@
|
||||
# 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`
|
||||
**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.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Liefert die auftragsspezifischen Features auf dem `Projekt`-Kern aus P8: die **Plantafel** (Scheduling pro Monteur/Tag, Drag&Drop, Konflikt-Detection aus HR/Kalender, offline-fähiger Monteur-Mobil-Modus), die **Sub-Areas am Projekt** (Termine, **Rechnungen [v1 NEU]**, Checklisten, Aufgaben, Aktivitäten, Dokumente, ProjektMitglieder, ProjektExterneFelder/KWP-Halter) und die **Abnahme** als immutable Checklisten/Protokoll-Sub-Area mit Touch-Signatur, PDF + Auto-Email, offline-Sync. Mängel sind Checklisten (`typ=maengel`).
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| 📱 **Plantafel** [`/projects/plantafel`] | Desktop: Y = Mitarbeiter, X = Zeit (Tag/Woche/Monat-Switcher) · Einträge je Person×Slot: Projekt-Titel, Status-Farbe (pipeline-basiert), Adresse-Kurzform · **Drag&Drop verschieben/resizen** · neue ScheduleEntry per Klick auf leeren Slot · **Konflikt-Indikatoren** (Doppelbelegung; Urlaub/krank aus HR M14; außerhalb Verfügbarkeit/Arbeitszeit) mit Klartext-„Trotzdem?" · MA-Filter (Rolle/Group/Verfügbarkeit) + Projekt-Filter · Status-Wechsel (planned→confirmed→in_progress→done/cancelled) · Bulk-Reassign · Calendar-Sync-Indikator · **Monteur-Mobil-Modus: „Meine Termine heute"** (Liste mit Adresse + Navigations-Link, Tap-Statuswechsel) + „Meine Woche", **offline-fähig** | **BESPOKE** (höchste Priorität nach Flow-Editor) |
|
||||
| 📱 **Projekt-Detail — Auftrags-Sub-Areas** [`/projects/:id`] | Erweitert P8-Detail um Sub-Area-Tabs/Sektionen: **ProjektMitglieder** (Monteure/PL/zuständig/Beobachter mit Rolle, Multi-Add aus Group), **Termine**, **Rechnungen [v1 NEU]**, **Checklisten** (inkl. Mängel), **Aufgaben**, **Dateien/Dokumente**, **Abnahmen**, **ProjektExterneFelder** (KWP/API — v1 nur Anzeige) · Baustellen-/Rechnungs-/Bauherr-Adress-Slots · Offene-Mängel-Banner · **Mobil-Modus: Stammdaten + heutige Tasks + Abnahme-Button + One-Tap-Foto-Upload** | A3 + 📱-Variante |
|
||||
| 📱 **Abnahme-Workflow** [`/projects/:id/acceptance/new`] | SHK-Abnahme-Protokoll (Datum, Anwesende, Druckprobe ja/nein+Wert, Funktionsprüfung, Zählerstände, Inbetriebnahme/Garantie-Datum, übergebene Dokumente-Checkliste, **Mängel-Repeater mit Foto je Mangel**, Bemerkungen Kunde/Monteur) → **Mängel-Klassifizierung** (kritisch=verweigert / klein=mit Vorbehalt / kosmetisch=erfolgt) bestimmt acceptance_kind → **Touch-Signatur Kunde** (Name eingeben, kann von Kontakt abweichen; IP+Timestamp auto) → **Touch-Signatur Monteur** → Bestätigen → PDF + Auto-Email an Kunden · **offline-fähig, Sync bei Verbindung** · nach Speichern **immutable** (nur archivierbar) | **BESPOKE-Mobile** |
|
||||
| Abnahme-Liste [`/projects/:id/acceptance`] | Protokoll-Liste je Projekt (Mehrfach-/Teilabnahmen): Datum, acceptance_kind, Unterzeichner, PDF-Link, Mängel-Status · letzte `full`-Abnahme bestimmt Stage-Wechsel-Vorschlag | A2 |
|
||||
| Rechnung-Sub-Entity [im Projekt-Detail, Sub-Area] | Rechnung anlegen/anzeigen: Rechnungsnummer (HiveNumberSeq), Betrag, Status (entwurf/gestellt/bezahlt/storniert), Datum, fällig_am, verknüpfte Datei, Quelle (manuell/kwp) · einfaches Sub-Entity am Projekt (v1 NEU, E3) | A2/A5 (in Sub-Area) |
|
||||
| Pipeline-Config-Auftragsteil [`/admin/pipelines/:id`] | Auftrags-spezifische Stage-Optionen: `requires_acceptance_protocol` je Stage (Block beim Wechsel ohne Abnahme), Acceptance-Form-Template-Zuweisung, auto_archive_after_days · (Basis-Pipeline-Editor = P8) | A6 |
|
||||
| Acceptance-Form-Templates [`/admin/projects/acceptance-forms`] | Form-Builder-basiert (M05, Subtyp acceptance_form), SHK-Default geseedet · Verwaltung/Zuweisung | A6 |
|
||||
| Project-Templates [`/admin/projects/templates`] | Vorlagen mit Default-Pipeline/Stage/Mitgliedern/Tasks/ScheduleEntries/Custom-Feldern | A2 |
|
||||
|
||||
*(Projekt-Kanban + Listen-View + Projekt-Detail-Basis + Pipeline-Engine = P8. „Sales-Verlauf-Sektion" als Deal-Snapshot entfällt — gemeinsamer Projekt-Activity-Stream. Material-Ausgang/Lagerist/Zeiterfassung/Leistungspositionen → v2.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] **Plantafel** (Scheduling pro Monteur/Tag, Drag&Drop verschieben/resizen, Status-Workflow, Bulk-Reassign) — offline-fähiger Monteur-Mobil-Modus („Meine Termine heute"/„Meine Woche")
|
||||
- [ ] **Konflikt-Detection** (Doppelbelegung, Urlaub/krank aus HR M14, Verfügbarkeits-Regeln) mit Klartext-„Trotzdem zuweisen?" · Calendar-Sync (M25) der ScheduleEntries
|
||||
- [ ] **Sub-Areas am Projekt:** Termine, **Rechnungen [v1 NEU]**, Checklisten (inkl. Mängel typ=maengel), Aufgaben, Aktivitäten, Dokumente, ProjektMitglieder, ProjektExterneFelder (KWP-Halter v1)
|
||||
- [ ] **Abnahme als Checklisten/Protokoll-Sub-Area:** immutable (6 J), Mängel-Checkliste eingebunden, Touch-Signatur Kunde + Monteur, Mängel-Klassifizierung, PDF + Auto-Email, **offline-Sync**, Mehrfach-/Teilabnahmen
|
||||
- [ ] Stage-Wechsel-Validation: `requires_acceptance_protocol` blockt ohne Abnahme; cancelled erfordert Grund; 24h-Reverse aus Terminal-Stages
|
||||
- [ ] Mängel mit `with_defects` werden als Tasks angelegt; `rejected` → zurück in Ausführung + Notification an PL
|
||||
- [ ] Permissions: `projects.*` (read_own_member/read_own_pl/read_all/write/change_stage/manage_members/delete/admin), `plantafel.*` (read_own/read_all/write/bulk_reassign), `acceptance.*` (read/write/admin); Volumen-Field-Level + PipelineFieldConfig; Hard-Delete blockt bei Abnahme-Protokollen (Aufbewahrung)
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Plantafel-Raster (Y=MA, X=Zeit, Zeitraum-Switcher Tag/Woche/Monat), Drag&Drop-/Resize-ScheduleEntry-Blöcke, leerer-Slot-Klick-Anlage, Konflikt-Indikatoren + „Trotzdem?"-Dialog, MA-/Projekt-Filter, Status-Wechsler je Eintrag, Bulk-Reassign-Funktion, Calendar-Sync-Indikator, Monteur-Mobil-Tagesliste mit Adresse/Navigations-Link + Tap-Statuswechsel + Offline-Hinweis, Sub-Area-Tabs/Sektionen am Projekt-Detail, ProjektMitglieder-Liste mit Rollen-Badge + Multi-Add, Rechnungs-Sub-Liste (Nummer/Betrag/Status/Fälligkeit/Quelle/Datei) + Anlage-Form, Checklisten-/ChecklistItem-Liste mit Status + Mängel-Klasse + Foto, Abnahme-Formular-Renderer (Repeater für Mängel mit Foto-Upload aus Kamera), Mängel-Klassifizierungs-Auswahl (kritisch/klein/kosmetisch), Touch-Unterschriften-Feld (Kunde + Monteur), PDF-Vorschau/-Download, immutable/gesperrt-Banner, Offene-Mängel-roter-Banner, KWP-Externe-Felder-Anzeige (read-only), Acceptance-Form-Template-Picker, Project-Template-Auswahl, One-Tap-Foto-Upload, Empty-/Loading-/Fehler-/Permission-Denied-/Offline-States (Klartext + Lösungs-Knopf).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (R-P9a/b) aktualisiert:
|
||||
@@ -0,0 +1,49 @@
|
||||
# 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.
|
||||
|
||||
> 🟢 **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.
|
||||
|
||||
## 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).
|
||||
|
||||
## 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 |
|
||||
| **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.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] **Meilisearch-Keyword-Suche** permission-aware über SearchAdapter (Modul-Registrierung: Kontakt/Firma/Lead/Projekt/File/Task/User); pgvector/Hybrid → v2
|
||||
- [ ] 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
|
||||
- [ ] **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
|
||||
- [ ] Permissions: `search.use`/`search.admin` (Suche selbst leichtgewichtig — Sichtbarkeit über Modul-Permissions); `dashboard.read/customize` (v1: nur Filter/Zeitraum), Drag&Drop-Customize → v2
|
||||
|
||||
## 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).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (R-P11a/b) aktualisiert:
|
||||
@@ -0,0 +1,58 @@
|
||||
# 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`
|
||||
**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.
|
||||
|
||||
## 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.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| **Flow-/Node-Editor** [`/automations/:id/edit`] | Graph-Canvas (Knoten + Kanten) · Knoten-Katalog-Sidebar (filterbar nach Modul-Quelle, Drag-&-Drop oder Klick-Hinzufügen) · Knoten-Konfig-Panel mit **Klartext-Label** · Mini-Map · Toolbar (Zoom/Pan/Undo/Redo/Zentrieren/Auto-Layout) · Validation-Hinweise inline (unverbundener Knoten, Cycle-Warnung, fehlendes Pflichtfeld) · Save/Aktivieren/Deaktivieren · **Dry-Run-Auslöser** | **BESPOKE — schwerste UI** |
|
||||
| **Sprach-zu-Automation-Einstieg** [im Editor] | Text-/Spracheingabe-Feld · Live-Streaming-Antwort · KI-Flow-Vorschau im Canvas + Klartext-Beschreibung · Rückfragen bei Mehrdeutigkeit · Risiko-Hinweise · **Bestätigungs-/Anpassungs-Schritt (nie Auto-Aktivierung!)** · Beispiel-Prompts | Bespoke-Teil des Editors |
|
||||
| **Dry-Run-Vorschau** [Modal im Editor] | „Trifft X Datensätze" + erste 5 Beispiele · Schritt-für-Schritt-Simulation mit Klartext je Step (z. B. „Email würde an … gehen") · **Bestätigungs-Pflicht** ab >100 Datensätzen/Schritt (Schwelle tenant-konfigurierbar) | A5 + Simulations-Liste |
|
||||
| Automation-Liste [`/automations`] | Name, Trigger, Status (aktiv/pausiert/Entwurf), Läufe (30d), letzte Ausführung · „nur meine"-Filter | A2 |
|
||||
| **Execution-Detail** [`/automations/:id/executions/:exec_id`] | `summary_text` · Trigger-Payload user-lesbar · **Step-by-Step-Verlauf mit Klartext je Schritt** (Status, Input/Output, Dauer) · Dry-Run-Marker · **24h-Rückgängig-Button mit Restzeit-Anzeige** · Manuell-Retry · Resume-ab-Schritt | A3 + Timeline |
|
||||
| Execution-Liste [`/automations/:id/executions`] | Letzte N Läufe · Filter (Status/Datum/Trigger-Typ) · Klick → Detail | A2 |
|
||||
| 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.)*
|
||||
|
||||
## 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)
|
||||
- [ ] 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)
|
||||
- [ ] Dry-Run mit Klartext-Wirkungsvorschau + Pflicht-Bestätigung ab Schwelle
|
||||
- [ ] 24h-Reverse-Window: angelegte Entitäten löschen / Status zurücksetzen / Tags rückgängig, Mail-Empfängerliste anzeigen (nicht zurückziehbar), Multi-Step-Confirm + Audit
|
||||
- [ ] Schutz: Loop-Guard (Abhängigkeits-Graph-Warnung), Rate-Limit + Anomalie-Pause, Idempotenz-Key, Resume-ab-Schritt mit Auto-Retry
|
||||
- [ ] Klartext-Diagnostik in allen Execution-Logs (Step-Status, Dauer, Input/Output)
|
||||
- [ ] Plattform- + Tenant-Templates mit Katalog und „aus Rule erstellen"
|
||||
- [ ] AutomationRule/Step/Execution/StepExecution/Credential/Template persistiert (Domäne 7); verschlüsselte AutomationCredentials
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Graph-Canvas (Knoten + Kanten, Pan/Zoom), Knoten-Katalog-Panel (gruppiert/filterbar nach Modul), Knoten-Konfig-Panel (typ-abhängige Felder), Klartext-Knoten-Label-Renderer, Verbindungs-Erstell-Interaktion, Mini-Map, Editor-Toolbar (Zoom/Undo/Redo/Auto-Layout/Zentrieren), Inline-Validation-Badges/Hinweise, Sprach-/Text-Eingabefeld mit Streaming-Antwort, Beispiel-Prompt-Chips, Dry-Run-Vorschau-Liste (getroffene Datensätze + Beispiele), Bestätigungs-Modal (Confirm-Phrase-Variante), Step-by-Step-Timeline mit Status-Markern, 24h-Reverse-Button mit Countdown, Retry-/Resume-Buttons, Abhängigkeits-Graph-Mini-Visualisierung (Loop-Guard), Template-Karten mit Use-Case-Beschreibung, Status-Pills (aktiv/pausiert/Entwurf/fehlgeschlagen/übersprungen), Daten-Tabelle (sortierbar, paginiert), Empty-/Loading-/Permission-Denied-States (Klartext).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (R-P12a/b) aktualisiert:
|
||||
@@ -0,0 +1,57 @@
|
||||
# Designer-Brief · P13 — KI-Layer
|
||||
|
||||
> ⛔ **ABGELÖST (KI→MCP-Pivot, [[AD-26]], 2026-06-22):** Phase 13 (KI-Layer) entfällt — kein KI-Settings-/AI-Credits-Screen. HiveGrid wird MCP-Server; die einzige zugehörige UI ist die Verbindungs-/Settings-Ansicht in **[[VD-MCP]]**. Brief unten = historisch.
|
||||
|
||||
**Phase:** 13/21 · **Modul:** M18 · **Owner-Dev:** Raffael (R-P13) · **Designer:** David (D-KI, Paket Mo 06.07. Compose)
|
||||
**Quellen:** `ROADMAP.md` §Phase 13 · `ENTITY-MODEL.md` Domäne 7 (Automation & KI) · `SCREEN-MAP.md` §6 (KI-Settings / AI-Credits) · `_bmad-output/specs/M18-ki-layer.md` (HiveMind/RAG/Whisper-Teile → v2)
|
||||
**Subframe:** Pflicht je Route. Archetypen aus D0 (A6 Settings/Connection, KPI+Charts). Compose-Paket — wenig Bespoke.
|
||||
|
||||
> 🟡 **v1-Grenze (Scope-Schnitt 11.06.):** HiveMind, RAG/Embeddings, Whisper-Transkription und AlephAlpha sind **v2** (→ P25). v1 baut nur den produktiven **EU-LLM-Gateway** (Mistral La Plateforme primär, Provider-Abstraktion), Token-/AiCredits-Tracking mit harten + Drossel-Limits und die **Andock-Adapter** als Muster. Kein RAG-Chat-UI, kein Whisper-Aufnahme-UI, kein HiveMind-Assistent in v1.
|
||||
> 🔴 **Sprach-zu-Automation gehört sichtbar in den Flow-Editor (P12)** — P13 liefert nur das Gateway dahinter. EU-Datenresidenz wird überall im Klartext kommuniziert; keine US-Kern-Abhängigkeit.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Der EU-only KI-Unterbau: ein Multi-Provider-LLM-Gateway, das Tokens trackt, gegen das lokale **AiCredits**-Konto bucht und Soft-/Hard-Limits durchsetzt. Sichtbare v1-Oberflächen sind die **KI-Settings** (Use-Case-Toggles, Modell-Wahl, EU-Klartext) und das **AI-Credits/Usage-Dashboard**. Die KI selbst wird über v1-Use-Cases konsumiert (primär Sprach-zu-Automation in P12, plus Lead-Zusammenfassung/Programm-Hilfe/Stuck-Vorschläge als KI-Widgets in bestehenden Detail-/Dashboard-Views). Promptfoo testet die ausgelieferten Funktionen.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| **KI-Settings** [`/admin/ai`] | Use-Case-Toggles (je v1-Use-Case ein/aus) · Modell-Wahl (Mistral Large/Small je Use-Case) · Token-Limit pro Monat · **EU-Datenresidenz-Klartext-Block** · Hinweis Plan-Erweiterung extern | A6 |
|
||||
| **AI-Credits / Usage** [`/admin/usage/ai`] | Saldo (current_balance_tokens) · Verbrauch je Use-Case (Donut) · Verlauf über Zeit (Linie) · Top-User · **80%-Soft-Limit-Warnbanner** · Hochrechnung Monatsende · Plan-Limit-Anzeige | KPI + Charts |
|
||||
| **Soft-/Hard-Limit-Banner** [global] | 80%-Banner („KI-Budget zu 80% verbraucht …") · 100%-Klartext bei Aufruf-Versuch („KI-Budget erschöpft, Erweiterung auf hivegrid.de/pricing") · kritische Funktionen (Klartext-Diagnostik) bleiben aktiv | Banner (A7/Topbar) |
|
||||
| KI-Widget: Lead-Zusammenfassung [im Kontakt-/Lead-Detail] | On-demand-Generierung des Pre-Termin-Briefs · Quelle Activity-Stream/Custom-Felder/Form-Submissions · Cache-Hinweis · Klartext bei Provider-Down | Compose (in A3-Detail) |
|
||||
| KI-Widget: Stage-Stuck-Vorschläge [im Dashboard] | Wöchentlich generierte Vorschläge für Stuck-Deals/-Projekte · Quick-Action-Buttons (Anrufen/Email) · **KI-Vorschlag-Kennzeichnung** | Compose (in Dashboard) |
|
||||
| Programm-Hilfe-Einstieg [In-App, klein] | Frage-Eingabe → KI-Antwort (Klartext + Deep-Link) · Conversation-Historie pro User · **„KI-Vorschlag"-Markierung** bei Fallback-Diagnostik | A5-klein / Drawer |
|
||||
|
||||
*(RAG-Chat, Whisper-Aufnahme-UI, HiveMind-Assistent, Bring-Your-Own-Key → v2.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] EU-LLM-Gateway (Mistral La Plateforme primär, Provider-Abstraktion für zweiten EU-Provider → v2) mit Token-Tracking je Aufruf
|
||||
- [ ] AiCredits-Buchung: AiTokenUsage je Aufruf, Aggregat-Abzug, Soft-Limit (80% Banner + Admin-Mail), Hard-Limit (100% Pause außer kritische Funktionen, Monats-Reset)
|
||||
- [ ] KI-Settings pro Tenant: aktivierte Use-Cases, Default-Modelle, Monats-Token-Limit, EU-Residenz-Klartext
|
||||
- [ ] Usage-Dashboard: Verbrauch je Use-Case (Donut), Zeitverlauf, Top-User, Forecast, Plan-Limit
|
||||
- [ ] v1-Use-Cases sichtbar: Sprach-zu-Automation (Gateway für P12), Lead-Zusammenfassung, Programm-Hilfe/FAQ, Klartext-Diagnostik-Fallback, Stage-Stuck-Vorschläge
|
||||
- [ ] Sicherheits-Layer-Wirkung im UI: schreibende KI-Aktionen erfordern Bestätigungs-Workflow (Action-Boundary); KI-Fallback-Outputs als „KI-Vorschlag" markiert
|
||||
- [ ] Klartext bei Provider-Down / Limit-erreicht statt technischer Fehler
|
||||
- [ ] Promptfoo-Eval-Suite deckt ausgelieferte KI-Funktionen ab (CI-Pflicht, kein UI)
|
||||
- [ ] v2-Andock-Adapter als Muster vorhanden: `RetrievalProvider`-Interface, Outbox-Index-Events (via P11), Bestätigungs-Grenze (kein v1-UI nötig)
|
||||
- [ ] Datenmodell persistiert: LlmGatewayProvider/Model, AiSettings, AiCredits, AiTokenUsage, Conversation/Message, GeneratedObject (Domäne 7)
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Settings-Sektionen mit Toggle-Zeilen (Klartext-Beschreibung), Modell-Auswahl-Dropdowns je Use-Case, Token-Limit-Eingabe, EU-Datenresidenz-Klartext-Block, KPI-Kacheln (Saldo/Verbrauch/Forecast), Donut-Chart (Verbrauch je Use-Case), Linien-Chart (Verlauf), Top-User-Liste, Soft-/Hard-Limit-Warnbanner (stapelbar mit Topbar-System), KI-Vorschlag-Badge/Kennzeichnung, On-demand-Generieren-Button mit Lade-Zustand, Conversation-Historie-Liste, Bestätigungs-Dialog für schreibende KI-Aktionen, Klartext-Provider-Down-Hinweis, Empty-/Loading-/Permission-Denied-States.
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (R-P13) aktualisiert:
|
||||
@@ -0,0 +1,57 @@
|
||||
# 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`
|
||||
**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).
|
||||
> 🔴 **DSGVO-First:** Double-Opt-In, Suppression-Check vor jedem Versand, One-Click-Unsubscribe, Pflicht-Footer (Impressum + Unsubscribe), Pflicht-Checkliste vor Versand — Versand wird bei rotem Check **blockiert**.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Der Betrieb verifiziert pro Mandant eine eigene **Sende-Domain** und versendet von dort transaktionale, Automation- und Marketing-Mails über Mailjet (AD-6) — ohne US-Kern-Abhängigkeit. 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). Marketing-Kampagnen versenden **DSGVO-konform** über einen mehrstufigen Builder mit Segmenten, Auto-Exclusion, Test-Versand, Tracking (Open/Click) und Bounce-Handling.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| **Sende-Domain** [`/settings/integrations/email`] | Domain-Eingabe · **DNS-Records (DKIM/SPF/DMARC) mit Copy-Button** · Verifikations-Status-Ampel (pending/verifying/verified/failed) · 5-Min-Prüf-Indikator + Klartext bei 7-Tage-Fehlschlag · **BCC-Logging-Toggle** + angezeigte BCC-Adresse + Klartext „Mails erscheinen am Kontakt" | A6 |
|
||||
| **Kampagnen-Editor** [`/email-marketing/campaigns/new`] | Mehrstufiger Wizard: Basis (Name/Sender/Subject/Preheader) → **Inhalt** (Rich-Text + HTML-Toggle, Personalisierungs-Tokens, Bild-Upload, Pflicht-Footer Impressum+Unsubscribe, Desktop-/Mobile-Vorschau) → Empfänger (Segment-Wahl/ad-hoc-Filter, Vorschau mit **Ausschluss-Aufschlüsselung** Abgemeldet/Bounce/Suppression) → Test-Versand (max. 5 Adressen, Sample-Tokens) → Zeitpunkt (sofort/geplant/Entwurf) → **Bestätigung mit Klartext-Checkliste** (Domain verifiziert? Unsubscribe? Impressum?) — Versand bei rotem Check blockiert | **BESPOKE** |
|
||||
| Kampagnen-Liste + -Detail [`/email-marketing/campaigns`] | Liste: Name, Status, Empfänger, Versanddatum, Stats · Detail: KPI-Header (Zugestellt/Geöffnet/Geklickt/Bounces/Abmeldungen in %) · **Klick-Map** (URLs + Counts) · Pro-Empfänger-Tabelle · (A/B-Vergleich falls vorhanden) | A2/A3 + KPI |
|
||||
| Segmente [`/email-marketing/segments`] | **Filter-Baum lesbar** (verschachtelte AND/OR), Tags/Custom-Felder/Verantwortlicher/Datum/aktiver-Deal/Sprache · Live-Empfänger-Anzahl · Auto-Exclusion-Aufschlüsselung · Sample-Vorschau (max. 50) · dynamisch/statischer Snapshot | A2 + Filter-Builder |
|
||||
| Sender + Suppression [`/email-marketing/senders`] | Sender: From-Name/-Email, Domain-DKIM-Status, Default-Marker · Suppression-Liste: Adresse, Grund (Bounce/Beschwerde/manuell) | A2/A6 |
|
||||
| Templates [`/email-marketing/templates`] | Template-Liste, Vorschau, als Ausgangspunkt verwenden | A2 |
|
||||
| 🌐 **Unsubscribe-Page** [`/unsubscribe/{token}`] | Klartext, Bestätigungs-Button, optionale Grund-Auswahl, Erfolgs-Meldung · Tenant-Branding | A4-Public / **Bespoke-Public** |
|
||||
|
||||
*(Inbox-Liste, Mail-Detail, Compose, Mailbox-Connect-OAuth → v2/P23.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Sende-Domain pro Mandant: DKIM/SPF/DMARC-Records mit Copy, 5-Min-Auto-Probe, Status-Ampel, Klartext-Fehler nach 7 Tagen; ohne verifizierte Domain kein Marketing-Versand
|
||||
- [ ] BCC-Logging-Brücke: Toggle + Anzeige der BCC-Adresse; in nativen Clients geschriebene Mails erzeugen Activity am Kontakt (kein OAuth)
|
||||
- [ ] Tenant-Inbound-Adresse: eingehende Mails → Lead/Aktivität
|
||||
- [ ] Kampagnen-Builder 6-stufig mit Personalisierungs-Tokens (auch Custom-Felder), Pflicht-Footer-Auto-Injektion, Desktop-/Mobile-Vorschau
|
||||
- [ ] Pflicht-Validierungen vor Versand (verifizierte Domain, Unsubscribe-Link, Impressum, Subject, >0 Empfänger, Daily-Cap) — Block + Fix-Link bei rotem Check
|
||||
- [ ] Segmente: verschachtelter AND/OR-Filter-Baum, Live-Auflösung, Auto-Exclusion (Unsubscribe/Suppression/kein Opt-In/archiviert/keine Email), dynamisch vs. statischer Snapshot
|
||||
- [ ] Double-Opt-In-Workflow (Form-Submissions), One-Click-Unsubscribe + List-Unsubscribe-Header, Opt-In-Dokumentation je Kontakt
|
||||
- [ ] Versand über BullMQ mit Rate-Limiting, geplanter Versand (timezone-aware), Throttling
|
||||
- [ ] Open-/Click-Tracking (IP anonymisiert), Klick-Map, Stats-Aggregation; Bounce-Handling mit Suppression-Eintrag
|
||||
- [ ] SMTP-Provider-Abstraktion (Mailjet, AD-6) ohne US-Kern-Abhängigkeit
|
||||
- [ ] Datenmodell persistiert: TenantSendingDomain, TenantInboundAddress, Email, Campaign, OutboundEmail (+Open/Click), EmailTemplate/Sender, RecipientSegment, Unsubscribe, EmailSuppressionList (Domäne 8)
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
DNS-Record-Karten mit Copy-Button, Status-Ampel (Connection-Card-Stil), Toggle-Zeile mit Klartext (BCC), mehrstufiger Wizard mit Progress, Rich-Text-/HTML-Editor mit Token-Einfügen, Bild-Dropzone, Desktop-/Mobile-Vorschau-Umschalter, Pflicht-Footer-Hinweis, Segment-Picker, verschachtelter AND/OR-Filter-Builder, Empfänger-Vorschau-Liste mit Auto-Exclusion-Aufschlüsselung, Test-Versand-Eingabe (max. 5), Date-Time-Picker (timezone-aware), Pflicht-Checkliste mit grün/rot-Status + Fix-Links, Versand-Blockade-Hinweis, KPI-Kacheln + Prozent-Anzeigen, Klick-Map-Tabelle, Pro-Empfänger-Tabelle, Suppression-Liste mit Grund-Badge, öffentliche Unsubscribe-Bestätigung mit Branding, Daten-Tabelle (sortierbar/paginiert), Empty-/Loading-/Permission-Denied-States (Klartext).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (AK-P14a/b) aktualisiert:
|
||||
@@ -0,0 +1,65 @@
|
||||
# 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`
|
||||
**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).
|
||||
> 🔴 **Chat ist Real-Time-Bespoke (AD-9):** WebSocket-Messaging mit Presence/Typing/Read-Receipts/Redis-Pub-Sub, drei Channel-Typen (public/private/entity-linked). Mobile-First für Monteure. **Admin-DM-Audit** nur mit Begründungs-Pflicht + Banner.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
**Telefonie:** 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). **Team-Chat:** Real-Time-Messaging für public/private/entity-linked Channels mit @Mentions, Threads, Reactions, Pins, File-Uploads, Link-Previews, Read-Receipts und Cross-Channel-Suche. Entity-linked Channels erscheinen im Deal-/Projekt-Detail.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| **Chat-Index** [`/chat`] | Channel-Liste: Name (DM: anderer User), Avatar/Typ-Indikator (Projekt/Gruppe/DM), Snippet (max. 80 Z., Mentions hervorgehoben), Zeitstempel, **Unread-Badge**, **Mention-Marker** (separat), Pin-/Mute-Indikator, bei Projekt-Chat Stage · Filter (Typ/ungelesen/Mentions/Projekt-Status/Tag) · Suche · „Archivierte anzeigen" · **Channel-Browser (Discover)** öffentlicher Groups · „Meine Mentions"-Link · pro Eintrag Pin/Mute/Mark-as-read/Archiv | **BESPOKE** |
|
||||
| **Channel-Detail** [`/chat/:id`] | Header (Name, Typ, Member-Anzahl, Projekt-Link) · Pinned-Sektion (max. 3 inline) · Verlauf mit **Date-Bucket-Separatoren**, Nachricht = Avatar+Name+Zeit, Markdown-Body, **Reactions** (Emoji+Count), **Thread-Indikator**, Mentions, Anhänge inline (Bild-Thumb/Datei-Icon/Link-Preview), Edited-/Lösch-Marker, System-Messages, **Read-Receipt „X von Y gelesen"** · Composer (Markdown, Emoji, @-Mention-Autocomplete, Datei-Dropzone, Draft-Autosave) · **Typing-Indikator** · Per-Message-Hover-Menü (Reagieren/Thread/Pin/Mark-as-Task/Permalink/Edit/Löschen) · Channel-Info-Sektion (Members/Pinned/Files/Settings) | **BESPOKE** |
|
||||
| Thread-Detail [`/chat/:id/thread/:thread_id`] | Eltern-Nachricht + Replies in Side-Panel oder eigener Route · eigener Composer | Bespoke-Teil |
|
||||
| Pinned-Übersicht [`/chat/:id/pinned`] | Alle gepinnten Nachrichten (max. 50) je Channel | A2 |
|
||||
| Mentions-Aggregat [`/chat/mentions`] | Alle @-Mentions auf den User kanalübergreifend | A2 |
|
||||
| Cross-Channel-Suche [`/chat/search`] | Volltext-Suche über erlaubte Channels mit Treffer-Kontext | A2 |
|
||||
| Neuer Channel / DM [`/chat/new`] | Modal: Group (Name, Privacy public/private, Member-Wahl) oder DM | A5 |
|
||||
| Channel-Settings | Members verwalten, Privacy, Archivieren, verlassen | A6 |
|
||||
| Admin-Chat-Übersicht [`/admin/chat`] | Alle Channels, Cleanup-Tools · **DM-Audit mit Begründungs-Pflicht-Banner** („Diese DM wird im Audit-Modus angezeigt") · Force-Member-Edit / Force-Delete | A2/A3 |
|
||||
| **AirCall-Setup** [`/settings/integrations/telephony`] | Connect-Card (Status-Ampel connecting/active/error/revoked + Klartext) · **User-Binding-Liste** (AirCall-User ↔ HiveGrid-User mit Email-Auto-Match-Vorschlag + manuelle Korrektur) · „Verbindung testen" · Trennen mit Bestätigung | A6 |
|
||||
| Anruf-Liste + -Detail [`/calls`] | Liste: Nummer, Richtung, Dauer, **gematchter Kontakt** (mit Confidence-Hinweis bei Soft-Match), Notiz-Snippet, verpasst-Marker · Detail: **Match-Override**, Markdown-Notiz-Editor, Aufnahme-Link · Click-to-Call-Button + eingehender-Anruf-Notification | A6 + A2/A3 |
|
||||
|
||||
*(HalloPetra-Adapter-UI, Whisper-Diktat-Aufnahme → v2. Click-to-Call-Buttons leben außerdem in Kontakt-/Lead-/Deal-Detail aus P6/P7/P8.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] AirCall-Connect (OAuth, verschlüsselte Tokens, Webhook-Secret) mit Klartext-Status-Diagnose
|
||||
- [ ] User-Bindings mit Email-Auto-Match-Vorschlag + manuelle Zuordnung
|
||||
- [ ] Click-to-Call aus Kontakt-/Lead-/Deal-Detail; Mehrfach-Nummern → Auswahl-Modal; Klartext-Edge-Cases (kein Binding / keine Connection / API-Fehler / ungültige Nummer); `tel:`-Fallback ohne Connection
|
||||
- [ ] Inbound-Anrufe: Auto-Match auf Kontakt/Lead/Deal (Hard/Soft-Match mit Confidence), unbekannte Nummer → Auto-Lead, Push-Notification beim Klingeln
|
||||
- [ ] Anruf-Logging in Activity-Stream (in/out, verpasst), Markdown-Notiz-Editor nach Anruf, Recording-Anzeige, Match-Override
|
||||
- [ ] Anruf-Events als Automation-Trigger (verpasster Anruf → Rückruf-Aufgabe — P12)
|
||||
- [ ] `TelephonyProviderInterface` mit AirCall als Referenz-Adapter (HalloPetra dockt v2 an)
|
||||
- [ ] Chat-Real-Time: WebSocket, Presence, Typing, Read-Receipts, Redis-Pub/Sub, Optimistic-UI, Reconnect
|
||||
- [ ] Drei Channel-Typen: public/private Group, DM, entity-linked (Projekt/Deal) mit ProjectMember-Sync
|
||||
- [ ] @Mentions (User/Projekt/Deal/Contact/Firma) mit Autocomplete, Threads, Reactions, Pinned (max 50), File-Uploads (via Files), Link-Previews, Mark-as-Task
|
||||
- [ ] Channel-Index mit Filter/Suche/Pin/Mute/Archiv + Channel-Browser; Cross-Channel-Suche; Mentions-Aggregat
|
||||
- [ ] Entity-linked Channel erscheint im Deal-/Projekt-Detail (P8/P9)
|
||||
- [ ] Admin-Audit (`read_all_channels`): Begründungs-Pflicht je Session + DM-Audit-Banner, audit-geloggt
|
||||
- [ ] Mobile-First-Variante für Monteure (vereinfachte Chat-View, Foto-Direct-Upload, Push)
|
||||
- [ ] Datenmodell persistiert: TelephonyConnection/UserBinding/CallSession/WebhookEvent · TeamChat/Member/Message/Thread/PinnedMessage/Reaction/Read (Domäne 8)
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Channel-Listen-Einträge (Snippet, Unread-Badge, Mention-Marker, Pin-/Mute-/Typ-Indikator), Filter-Bar, Channel-Browser/Discover, Chat-Verlauf mit Date-Bucket-Separatoren, Nachrichten-Bubble (Avatar+Name+Zeit, Markdown-Renderer, Edited-/Lösch-Marker, System-Message-Stil), Reactions-Leiste (Emoji+Count), Thread-Indikator + Thread-Side-Panel, Mention-Highlight, Inline-Anhang-Renderer (Bild-Thumb/Datei-Icon/Link-Preview), Read-Receipt-Aggregat, Composer mit Markdown/Emoji-Picker/@-Mention-Autocomplete/Datei-Dropzone/Draft-Autosave, Typing-Indikator, Scroll-to-Bottom + New-Messages-Indikator, Per-Message-Hover-/Tap-Menü, Neuer-Channel-/DM-Modal, Channel-Settings-Sektion, Admin-DM-Audit-Banner mit Begründungs-Eingabe, Connection-Card (Status-Ampel + Klartext), User-Binding-Mapping-Liste mit Auto-Match-Vorschlag, Click-to-Call-Button + Nummer-Auswahl-Modal, eingehender-Anruf-Notification, Anruf-Liste (Richtung/Dauer/Match-Confidence), Match-Override-Picker, Markdown-Notiz-Editor, Recording-Player-Link, Mobile-vereinfachte-Chat-Variante 📱, Empty-/Loading-/Permission-Denied-/Offline-States (Klartext).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (AK-P15a/b) aktualisiert:
|
||||
@@ -0,0 +1,61 @@
|
||||
# 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`
|
||||
**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 **PandaDoc** (DocuSign-Adapter bleibt möglich). 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.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Deckt Termin- und Dokument-Workflows ab: bidirektionaler **Kalender-Sync** mit Google (Settings + Connection-Health), öffentliche **Buchungsseiten** (Calendly-Style, timezone-aware Slots, iFrame-Embed, Auto-Bestätigungsmail, erzeugt Lead/Activity), ein Drag-&-Drop-**Form-Builder** auf Google-Forms-Niveau (12 Feld-Typen, Conditional Logic, SHK-Templates, Post-Submit-Actions) und Multi-Signer-**Angebots-Signatur** über die Apps-Engine.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| Kalender [`/calendar`] | Monats-/Wochen-Grid mit Terminen aus Google-Sync + HiveGrid-Quellen (Booking, Plantafel, Projekt-Termine) · Quell-Marker je Termin · Konflikt-Log | BESPOKE (mittel) |
|
||||
| Kalender-Verbindungen [`/settings/integrations/calendar`] | Google-Connect-Card (Status-Ampel, verbundenes Konto-Email, letzte Sync), Kalender-Auswahl, Sync-Richtung, Disconnect mit „auch extern entfernen?"-Wahl · Re-Connect-Banner bei Fehler | A6 |
|
||||
| Kalender-Verbindungs-Detail [`/settings/integrations/calendar/:id`] | gewählte Kalender, Sync-Status, Konflikt-Liste (letzte 50, Klartext + Resolution) | A6 + A2 |
|
||||
| 🌐 Booking-Page [`/b/{tenant}/{slug}`] | Multi-Step: Slot-Picker (Kalender-Grid freie Slots, timezone-aware + Wechsler) → Intake-Form (M05) → Bestätigung + Add-to-Calendar (.ics) · Tenant-Logo · iFrame-Embed-Variante · 4 Zustände | BESPOKE-Public (höchster Polish) |
|
||||
| Buchungen-Liste [`/bookings`] | Termin, Endkunde (Name/Email), Booking-Page, Provider, Status · Tabs Anstehend/Vergangen/Storniert/Alle · Filter (Status/Provider/Page/Zeitraum) · Bulk-Cancel · CSV | A2 |
|
||||
| Buchung-Detail [`/bookings/:id`] | Termin-Daten, Provider, verknüpfter Kontakt/Lead, Form-Antworten, Kalender-Sync-Status-Badge, interne Notiz · Aktionen: held/no-show, Cancel (mit Grund + Auto-Mail), Reschedule (Slot-Picker), Provider-Re-Assign | A3 |
|
||||
| Booking-Page-Editor [`/bookings/pages/:id`, `/new`] | Grunddaten, Dauer, Puffer, Vorlauf/Vorausbuchbarkeit, Provider-Auswahl, Intake-Form-Wahl, Bestätigungsmail-Template (Markdown + Tokens), Publish-Toggle, Public-URL + Embed-Code-Generator (iFrame) | A6 + A4 |
|
||||
| Booking-Pages-Liste [`/bookings/pages`] | Title, Slug, aktive Provider, Buchungen (gesamt/30T), Status, Public-URL mit Copy | A2 |
|
||||
| Verfügbarkeit [`/availability`] | Wöchentliche Standard-Regeln (mehrere Zeitfenster/Tag), Datums-Ausnahmen (frei/Custom-Window), Timezone, Hinweis welche Booking-Pages zugreifen | A6 + A4 |
|
||||
| **Form-Builder-Canvas** [`/forms/:id/edit`] | Feld-Palette (12 Typen) · Canvas mit Drag-&-Drop-Feldliste · Feld-Konfiguration (Label, Pflicht, Validierung, Optionen) · Conditional-Logic-Editor („zeige Feld X wenn Y = Z") · Live-Vorschau · Publish-Toggle · Sharing: öffentliche URL + QR + iFrame · Post-Submit-Actions (Lead/Kontakt/Projekt/Task, Email, Webhook, Automation-Trigger) mit Field-Mapping | BESPOKE (schwerste UI nach Flow-Editor) |
|
||||
| Forms-Liste [`/forms`] | Name, Subtyp, Status (Entwurf/Publiziert/Archiviert), Submissions-Anzahl, letzte Submission · SHK-Templates geseedet | A2 |
|
||||
| 🌐 Öffentliches Formular [`/f/{tenant}/{slug}`] | Gerenderte Felder, Conditional Logic live, mCaptcha, Submit → Erfolgs-Text oder Redirect · Tenant-Logo · 4 Zustände | BESPOKE-Public |
|
||||
| Submissions [`/forms/:id/submissions`] | Tabelle der Antworten (Spalten = Felder), Filter, CSV-Export · Detail: alle Antworten in Reihenfolge, Submitter-Metadata, Action-Log mit Status (Re-Run), File-/Foto-Vorschau, PDF-Export | A2 / A3 |
|
||||
| Signatur-Wizard [im Projekt-Detail] | PDF-Upload (aus Files oder neu) → Unterzeichner (Name vorausgefüllt aus Kontakt, Email, Rolle, Reihenfolge sequenziell/parallel) → Provider (PandaDoc, Default) → Senden · Status-Tracking je Unterzeichner (entwurf/gesendet/angesehen/signiert/abgelehnt) + Erinnerung + Widerruf · Original- + Signed-PDF-Download | A5 + A6 |
|
||||
|
||||
*(Lead-Inbox/Lead-Detail → P7. Plantafel/Projekt-Detail → P9. Sende-Domain-Card → P14. Integrations-Katalog/Connection-Setup → P5. Task-Komponente → P4.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Kalender synchronisiert bidirektional mit **Google** (CalendarAdapter, Auto-Token-Refresh, Webhook-Subscriptions); HiveGrid-Termine (Booking/Projekt/Plantafel) gehen extern, externe Events kommen read-only für Verfügbarkeit (Outlook → v2)
|
||||
- [ ] Connection pro **User** (nicht pro Tenant); externe Event-Inhalte nie an andere User leaken (Booking sieht nur „belegt von X bis Y"); Last-Write-Wins-Konflikt mit Klartext-Notification
|
||||
- [ ] Öffentliche Booking-Seiten berechnen Slots timezone-aware (Verfügbarkeitsregeln, Ausnahmen, Kalender-Sync, Puffer, Vorlauf); nach Buchung: Lead **oder** Activity (Email-Match), FormSubmission, Bestätigungs-Email; iFrame-Embed; Race-Schutz beim Submit
|
||||
- [ ] Booking nur **eine** Zuteilungs-Strategie „Erster der frei ist" (Round-Robin/Provider-Wahl → v2)
|
||||
- [ ] Form-Builder mit Drag-&-Drop, **12 Feld-Typen**, **Conditional Logic**, Validierung pro Feld, SHK-Form-Templates geseedet, iFrame-Embed + QR + öffentliche URL
|
||||
- [ ] Post-Submit-Actions feuern mit Field-Mapping + ActionLog (Lead/Kontakt/Projekt/Task anlegen, Email an Submitter/Team, Webhook, Automation-Trigger, Auto-Match)
|
||||
- [ ] Angebote durchlaufen Multi-Signer-Signatur via **PandaDoc** über die Apps-Engine (M33a) mit Webhook-Verarbeitung, Status-Updates, optionalem Auto-Stage-Wechsel; Signed-PDF landet in Files
|
||||
- [ ] Signatur hängt am **`Projekt`**-Kern (`ProjektSignatureDocument`/`Signer`) — kein eigenes „Deal"-Objekt
|
||||
- [ ] Permission-Bundles: `calendar.*` (connect_own/admin), `bookings.*` (read_own/read_all/write/admin), `forms.*` (basic/builder/publisher/admin), `signature.*` (read/send/revoke/admin) — serverseitig Owner-gefiltert
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Kalender-Grid (Monat/Woche, Quell-farbige Termine), Connection-Card mit Status-Ampel + letzter-Sync-Zeit, Sync-Richtungs-Selector, Konflikt-Log-Liste mit Klartext + Resolution, Slot-Picker (Kalender mit freien/belegten Tagen + Zeitslot-Liste), Timezone-Wechsler, Multi-Step-Flow (öffentlich), Add-to-Calendar-Button (.ics), Wochen-Verfügbarkeits-Editor (mehrere Zeitfenster/Tag), Ausnahmen-Editor (Datum + frei/Custom-Window), Daten-Tabelle (sortierbar, paginiert), Filter-Bar, Bulk-Action-Toolbar, Reschedule-Slot-Picker, Status-Badge mit Klartext-Tooltip, Feld-Palette (12 Typen), Drag-&-Drop-Canvas-Feldliste, Feld-Konfigurations-Panel, Conditional-Logic-Editor (Wenn-Dann-Regeln), Live-Vorschau-Pane, Embed-Code-Generator + QR-Generator + Copy-to-Clipboard, Post-Submit-Action-Liste mit Field-Mapping-Zeilen, gerenderter Form-Player (öffentlich, mCaptcha), Action-Log-Liste mit Re-Run, PDF-Upload-Dropzone, Unterzeichner-Liste mit Reihenfolge + Rollen-Badge, Status-Tracker je Unterzeichner, PDF-Download-Buttons (Original/Signed), Empty-/Loading-/Fehler-/Permission-Denied-/Offline-States (Klartext mit Lösungs-Knopf).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (AK-P16a–d) aktualisiert:
|
||||
@@ -0,0 +1,61 @@
|
||||
# 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`
|
||||
**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.
|
||||
|
||||
> 🟡 **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.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Interner verschlüsselter HR-Hub als Mitarbeiterplattform: persönlicher MA-Bereich, Announcements mit Read-Receipt/Reaktionen/Kommentaren, Urlaubs-Approval- und Krankmeldungs-Workflow (mit Plantafel-Konflikt-Hinweisen), Lohnabrechnungen (Bulk-Upload mit Auto-Match), Upload-Erinnerungen, generische Requests via Templates, MA-Verzeichnis + Standorte, verschlüsselter Team-Passwort-Safe (Reveal audit-geloggt) und HR-Surveys.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| HR-Hub-Start [`/hr`] | Angepinnte Announcements, offene Bestätigungs-/Upload-Pflichten, eigene pendente Anträge, Team heute (Urlaub/krank, gegated), Geburtstage, letzte Lohnabrechnung-Hinweis, Quick-Links · prominente Aktionen „Krank melden / Urlaub beantragen / Antrag stellen" | Compose aus KPI + Listen |
|
||||
| Announcements + Detail [`/hr/announcements`, `/:id`] | Feed mit Pinned-Sektion + Ungelesen-Filter · Detail: Markdown, Anhänge, Reaktionen (gruppiert), 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, vorhandener Urlaub) · Krankmeldung: Start, erwartete Rückkehr, **AU-Upload (verschlüsselt)** · Admin-Monatskalender + KPI-Kacheln | A2 + A4 + A5 |
|
||||
| Lohnabrechnungen [`/hr/payslips`] | Eigene: Liste nach Periode + PDF-Viewer (Öffnen setzt gelesen) · Admin (`/admin/hr/payslips`): alle MA + Einzel-/Bulk-Upload mit **Auto-Match-Vorschau** (hart/weich/kein Match, Farb-Konfidenz) | A2 |
|
||||
| MA-Anträge [`/hr/requests`] | Template-Wahl (Spesen, Hardware, Schulung, Zeugnis, sonstiges), M05-Form, Genehmiger-Vorauswahl, Priorität, Anhänge · Detail: Kommentar-Stream (interne Notizen verborgen für Requester), Entscheidung | A2 / A3 |
|
||||
| Passwort-Safe [`/hr/password-safe`] | Vault-Liste (nur mit Access) → Eintrags-Liste (Titel, Tags — **keine Werte!**) → Eintrags-Detail: **Reveal-Button je Wert** (audit-geloggt), Copy mit 30s-Auto-Clear, Access-Verwaltung (nur Vault-Admin), Audit-Log-Anzeige | A2 / A3 + Reveal |
|
||||
| Surveys [`/hr/surveys`] | Teilnahme: Items (Text/Rating/NPS/Choice/Boolean/Datum) · Auswertung (`/results`, gegated): Häufigkeits-Charts, Durchschnitte, Textantworten · Admin-Editor mit Audience + Sichtbarkeit + Anonymität | A4 + Charts |
|
||||
| MA-Verzeichnis + MA-Detail [`/hr/directory`, `/:userId`] | Karten/Tabelle: Avatar, Name, Position, Team, Standort · Click-to-Call/Mail/Chat · Detail: Stammdaten, Notfallkontakt (nur self/HR), Inline-Edit der selbst-pflegbaren Felder, eigene Dokumente | A2 / A3 |
|
||||
| Standorte + Detail [`/hr/locations`, `/:id`] | Karten/Tabelle: Name, Adresse, Telefon, Map-Vorschau, MA-Anzahl, Beschreibung, Bild · Admin: anlegen/bearbeiten/Default/Bulk-Reassign | A2 / A3 |
|
||||
| Eigene Dokumente [`/hr/my-documents`] | Liste (Titel, Art, Datum, Gültigkeit) + Filter, Upload eigener Dokumente, File-Viewer; vom Büro hochgeladene = read-only | A2 |
|
||||
| Upload-Erinnerungen-Verwaltung [`/admin/hr/upload-reminders`] | Reminder-Liste (Titel, Cadence, Audience, pendend/überfällig) · Editor (Dokumentart, Cadence, Mandatory, Linked-Form) · Detail mit Dispatch-Liste | A2 + A6 |
|
||||
| Request-Templates [`/admin/hr/request-templates`] | Template-Liste · Editor: Name, Kind, Default-Approver-Logik, Linked-Form, Instructions, Audience · SHK-Defaults geseedet | A2 + A6 |
|
||||
| Announcement-Verwaltung [`/admin/hr/announcements`] | Alle (inkl. Draft/archiviert) · Editor: Titel, Markdown-Body, Audience-Wahl, Acknowledgement-Toggle, Reactions/Comments-Toggle, Anhänge, Pin, geplante Veröffentlichung, Ablauf | A2 + A4 |
|
||||
| Passwort-Safe-Verwaltung [`/admin/hr/password-safe`] | Tenant-weite Vault-Sicht (auch ohne Inhalts-Access), Vault-Anlage/Archiv/Delete, Access-Verwaltung, Audit-Log-Übersicht (Reveals nach User/Vault) | A2 + A6 |
|
||||
|
||||
*(Mitarbeiter-Einladung/Rollen → P2-Admin. Plantafel → P9. Dashboard-HR-Widgets → P11. Click-to-Call → P15. Chat-Start → P15.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] HR-Profile, Urlaubs-/Krank-/Payslip-/Request-Daten liegen **AES-256-GCM-verschlüsselt** vor; sensible Felder nutzen KMS-backed Envelope-Encryption (AD-8)
|
||||
- [ ] MA-Bereich vs. HR-Admin-Bereich strikt getrennt; sensible Tabellen zusätzlich zum RLS App-Permission-gegated (Standard-MA/Manager sieht „krank von X bis Y" — keine Diagnose, keine AU-Inhalte)
|
||||
- [ ] Verschlüsselter Passwort-Safe mit Audit-Trail: Reveal/Copy entschlüsselt on-demand mit Permission-Check + Audit-Eintrag; Werte nie in Liste, Copy mit 30s-Auto-Clear; DSGVO-Export
|
||||
- [ ] Mehrstufiger Urlaubs-Approval-Workflow (submitted/approved/rejected/withdrawn, Rückfrage) + Krankmeldungs-Erfassung (selbst oder durch Büro im Auftrag) → speisen Abwesenheits-Kalender (M25) und Plantafel-Konflikt-Indikatoren (M04)
|
||||
- [ ] Lohnabrechnungs-Bulk-Upload mit Dateiname-Pattern-Auto-Match (Personalnummer/Name), Match-Vorschau mit Konfidenz, Read-Tracking, Audit pro Read
|
||||
- [ ] Upload-Erinnerungen mit Cadence (once/yearly/every_n_months/on_expiry), Eskalation an Manager bei Überfälligkeit, Erfüllung via Form oder Direkt-Upload
|
||||
- [ ] Announcements mit Audience-Targeting, Acknowledgement-Pflicht + Read-Receipt, Reaktionen, Kommentare; Surveys (anonym möglich) mit Auswertung
|
||||
- [ ] Anträge (Urlaub/Krank/Requests) laufen als **M05-Form-Submissions** (Form-Renderer aus P16 wiederverwenden)
|
||||
- [ ] Permission-Layer mit Owner-/HR-Admin-Gates; Mobile-Default-Tab für Monteure (eigene Anträge, Payslips, Announcements, AU-Foto-Upload mobil)
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
KPI-Kacheln (heute krank / im Urlaub / pendente Genehmigungen / offene AU), Card-/Widget-Hub-Layout mit Tab-Navigation (nur sichtbare Tabs je Permission), Announcement-Feed mit Pinned-Sektion, Markdown-Renderer + -Editor, Reaktions-Picker (Emoji), Kommentar-Liste mit Reply, Read-Receipt-Tabelle (gegated), Acknowledgement-Button mit Counter, M05-Form-Renderer (eingebettet), Genehmiger-Aktions-Buttons (Approve/Reject/Rückfrage) mit Konflikt-Hinweis-Banner, verschlüsselter File-Upload mit Vertraulichkeits-Marker, Monatskalender-Abwesenheits-Sicht, PDF-Viewer + Download, Bulk-Upload-Dropzone mit Match-Vorschau-Tabelle (Farb-Konfidenz hart/weich/kein), Vault-Liste/Kacheln, Eintrags-Liste ohne Werte, Reveal-Button je Wert, Copy-mit-Auto-Clear, Audit-Log-Tabelle, Template-Editor mit Approver-Logik-Selector, Survey-Item-Renderer (Rating/NPS/Choice) + Auswertungs-Charts, MA-Karten/Tabelle mit Click-to-Call/Mail/Chat, Standort-Karte mit Map-Vorschau, Dispatch-Status-Liste, Empty-/Loading-/Fehler-/Permission-Denied-/Offline-States (Klartext mit Lösungs-Knopf).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (AK-P17a/b) aktualisiert:
|
||||
@@ -0,0 +1,57 @@
|
||||
# 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)
|
||||
**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 + Stripe-Positionen — **Abo-Baukasten-Mechanik**; Self-Service-UI dafür → v2). KWP-Sync-Status-Screen entfällt v1 (KWP ist erstes v2-Modul).
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Die Plattform ist aus einer getrennten Admin-Welt betreibbar: Tenant-Management (Stammdaten, Status-Wechsel, Notizen, Impersonate mit Begründung), **Abo-Zusammenstellung** je Tenant (Feature-Konnektoren + Stripe-Positionen + Trial-Verlängerung), User-Verwaltung (2FA-Reset, Session-Revoke), Feature-Flag-Verwaltung (UI zur Engine aus Phase 1), Queue-/Health-Monitoring und eine Support-Inbox, die sich aus dem Feedback-Widget (P21) speist. Alle Admin-Aktionen laufen ins `AdminAuditLog` (cross-tenant, tenant_id=null).
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| Admin-Login + 2FA [`admin.hivegrid.de/login`, `/2fa`] | Email + Passwort (NIST/HIBP, Captcha ab 3. Fehler), TOTP-Pflicht, kein Magic-Link, 8h-Session | A4 / A5 |
|
||||
| Admin-Dashboard [`/dashboard`] | **Basis-KPIs: Tenants, aktive User, MRR** + System-Health-Ampel + Queue-Status · Klick je Kachel → Drill-Down · Zeitraum-Wechsler *(Churn/ARPU/Sales-Pipeline → v2)* | KPI |
|
||||
| Tenant-Liste [`/tenants`] | Name, Slug, Status (Klartext-Farbe), Plan, MRR, User-Anzahl, letzte Aktivität, Branche/Größe · Filter + Suche + Bulk (Tag/Email) | A2 |
|
||||
| **Tenant-Detail** [`/tenants/:id`] | Stammdaten, Status-Wechsler (Reason-Pflicht), **Abo-Zusammenstellung (Feature-Konnektoren togglen + Stripe-Positionen — Abo-Baukasten!)**, Trial-Verlängerung (Datum + Reason), Notizen (Markdown, kategorisiert, gepinnt), User-/Activity-/Audit-/Feature-Flag-Sektionen, **Impersonate mit Begründungs-Pflicht** | A2 / A3 + A6 |
|
||||
| Manuelle Tenant-Anlage [`/tenants/new`] | Name, Slug (Live-Validation), Branche, Größe, Initial-Admin-Email, Initial-Module/Plan, Trial-Dauer, Demo-Daten-Häkchen, Reason-Pflicht | A4 |
|
||||
| User-Liste + Detail [`/users`, `/:id`] | Liste: Email, Name, Tenant-Memberships, 2FA-Status, letzte Aktivität, Status · Detail: Memberships mit Rolle, Sessions, letzte Logins, Ops (2FA-Reset mit Reason, Session-Revoke, Deaktivieren, Lösch im Auftrag) | A2 / A3 |
|
||||
| Subscription-Liste + Detail [`/subscriptions`, `/:id`] | Liste: Tenant, Plan, MRR, Status, Renewal, Stripe-Sync · Detail: Stripe-Customer/Sub-ID (Link), Plan + Positionen + MRR, Trial, Rechnungs-History, manuelle Override (Plan/Sonderpreis/Reason), Stripe-Sync forcieren, Refund | A2 / A3 |
|
||||
| Feature-Flags [`/feature-flags`] | Flag-Liste (Key, Status, Targeting), Filter-Editor (plan-tier), Tenant-Override mit Ablauf *(Massen-Statistik → v2)* | A2 + A6 |
|
||||
| Health + Worker-Queues [`/health`, `/health/workers`] | Service-Ampeln (Web/API/Worker/Scheduler), DB/Redis/Storage · BullMQ-Queues: Active/Waiting/Delayed/Failed je Queue, Job-Detail mit Error-Stack, Retry (Bulk/einzeln), Pause/Resume · Error-Rate Top-10 | A2 + KPI |
|
||||
| Support-Inbox + Ticket-Detail [`/support`, `/:id`] | Liste: Betreff, Tenant, Source, Status, Priorität, Zugewiesen · Detail: Konversation, Antwort (Markdown + Anhänge), interne Notiz, Status/Priority/Tag/Assignee-Wechsler, Reaktions-Templates · **speist sich aus Feedback-Widget (P21)!** | A2 / A3 |
|
||||
| Admin-Audit [`/audit`] | Cross-Tenant-`AdminAuditLog` + aggregierter Tenant-Audit-Read · Filter (Akteur/Tenant/Action-Type/Zeitraum/Target), Volltext in Summary, Detail-Drawer mit Diff, Export (CSV/JSON) · read-only | A2 + Drawer |
|
||||
| Subprozessoren + AVV [`/legal/subprocessors`, `/legal/avv`] | Subprozessor-Liste (anlegen/edit/archiv, 14-Tage-Widerspruchs-Trigger) · AVV-Versionen (PDF-Vorlage, Aktiv-ab, akzeptierende/ausstehende Tenants, Re-Akzeptanz-Trigger) | A2 + A6 |
|
||||
|
||||
*(Entfällt v1: AdminUser-/AdminRole-Verwaltung, Plattform-Lead-Inbox/Deal-Kanban, KWP-Sync-Status, Feature-Flag-Massen-Statistik — alles v2.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Plattform-Admin meldet sich auf `admin.hivegrid.de` an (Host-Routing, **Cookie-Domain-Trennung**, TOTP-Pflicht + MFA-Step-up); Admin-User haben **keinen** Tenant-Workspace und erscheinen in keiner Mitgliederliste; kein Generalschlüssel zwischen Plattform und Mandanten *(getrennte AdminUser-Identität/AdminRBAC = M038/M039 → v2; v1 = Boilerplate-User-Extension + `admin-mfa-gate`)*
|
||||
- [ ] Admin verwaltet Tenants, Subscription-Overrides und Feature-Flags aus zentraler Konsole; **Abo-Zusammenstellung** = Feature-Konnektoren togglen + Stripe-Positionen (Abo-Baukasten-Mechanik)
|
||||
- [ ] Admin-Dashboard zeigt Boilerplate-KPIs (Tenants/User/MRR) + System-Health + Queue-Status *(Churn/ARPU/Health-Kacheln → v2)*
|
||||
- [ ] Admin überwacht BullMQ-Queues (Retry/Pause/Resume, Job-Detail mit Error-Stack) und bearbeitet eine Support-Inbox
|
||||
- [ ] `AdminAuditLog` protokolliert plattformweite Aktionen (tenant_id=null) über die Audit-Hash-Kette; sensitive Aktionen (Status-Wechsel, Impersonate, Subscription-Override) mit **Reason-Pflicht** + Klartext-Bestätigung
|
||||
- [ ] Impersonate generiert temporäre Tenant-User-Session (max. 30 Min) mit Klartext-Banner im Tenant + voller Reason-Spur
|
||||
- [ ] Eigene getrennte Admin-Shell (Sidebar: Dashboard/Tenants/Users/Subscriptions/Feature-Flags/Health/Audit/Support/Legal/Settings) — kein Reuse der App-Sidebar
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Eigene Admin-Sidebar + -Topbar (getrennt von A1), KPI-Kacheln mit Drill-Down + Zeitraum-Wechsler, System-Health-Ampel, Daten-Tabelle (sortierbar, paginiert, Spalten-Konfig), Filter-Bar, Bulk-Action-Toolbar, Status-Wechsler mit Reason-Pflicht-Modal, **Abo-Baukasten-Panel** (Feature-Konnektor-Toggles + Stripe-Positionsliste mit Preisen), Trial-Verlängerungs-Datum-Picker, Markdown-Notizen-Editor mit Pin + Kategorie, Impersonate-Button mit Begründungs-Modal, Stripe-Link-Badge, manuelle-Override-Formular, Queue-Status-Tabelle mit Retry/Pause/Resume, Job-Detail-Drawer mit Error-Stack, Feature-Flag-Liste + Targeting-Filter-Editor + Tenant-Override-mit-Ablauf, Support-Konversations-Ansicht + Markdown-Reply + interne-Notiz-Toggle + Reaktions-Templates, Audit-Tabelle mit Diff-Drawer + Export, Subprozessor-Tabelle + AVV-Versions-Liste mit PDF-Upload, Bestätigungs-Dialoge (Confirm-Phrase für destruktive Aktionen), Empty-/Loading-/Fehler-/Permission-Denied-States (Klartext mit Lösungs-Knopf).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (AK-P19) aktualisiert:
|
||||
@@ -0,0 +1,56 @@
|
||||
# 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`
|
||||
**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.
|
||||
> - **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).
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Ein neuer Betrieb kommt vom Self-Service-Signup per Auto-SHK-Provisionierung ins Produkt, läuft auf Stripe-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.
|
||||
|
||||
## 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`] | **Stripe-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) |
|
||||
|
||||
*(Signup-Formular → P2-Auth. Mitarbeiter-Einladung → P2/P20-Seeds. Kein Onboarding-Setup-Wizard v1. Stripe-Checkout läuft extern über Marketing-Site.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Billing über Stripe als **Abo-Baukasten**: Basis-Preis pro Nutzer + Feature-Module als daten-getriebene Positionen (keine Seat-Typen — M154-Recut); konkrete Preise geparkt (AD-15)
|
||||
- [ ] 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
|
||||
- [ ] 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`)*
|
||||
|
||||
## 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, Stripe-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).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (AK-P20) aktualisiert:
|
||||
@@ -0,0 +1,58 @@
|
||||
# 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`
|
||||
**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.
|
||||
> - **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.
|
||||
|
||||
## 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-Löschung** [`/admin/privacy/deletion`, `/:requestId`] | Multi-Step: Erklärung (30-Tage-Grace, Read-Only, Hard-Delete) → Export-Angebot → Stripe-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 |
|
||||
| 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 |
|
||||
|
||||
*(Kein DSGVO-Auskunfts-Wizard v1 — Playbook nutzt Cmd+K-Suche + Kontakt-Detail-Activity-Stream + CSV-Export + Task aus P6/P4/P11. Admin-Support-Inbox + Subprozessor-/AVV-Verwaltung → P19. Privacy-Manifest-Inhalt = Marketing-Site.)*
|
||||
|
||||
## 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
|
||||
- [ ] **Tenant-Löschung** führt Crypto-Shredding (Per-Tenant-DEK), Stripe-Cancel und Storage/Cache/Index-Bereinigung durch (AD-8); 30-Tage-Grace mit Read-Only + Abbruch-Möglichkeit; **Slug als Confirm-Phrase**; Stripe-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)
|
||||
- [ ] **In-App-Feedback-Widget** (Bug/Feature/Frage, Screenshot, Rate-Limit) live → speist Admin-Support-Inbox (P19, generische Quelle)
|
||||
- [ ] **Minimal-FAQ**-Seite existiert (statisch, kein Help-Center-Ausbau)
|
||||
- [ ] Monteure arbeiten mobil über die **PWA/responsive Web-App** (mobile-first + P9-Offline) — alle neuen Screens mobil tauglich; PWA-Installierbarkeit/Web-Push → v2; kein nativer Client (AD-17)
|
||||
- [ ] Permissions: `privacy.user_export.self` (implizit jeder User), `privacy.tenant_export` / `privacy.tenant_deletion` / `privacy.avv.*` / `privacy.subprocessors.read` (über `tenant.admin`)
|
||||
|
||||
## 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.
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (AK-P21) aktualisiert:
|
||||
@@ -0,0 +1,52 @@
|
||||
# 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`
|
||||
**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).
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Externe Systeme lesen die HiveGrid-Hauptentitäten (Kontakte, Firmen, Deals, Projekte, Tasks, Leads) über eine **versionierte REST-API** (`/api/v1/…`, cursor-paginiert) und tauschen Events über **signierte Webhooks** aus — eingehend (Lead-Ingestion mit Auto-Match) wie ausgehend (HMAC-SHA256, Idempotenz, Retry/Backoff, Auto-Disable). Auth läuft über Tenant-API-Keys mit Scopes und Rate-Limit; die ausgehende Webhook-Action dockt an die v1-Automation (`external_event`-Trigger) an.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| API-Key-Verwaltung [`/admin/api-keys`] | Key-Liste (Name, Scopes, letzte Nutzung, Status, Tarif-Gate) · Key erstellen (Scope-Auswahl, Secret einmal sichtbar) · Rotieren/Widerrufen | A2 + A5 (Erweiterung v1) |
|
||||
| Incoming-Webhook-Verwaltung [`/admin/api-keys/incoming-webhooks`] | Slug-Endpoints (`/webhooks/incoming/{tenant}/{slug}`), Auth-Modus (API-Key/HMAC/URL-Token), Payload-Mapping, Auto-Match-Regeln · Ingestion-Log (Eingang, Match-Ergebnis, Fehler) | A2 + A3 |
|
||||
| Outgoing-Subscription-Liste [`/admin/webhooks`] | Ziel-URL, abonnierte Event-Typen, Status (aktiv/auto-disabled), letzte Zustellung, Fehlerzähler | A2 |
|
||||
| Outgoing-Subscription-Detail [`/admin/webhooks/:id`] | Secret (einmal sichtbar), Delivery-Stats, Delivery-Log mit Retry-Status, Replay/Test-senden, Aktivieren/Pausieren | A3 |
|
||||
| API-Request-Logs + Usage [`/admin/api-keys/usage`] | Request-Log (Endpoint, Key, Status, Latenz, Rate-Limit-Treffer) · Usage-Aggregat (Calls/h pro Key + Tenant, Quota-Auslastung) | A2 |
|
||||
| OpenAPI/Swagger-UI [`/api/v1/openapi` · Swagger] | Auto-generierte OpenAPI-3.1-Doku + interaktiver Try-it-out (entwickler-gerichtet, evtl. eingebettete Drittanbieter-UI) | A6/extern |
|
||||
|
||||
*(Die eigentlichen REST-Endpoints `/api/v1/contacts|companies|deals|projects|tasks|leads` sind serverseitig — kein eigener Screen außer Swagger-UI.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Read-Endpoints für contacts/companies/deals/projects/tasks/leads — cursor-paginiert, Filter/Sort/Sparse-Fieldsets/Embed (Tiefe 1)
|
||||
- [ ] `read_only`-Scope blendet sensible Felder aus (Feld weglassen, nicht 403)
|
||||
- [ ] API-Key-Auth mit Scopes + Rate-Limit (1k/h pro Key, 10k/h pro Tenant), `X-RateLimit-*`-Header + Klartext-429
|
||||
- [ ] Eingehende Lead-Webhooks legen Leads an (API-Key/HMAC/URL-Token + Payload-Mapping + Auto-Match)
|
||||
- [ ] Ausgehende WebhookSubscriptions: HMAC-SHA256-Signatur, Idempotenz-ID, Retry mit exp. Backoff (max 5), Auto-Disable nach 10 Fehlern
|
||||
- [ ] OpenAPI-3.1 auto-generiert (`/api/v1/openapi.json`) + Swagger-UI
|
||||
- [ ] Tarif-Gates (M027): API-Keys/Webhooks nur in passendem Abo verfügbar
|
||||
- [ ] Writes durch v1-Frozen/past_due-Middleware geblockt (402); RLS via `app.tenant_id`
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Daten-Tabelle (sortierbar, paginiert) für Keys/Webhooks/Logs, „Secret/Token einmal sichtbar"-Reveal mit Copy-Button + Warnhinweis, Scope-Multi-Select (Checkbox-Gruppe), Status-Badges (aktiv/pausiert/auto-disabled), Tarif-Gate-Hinweis/Upgrade-Prompt, Payload-Mapping-Editor (Feld-zu-Feld-Zuordnung), Auth-Modus-Auswahl (API-Key/HMAC/URL-Token), Delivery-Log-Timeline mit Retry-Status-Marker, Replay-/Test-senden-Button, Rate-Limit-/Quota-Auslastungs-Anzeige (Balken/Zahl), Code-Snippet-Block (HMAC-Verifizierungs-Beispiel), Empty-/Loading-/Permission-Denied-States (Klartext), 429-/Fehler-Hinweis-Banner.
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (VR-P22a/b) aktualisiert:
|
||||
@@ -0,0 +1,48 @@
|
||||
# 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-Deal-Project-FKs) · `_bmad-output/specs/M09-email-inbox.md` (OAuth-Sync/Inbox/Threading-Teile)
|
||||
**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.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Gmail- und Outlook-Postfächer der User werden **bidirektional ins CRM gespiegelt**: per OAuth verbunden, per Push-Sync (Gmail Pub/Sub-Watch, Microsoft Graph-Subscription) aktuell gehalten, **auto-gematcht** auf Contact/Lead/Deal und im **Activity-Stream** sichtbar. User lesen Threads in einer Inbox-Liste mit sicherem HTML-Render und antworten/leiten weiter über die eigene Mailbox. Permission-getrennt über `email.read_own` vs. `email.read_all`.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| Mailbox-Connect-Settings [`/settings/integrations/email`] | Postfach verbinden (Gmail/Microsoft OAuth), Sync-Status (Initial-Sync-Progress, letzter Sync, Fehler), Reconnect/Token-Refresh, Trennen/Revoke | A6 |
|
||||
| Inbox-Liste [`/emails`] | Mail-Liste (Absender, Betreff, Snippet, Datum, Verknüpfung-Badge, gelesen/ungelesen) · Filter (Mailbox/verknüpft/unverknüpft/Datum) · Volltext-Suche · Bulk-Actions | A2 |
|
||||
| Mail-Detail [`/emails/:id`] | Thread-Ansicht (chronologisch), sicherer HTML-Render (externe Bilder blockiert/optional laden), Anhänge (→ Files), Verknüpfungs-Editor (Contact/Lead/Deal/Project, manueller Override), Reply/Forward | A3 |
|
||||
| Outbound-Compose [`/emails/new`] | Neue Mail / Reply / Forward über User-Mailbox, Empfänger, Betreff, Body, Anhänge, Vorlagen-Auswahl | A5/A3 |
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] OAuth-Connect Gmail (Pub/Sub-Watch) + Microsoft (Graph-Subscription) mit 3-Tage-Renewal-Worker, Token-Refresh + Revoke
|
||||
- [ ] Push-Sync (kein Primär-Polling); Initial-Sync 90 Tage, resumebar mit Progress-Anzeige
|
||||
- [ ] Auto-Match: From-Adresse → Contact/Lead, Subject-Pattern (`[Deal #123]`), 1-offener-Deal-Heuristik; manueller Override sticht
|
||||
- [ ] Inbox-Liste mit Filter/Suche/Bulk + Detail mit Thread + sicherem HTML-Render (CSP, externe Bilder blockiert)
|
||||
- [ ] Reply/Forward via User-Mailbox (Provider-Quotas beachten) + Vorlagen (M098)
|
||||
- [ ] Anhänge landen in v1-Files; Mails erscheinen im Activity-Stream
|
||||
- [ ] `email.read_own` vs. `email.read_all` filtern Liste + Activity-Stream
|
||||
- [ ] OAuth-Tokens per DEK verschlüsselt (Token-Encryption)
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Provider-Connect-Buttons (Gmail/Microsoft mit Logo), Sync-Status-Panel (Progress-Bar Initial-Sync, letzter-Sync-Zeitstempel, Fehler-Banner mit Reconnect), Mail-Daten-Tabelle (gelesen/ungelesen-Indikator, Verknüpfungs-Badge), Filter-Bar + Volltext-Suchfeld, Bulk-Action-Toolbar, Thread-Ansicht (kollabierbare Nachrichten), sicherer HTML-Render-Container mit „externe Bilder laden"-Hinweis, Anhang-Chips/Liste, Verknüpfungs-Editor (Entity-Picker mit Auto-Match-Vorschlag + Override), Reply/Forward-Composer (Empfänger-Felder, Body-Editor, Vorlagen-Dropdown, Anhang-Upload), Permission-gefilterte Empty-/Loading-/Permission-Denied-States (Klartext), Re-Auth-/Token-abgelaufen-Hinweis.
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (VA-P23) aktualisiert:
|
||||
@@ -0,0 +1,48 @@
|
||||
# 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`
|
||||
**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-Stripe-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).
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Tenants buchen und wechseln Pläne **self-service** über den Web-Checkout (Trial ohne Vertriebs-Freigabe, Add-On-Käufe) und durchlaufen nach dem Signup einen **resumebaren, branchen-getriebenen Onboarding-Wizard** (State-Machine), der das SHK-Branchen-Template deklarativ aus YAML seedet (Pipelines/Rollen/Custom-Felder/Forms/Demo/Checkliste). Eine Erste-Schritte-Checkliste (Detection-Rules) führt weiter; Demo-Daten lassen sich gebündelt löschen.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| Onboarding-Wizard [`/onboarding/setup/step/:n`] | 10-Step-Vollbild-Flow: Branchen-Wahl, Pipelines/Rollen/Felder, Forms, Demo-Daten, Team-Einladung etc. · Step-Validierung · Rückwärts-Block nach irreversiblen Actions · resumebar | Vollbild-Flow |
|
||||
| Erste-Schritte-Checkliste [`/onboarding/checklist`] | Checklisten-Widget (Detection-Rules: erledigt/offen) + Detail-Sicht mit Deep-Links zu den Aufgaben | A2/Widget |
|
||||
| Demo-Daten-Verwaltung [`/admin/onboarding/demo-data`] | Übersicht geseedete Demo-Daten + Bulk-Löschung (Bestätigung) | A6 |
|
||||
| Self-Service-Plan-Wechsel [`/admin/subscription`] | Aktueller Plan, verfügbare Pläne (Web-Checkout), Plan-Wechsel/Upgrade/Downgrade, Zahlungsmethoden-Pflicht, Checkout-Return | A6 + Web-Checkout |
|
||||
| Add-On-Kauf-Flächen [`/admin/subscription` · `/admin/usage`] | Add-On-Katalog (z. B. AI-Credits, Seats), Kauf via Web-Checkout, Usage-/Quota-Anzeige | A6 |
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Self-Service-Trial ohne Vertriebs-Freigabe (`requires_manual_activation=false`) mit Zahlungsmethoden-Pflicht
|
||||
- [ ] Plan-Wechsel + Add-On-Käufe über Web-Checkout-Flow (PWA-only → kein App-Store, keine Store-Billing-Auflage)
|
||||
- [ ] Onboarding-Wizard resumebar nach Signup, Step-Validierung, Block der Rückwärts-Navigation nach irreversiblen Actions
|
||||
- [ ] SHK-Branchen-Template (Pipelines/Rollen/Custom-Felder/Forms/Demo/Checkliste) deklarativ aus YAML geseedet; weitere Branchen „coming soon"
|
||||
- [ ] Erste-Schritte-Checkliste mit Detection-Rules + Demo-Daten-Bulk-Löschung
|
||||
- [ ] KI-Walkthrough-Coach-Andockpunkt (wird von P25 rückwirkend eingehängt — kein harter Forward-Dep)
|
||||
- [ ] Wiederverwendung v1: Stripe-Checkout + Webhook-Handler + StripeWebhookLog + SubscriptionFeature/ProductFeature (Feature-Gate) + Read-Only-Middleware + TenantUserInvitation
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Step-Progress-Indikator (10 Steps, Vollbild), Step-Inhalts-Container mit Validierungs-Feedback, „Zurück gesperrt"-Hinweis nach irreversiblen Actions, Branchen-Auswahl-Karten (SHK aktiv, andere „coming soon"-disabled), Plan-Vergleichs-Karten/Tabelle (Features pro Plan, aktueller Plan markiert), Web-Checkout-Trigger-Button + Checkout-Return-Status, Zahlungsmethoden-Pflicht-Hinweis, Add-On-Katalog-Karten mit Preis + Kauf-Button, Usage-/Quota-Auslastungs-Anzeige (Balken), Erste-Schritte-Checklisten-Widget (abhakbare Items mit Deep-Link), Demo-Daten-Lösch-Bestätigung (mit Folgen-Hinweis), Resume-Banner („Onboarding fortsetzen"), KI-Coach-Slot/Platzhalter (von P25 befüllt), Empty-/Loading-/Permission-Denied-States (Klartext).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (VA-P24a/b) aktualisiert:
|
||||
@@ -0,0 +1,50 @@
|
||||
# Designer-Brief · P25 — KI-Tiefe: HiveMind/RAG (v2-P4)
|
||||
|
||||
> ⛔ **ABGELÖST (KI→MCP-Pivot, [[AD-26]], 2026-06-22):** HiveMind/RAG/Whisper-UI entfällt (zurückgestellt). Ersetzt durch **[[VD-MCP]]** (MCP-Verbindungen/Settings). Brief unten = historisch.
|
||||
|
||||
**Phase:** 25/34 (v2-P4) · **Modul:** M18 (M087 + Whisper-EU + pgvector-Hybrid-Suche + zweiter EU-Provider) · **Owner-Dev:** Raffael (VR-P25) · **Designer:** David · **Slot:** v2-W1→W2 (Start 18./19.07.)
|
||||
**Quellen:** `ROADMAP-V2.md` §v2-P4 (Screens/Features = Hauptquelle) · `ROADMAP.md` §Phase 25 · `_bmad-output/specs/M18-ki-layer.md` (RAG/HiveMind/Whisper-Teile)
|
||||
**Subframe:** Pflicht je Route. Archetypen aus D0 (A2 Liste, A3 Detail, A5 Modal, A6 Settings, Chat-Panel).
|
||||
|
||||
> 🔴 **DSGVO-Hard-Constraint:** **Nur EU-Provider** (kein OpenAI/Anthropic/Gemini), AVV mit allen Providern. Aufbau auf dem **v1-LLM-Gateway** (Multi-Provider-Abstraktion) — **NICHT** neu bauen. Der **HiveMind-Agent** läuft erst nach etabliertem Werkzeug-Modus (Reifegrad-Gate) autonom und immer mit **Action-Boundary**: keine schreibenden Aktionen ohne explizite Bestätigung. Hilfe-Korpus für RAG kommt aus v2-P9 (Help-Center) per Retro-Integration.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Aus dem v1-LLM-Gateway wird semantische Tiefe: eine **Embedding-Pipeline** (pgvector, permission-vorgefiltert) speist **RAG** für Programm-Hilfe, Lead-Zusammenfassungen und eine **hybride globale Suche** (Volltext + Vektor, RRF). **Whisper-EU** transkribiert Voice-Notes async. Der **HiveMind-Agent** liefert proaktive Vorschläge (Insights) mit Bestätigungs-Workflow, Audit-Trail und Scheduled-Actions. Multi-Provider-Failover (Mistral→Scaleway→AlephAlpha) + Promptfoo-Eval in CI.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| KI-Chat/Assistent-Panel [überall einblendbar / `/assistant`] | Chat mit RAG-Antworten (Quellen-Zitate), Conversation-History, Use-Case-Kontext (aktuelle UI-Sicht), Graceful-Degradation-Hinweis bei Provider-Down (Fallback Help-Volltext) | Chat-Panel |
|
||||
| HiveMind-Insight-Anzeige [Dashboard-Widget / Detail] | Proaktive Vorschläge (Stuck-Deals/Stuck-Projects), Bestätigungs-Workflow (annehmen/verwerfen) mit Action-Boundary, Begründung/Quelle | A2/Widget |
|
||||
| Custom-Tool-Editor + Scheduled-Actions [`/admin/ai/tools`] | Tenant-definierte HiveMind-Tools anlegen/bearbeiten, Cron-basierte Scheduled-Actions, Action-Log (Audit-Trail autonomer Actions) | A2 + A3 |
|
||||
| AI-Usage-Dashboard [`/admin/usage/ai`] | Token-/Credit-Verbrauch (AiCredits/AiTokenUsage), pro Use-Case/Provider, Quota/Failover-Status | A6 |
|
||||
| Whisper-Aufnahme/Transkription [in Abnahme/Notes eingebettet] | Voice-Note aufnehmen/hochladen, async Transkriptions-Status, Resultat + Klartext-Fehlerpfad | A5/eingebettet |
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Embedding-Pipeline → `TenantEmbedding` (pgvector, HNSW/IVFFlat), Re-Embed per Hash-Diff, Permission-Pre-Filter vor Vector-Search
|
||||
- [ ] RAG bedient Programm-Hilfe (Help-Embeddings aus P9), Lead-Zusammenfassung, hybride globale Suche (Volltext+Vektor, RRF); Graceful Degradation bei Provider-Down
|
||||
- [ ] Whisper-EU (Scaleway-GPU) transkribiert Voice-Notes async mit Klartext-Fehlerpfad
|
||||
- [ ] HiveMind-Agent: proaktive Vorschläge mit Action-Boundary (keine Writes ohne Bestätigung), Audit-Trail, Scheduled-Actions, Screen-Context-Bewusstsein
|
||||
- [ ] Multi-Provider-Failover (Mistral→Scaleway→AlephAlpha) + Promptfoo-Eval in CI (scheitert bei erfolgreicher Injection)
|
||||
- [ ] Permissions: `ai.use_chat` / `ai.use_transcription` / `ai.basic` gaten Chat/Whisper/Read
|
||||
- [ ] Wiederverwendung v1: LLM-Gateway, `RetrievalProvider`-Interface + Outbox-Index-Events, AiCredits/AiTokenUsage, Activity-Stream/Custom-Felder/Forms als RAG-Quellen
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Chat-Panel (Nachrichten-Stream, Eingabefeld, Streaming-Antwort), Quellen-Zitat-Chips/Aufklapp (RAG-Belege), Conversation-History-Liste, Insight-Karten mit Annehmen/Verwerfen + Begründung, Action-Boundary-Bestätigungs-Dialog (zeigt geplante Action vor Ausführung), Audit-Trail-Timeline (autonome Actions), Custom-Tool-Editor (Tool-Definition-Felder), Scheduled-Action-Konfig (Cron + Tool-Auswahl), Voice-Recorder-Control (Aufnahme/Stop/Upload) + Transkriptions-Status-Indikator, Usage-/Quota-Charts pro Provider/Use-Case, Provider-Down-/Degradation-Banner (Klartext-Fallback-Hinweis), Permission-Denied-/Empty-/Loading-States (Klartext), DSGVO-/EU-Provider-Hinweis (Transparenz).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (VR-P25) aktualisiert:
|
||||
@@ -0,0 +1,55 @@
|
||||
# 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`
|
||||
**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.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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 |
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Eigene `PortalUser`-Klasse strikt getrennt von TenantUser (eigene Cookies/Routes, keine Permission-Vermischung); Magic-Link primär
|
||||
- [ ] Endkunde sieht nur eigene Projekte / konfigurierte Stages / freigegebene Dokumente; fehlender Zugang → 404 (keine Existenz-Offenlegung)
|
||||
- [ ] Upload (mobile-Kamera, Multi-File, Limits) → Files + Activity + Projektleiter-Notification; Reklamation melden
|
||||
- [ ] Auto-Status-Mails bei `project.stage_changed` (Debounce; Bedingungen: sichtbare Stage / aktiver Access / Pref / nicht frozen)
|
||||
- [ ] 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
|
||||
- [ ] 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).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (VA-P26a/b) aktualisiert:
|
||||
@@ -0,0 +1,52 @@
|
||||
# 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)
|
||||
**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.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Die mobile-first-PWA aus v1 wird zur vollwertigen installierbaren App für den Baustellen-Einsatz. Pre-Cache beim Login (Projekte/Tasks/Kontakte/Checklisten/Acceptance-Templates) über Service-Worker + IndexedDB ermöglicht Offline-Lesen und eine Offline-Write-Queue (Foto/Note/Task-Status/Checklist/Acceptance/Chat). Bei Reconnect drainiert die Queue idempotent (lokale UUID als Key); Append-only ist konfliktfrei, Status-Updates laufen LWW mit Konflikt-Resolution. Installierbarkeit, Web-Push und Force-Update kommen über reine Web-Standards — kein Store dazwischen.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| Mobile-Login + Setup [`/login` mobil] | Email/Pwd + Magic-Link, 2FA bleibt, offline-Permissions-Snapshot, Erst-Setup nach Install | A1/Setup |
|
||||
| Mobile-Navigation (Baustelle/Büro) [`/m`] | Touch-optimierte Haupt-Navigation, Modus-Umschaltung Baustelle/Büro, Deeplinks | A-Shell |
|
||||
| Sync-Queue + Konflikt-Resolution [`/m/sync`] | Liste ausstehender Offline-Writes (Foto/Note/Status/Checklist/Acceptance/Chat) mit Status, Konflikt-Resolution bei LWW-Status-Updates | A2 + Konflikt-Ansicht |
|
||||
| Mobile-Settings [`/m/settings`] | Pre-Cache-Steuerung, Storage-Budget/Belegung, registrierte Geräte, Account-Löschung erreichbar | A6 |
|
||||
| Web-Push-Pre-Prompt [Modal] | Erklärungs-Pre-Prompt vor dem nativen Berechtigungs-Dialog (VAPID) | A5 |
|
||||
| Force-Update-Modal [Modal] | Hinweis auf neue Service-Worker-Version, Reload-Aufforderung | A5 |
|
||||
| Install-Hinweis (A2HS) [Banner/Modal] | Add-to-Homescreen-Hinweis, plattformspezifisch (iOS-Safari-Standalone vs. Android) | Banner |
|
||||
|
||||
*(Die fachlichen Screens — Projekte/Tasks/Abnahme/Chat/Foto — existieren aus v1; P27 macht sie offline-tauglich und touch-optimiert, baut sie nicht neu.)*
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Offline-Pflicht: Pre-Cache beim Login (Projekte/Tasks/Kontakte/Checklisten/Acceptance-Templates) über Service-Worker + IndexedDB
|
||||
- [ ] Offline-Write-Queue (Foto/Note/Task-Status/Checklist/Acceptance/Chat); Sync-on-Reconnect drainiert idempotent (lokale UUID als Key)
|
||||
- [ ] Append-only konfliktfrei; Status-Updates LWW mit Konflikt-Resolution
|
||||
- [ ] Installierbar: Web-App-Manifest + Add-to-Homescreen + Standalone-Display
|
||||
- [ ] Web-Push (VAPID) aktiviert den in v1 ruhenden notify()-Push-Kanal über NotificationDevice
|
||||
- [ ] Kamera/Foto via Web-APIs mit lokalem Resize; 2FA bleibt; Account-Löschung erreichbar
|
||||
- [ ] Force-Update via Service-Worker-Versionierung; Deeplinks
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Touch-optimierte Navigations-Shell (Bottom-Nav/Drawer), Modus-Umschalter (Baustelle/Büro), Sync-Status-Indikator (online/offline/pending count), Queue-Liste mit Pro-Eintrag-Status, Konflikt-Resolution-Ansicht (lokal vs. Server), Pre-Cache-Fortschritt/Storage-Belegung-Anzeige, Web-Push-Pre-Prompt-Dialog, A2HS-Install-Banner (plattformabhängig), Force-Update-Modal, Foto-Aufnahme-/Resize-Komponente, Offline-Banner, Empty-/Loading-/Permission-Denied-States (Klartext).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (VA-P27a/b) aktualisiert:
|
||||
@@ -0,0 +1,51 @@
|
||||
# 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)
|
||||
**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.
|
||||
|
||||
## 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.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| AdminUser-Verwaltung [`admin.hivegrid.de/admin-users`] | Liste AdminUser, Status, Rolle, letzte Aktivität; Anlegen durch super_admin | A2 |
|
||||
| AdminUser-Detail [`/admin-users/:id`] | Rollen-Zuweisung, Sessions, Audit-Trail, Self-Permission-Schutz | A3 |
|
||||
| AdminRole-Editor [`/admin-users/roles`] | Permission-Bundles je Rolle, Default-Rollen, Bundle-Zuweisung | A6 |
|
||||
| Admin-Security-Settings [`/settings/security`] | Aktive Sessions + individueller Revoke, 2FA-Pflicht, 8h-Session-Policy | A6 |
|
||||
| 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 |
|
||||
| Cross-Tenant-Audit-View [`/audit`] | AdminAuditLog über alle Tenants, Reason-Pflicht-Einträge, Impersonate-Records, Filter | A2 |
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Eigene `AdminUser`-Klasse hart getrennt (eigene Cookies SameSite=Strict, kein Cross-Routing, **kein BYPASSRLS**)
|
||||
- [ ] AdminRBAC mit eigenen Bundles + Default-Rollen (super_admin/support/sales/engineering/viewer), 2FA-Pflicht, 8h-Session, Self-Permission-Schutz
|
||||
- [ ] 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
|
||||
|
||||
## 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).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (VR-P28a / VA-P28b) aktualisiert:
|
||||
@@ -0,0 +1,49 @@
|
||||
# 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`
|
||||
**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.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Öffentliches, file-basiertes Help-Center mit SEO-Routen (`/help/{lang}/{category}/{slug}`, ohne Auth, vor der Auth-Middleware), Volltext-Suche und Build-Time-Index (Build-Fail bei kaputten Referenzen). Aus jeder App-Route führt ein Hilfe-Icon per Deep-Link zum passenden Artikel (Fallback Help-Home). Ein überall erreichbares Feedback-Widget („Problem melden") erzeugt `Feedback`-Einträge mit Auto-Kontext (tenant/user/route/browser/app-version) und optionalem Screenshot; die Plattform-Admin-Seite verwaltet Feedback als Liste + Detail mit Status-Lifecycle/Assignee/Notes/Attachments und Audit.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| Help-Home [`/help/{lang}/`] | Hero, Such-Eingang, Kategorien-Übersicht, öffentlich (kein Tenant-Context) | A-Public |
|
||||
| Kategorie-Seite [`/help/{lang}/{category}/`] | Liste der Artikel einer Kategorie, Kategorie-Metadaten | A2-Public |
|
||||
| Artikel-Detail [`/help/{lang}/{category}/{slug}`] | Markdown-Inhalt, TOC, verwandte Artikel, Vote (hilfreich?), SEO-Meta/Canonical | A3-Public |
|
||||
| Such-Ergebnisse [`/help/{lang}/search?q=`] | Volltext-Treffer mit Snippets, Kategorie-Zuordnung | A2-Public |
|
||||
| Feedback-Widget [Modal, überall] | „Problem melden"-Trigger (global erreichbar), Freitext, Screenshot-One-Click-Anhang, Erfolgs-Hinweis | A5 |
|
||||
| Admin-Feedback-Liste [`admin.hivegrid.de/support`] | Feedback-Liste mit Status, Assignee, Quelle, Datum, Filter | A2 |
|
||||
| Admin-Feedback-Detail [`admin.hivegrid.de/support/:ticketId`] | Status-Lifecycle, Assignee, interne Notes, Auto-Kontext (route/browser/app-version), Attachments, Audit | A3 |
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Markdown mit Frontmatter, Build-Time-Index (Volltext + Kategorien + Sitemap), Build-Fail bei kaputten Referenzen/`related_slug`
|
||||
- [ ] Öffentliche Routen `/help/{lang}/{category}/{slug}` ohne Auth (vor Auth-Middleware), SEO-Defaults (title/description/canonical), Suche
|
||||
- [ ] Deep-Link Route→Artikel (Hilfe-Icon pro App-Route, Fallback Help-Home)
|
||||
- [ ] Feedback-Widget überall → `Feedback` mit Auto-Kontext (tenant/user/route/browser/app-version), Screenshot-Option, Rate-Limit 10/h
|
||||
- [ ] Plattform-Admin: Feedback-Liste + Detail (Status-Lifecycle/Assignee/Notes/Attachments) mit Audit
|
||||
- [ ] Help-Artikel als RAG-Korpus an P25/v2-P4 registrierbar (Embedding-Quelle)
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Such-Eingabe mit Auto-Suggest, Kategorie-Kacheln/-Liste, Artikel-Renderer (Markdown) mit Inhaltsverzeichnis, „War das hilfreich?"-Vote, Breadcrumb, Hilfe-Icon (in-App, deep-link-fähig), Feedback-Trigger (Button/FAB, global), Feedback-Formular (Freitext + Screenshot-One-Click), Erfolgs-/Rate-Limit-Hinweis (Klartext), Admin-Daten-Tabelle (Status-Filter), Status-Lifecycle-Badge, Assignee-Auswahl, Notiz-Liste, Attachment-Vorschau, Empty-/Loading-/Permission-Denied-States (Klartext).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (VA-P29) aktualisiert:
|
||||
@@ -0,0 +1,48 @@
|
||||
# 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`
|
||||
**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.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Querschnitts-Komfort über die ganze App: User passen ihr Dashboard an (Drag/Resize, permission-gegateter Widget-Catalog), bohren pro Kachel in Drilldowns, exportieren als CSV/Report und schalten Realtime mit Opt-Out. Notifications werden gebündelt (gleicher event_type_group in 5-Min-Window → 1 Push/Mail mit count), respektieren Quiet-Hours (queued, Urgent-Override) und pro-User-Präferenzen je Event×Kanal. i18n bekommt einen Sprach-Wechsler (Profil + Public) und ein per DeepL (DE→EN, mit Review) befülltes EN-Locale mit Build-Validierung und Fallback DE, inkl. Empfänger-Sprach-Auflösung für Outbound-Mails.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| Dashboard-Edit-Modus [`/dashboard` (edit)] | Grid mit Drag/Resize, Widget-Picker (permission-gegateter Catalog), Pro-Widget-Config, Layout speichern | A-Dashboard + Edit |
|
||||
| Dashboard-Drilldown [`/dashboard` (Kachel)] | Pro-Kachel-Drilldown in Detail-Daten, CSV-Export, Report-Export | A3/Modal |
|
||||
| Notification-Präferenzen-Editor [`/settings/notifications`] | Matrix Event×Kanal (an/aus), Bündelungs-Verhalten | A6 |
|
||||
| Quiet-Hours-Einstellung [`/settings/notifications`] | Ruhezeit-Fenster, Urgent-Override-Regel | A6 |
|
||||
| Sprach-Wechsler [Profil + Public] | Sprachauswahl im Profil und im Public-Bereich, Fallback-Hinweis DE | A6/Control |
|
||||
| Tenant-Default-Sprache [`/admin/settings`] | Tenant-weite Default-Sprache, Empfänger-Sprach-Auflösung Outbound | A6 |
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] Dashboard: Layout anpassbar (Drag/Resize), Widget-Catalog permission-gegated, Drilldown pro Kachel, CSV-Export + Report-Export, Realtime mit Opt-Out
|
||||
- [ ] Notifications: Bündelung (gleicher event_type_group in 5-Min-Window → 1 Push/Mail mit count)
|
||||
- [ ] Notifications: Quiet-Hours (queued, Urgent-Override), Pro-User-Präferenzen Event×Kanal
|
||||
- [ ] i18n: Sprach-Wechsler (Profil + Public), EN-Locale via DeepL (DE→EN) mit Review
|
||||
- [ ] i18n: vollständige Build-Validierung, Fallback DE, Empfänger-Sprach-Auflösung Outbound
|
||||
- [ ] (Chat-Auto-Übersetzung koppelt an M13 + EU-LLM/v2-P4 — hier nur i18n-Fundament)
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Anpassbares Dashboard-Grid (Drag/Resize-Handles), Widget-Catalog/-Picker (permission-gegated), Pro-Widget-Config-Panel, Drilldown-Ansicht, CSV-/Report-Export-Button, Realtime-Opt-Out-Toggle, Notification-Präferenz-Matrix (Event×Kanal-Toggles), Bündelungs-Vorschau (count-Anzeige), Quiet-Hours-Zeitfenster-Picker, Urgent-Override-Schalter, Sprach-Wechsler (Dropdown/Selector), Fallback-DE-Hinweis, Tenant-Default-Sprach-Einstellung, Empty-/Loading-/Permission-Denied-States (Klartext).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (VA-P30a/b) aktualisiert:
|
||||
@@ -0,0 +1,53 @@
|
||||
# Designer-Brief · P31 — DSGVO-Vollausbau
|
||||
|
||||
**Phase:** 31/34 · **Modul:** M35 (M166) · **Owner-Dev:** Raffael (VR-P31) · **Designer:** David (D-DSGVO)
|
||||
**Quellen:** `ROADMAP-V2.md` §v2-P11 (NUR DSGVO-Teil) · `ROADMAP.md` §Phase 31 · `_bmad-output/specs/M35-dsgvo-export.md`
|
||||
**Subframe:** Pflicht je Route. Tenant-facing Privacy-Hub + Admin-Legal-Verwaltung.
|
||||
|
||||
> 🔵 **Nur DSGVO-Vollausbau:** Die ROADMAP-V2-Phase v2-P11 bündelt Telefonie-Erweiterung **und** DSGVO. Dieser Brief deckt **ausschließlich den DSGVO-Vollausbau (M166)** ab — AVV-Versionierung, Subprozessoren-Workflow, Auskunfts-/Voll-Export-Workflow. **HalloPetra/Telefonie ist eine eigene Phase (P33)** und nicht Teil dieses Briefs. P31 ersetzt das manuelle v1-Playbook durch echte Workflows; baut auf dem v1-DSGVO-Export/-Lösch-Fundament (P21) und der Admin-Legal-Verwaltung/AdminAuditLog (P28) auf.
|
||||
|
||||
> ⚠ **Risiko:** AVV-PDF-Inhalt muss anwaltlich finalisiert werden (in v1 EXT-03 beauftragt).
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Vertieft DSGVO-Compliance zu nutzbaren Self-Service-Workflows. Tenants akzeptieren eine versionierte AVV (dynamisches PDF, elektronische Akzeptanz), bei Updates ist Re-Akzeptanz innerhalb 14 Tagen erzwungen (danach Read-Only). Eine Subprozessoren-Liste mit Drittland-Warnung führt einen 14-Tage-Widerspruchs-Workflow. User exportieren ihre Daten (Art. 15/20); Tenants ziehen einen asynchronen Voll-Export (ZIP, 7-Tage-Download-Window) und durchlaufen einen Tenant-Lösch-Workflow (30-Tage-Grace + Hard-Delete-Cron, inkl. pgvector-Embedding-Löschung beim Hard-Delete).
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| DSGVO/Privacy-Hub [`/settings/privacy`] | Übersicht: Export-Jobs, AVV-Status/-Download, Subprozessoren, Tenant-Lösch-Einstieg | A6/Hub |
|
||||
| AVV-Download & History [`/settings/privacy/dpa`] | Aktuelle AVV als dynamisches PDF, Akzeptanz-Status, Versions-Historie, Re-Akzeptanz-Aufforderung (14-Tage-Frist → Read-Only) | A3 |
|
||||
| Subprozessoren-Liste [`/settings/privacy/subprocessors`] | Liste mit Drittland-Warnung, 14-Tage-Widerspruchs-Workflow, Widerspruch einlegen | A2 + Workflow |
|
||||
| Tenant-Voll-Export [`/settings/privacy/export`] | Async-Export-Job anstoßen (ZIP), Job-Status, 7-Tage-Download-Window | A2/Jobs |
|
||||
| Tenant-Lösch-Workflow [`/settings/privacy/delete`] | Multi-Step-Lösch-Flow mit Slug-Confirm, 30-Tage-Grace-Hinweis, Hard-Delete-Folgen | A5/Multi-Step |
|
||||
| User-Daten-Export / Account-Löschung [`/profile/privacy`] | Eigener Daten-Export (Art. 15/20), Account-Löschung erreichbar | A6 |
|
||||
| Admin: Subprozessoren-Verwaltung [`admin.hivegrid.de/legal/subprocessors`] | Subprozessoren anlegen/ändern, Drittland-Flag, Benachrichtigung auslösen | A2 + A3 |
|
||||
| Admin: AVV-Versions-Verwaltung [`admin.hivegrid.de/legal/dpa`] | AVV-Versionen pflegen, Veröffentlichung, Akzeptanz-Übersicht je Tenant | A2 + A3 |
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] AVV-Versionierung mit dynamischem PDF + elektronischer Akzeptanz
|
||||
- [ ] Re-Akzeptanz bei AVV-Updates (14-Tage-Frist → danach Read-Only)
|
||||
- [ ] Subprozessoren-Liste mit Drittland-Warnung + 14-Tage-Widerspruchs-Workflow
|
||||
- [ ] User-Daten-Export (Art. 15/20)
|
||||
- [ ] Tenant-Voll-Export (ZIP, async, 7-Tage-Download-Window)
|
||||
- [ ] Tenant-Lösch-Workflow (30-Tage-Grace + Hard-Delete-Cron, inkl. pgvector-Embedding-Löschung)
|
||||
- [ ] Admin-Legal-Verwaltung (Subprozessoren + AVV-Versionen) mit AdminAuditLog
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
PDF-Vorschau/-Download (dynamisches AVV), Akzeptanz-Button mit Status-Badge, Versions-Historie-Liste, Re-Akzeptanz-Banner (Frist-Countdown), Subprozessoren-Tabelle mit Drittland-Warn-Badge, Widerspruchs-Workflow-Aktion (Frist-Anzeige), Export-Job-Liste mit Status/Progress + Download-Link (Ablauf-Hinweis), Multi-Step-Lösch-Wizard mit Slug-Confirm-Eingabe + Folgen-Warnung, Grace-Period-Hinweis, Admin-CRUD-Tabellen (Subprozessoren/AVV-Versionen), Audit-Bezug, Empty-/Loading-/Permission-Denied-States (Klartext).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (VR-P31) aktualisiert:
|
||||
@@ -0,0 +1,49 @@
|
||||
# Designer-Brief · P32 — KWP-Integration (Recut)
|
||||
|
||||
**Phase:** 32/34 · **Modul:** M19 (M089–M095, M074) · **Owner-Dev:** Raffael (VR-P32a–c) · **Designer:** David/Akeshan (D-KWP)
|
||||
**Quellen:** `ROADMAP-V2.md` §v2-P5 · `ROADMAP.md` §Phase 32 · `_bmad-output/specs/M19-kwp-integration.md` + **`docs/milestones/M19-KWP-API-RECUT.md` (bindend)**
|
||||
**Subframe:** Pflicht je Route. Backend-lastig, aber Setup-/Health-/Sync-Log-/Konflikt-Screens existieren.
|
||||
|
||||
> 🔴 **Recut-Sonderfall (Block 2):** KWP wird regulärer **REST/OAuth-Adapter über die Apps-Engine (M33a)** — **`kwpsync.exe` wird NICHT gebaut** (3→2-Komponenten). Offizielle KWP-REST/OAuth-API. ⚠ **Größter Blocker:** der konkrete KWP-API-Vertrag (Auth/Endpoints/Webhook-Support/Rate-Limits/Versionierung/Doc-API) ist noch offen — Zugang ~20.07. ist der härteste Kalender-Anker; Detail-Planung pro Milestone braucht den Vertrag. Backend-lastige Phase, aber mit klar umrissenen Setup-/Health-/Log-/Konflikt-Oberflächen.
|
||||
|
||||
## Was dieses Modul tut (Kurzfassung)
|
||||
|
||||
Bindet KWP als ersten konkreten Adapter hinter dem M33a-Interface an und spiegelt bidirektional: Push (gewonnener Deal → Auftrag) via Cloud-Outbox + rate-limited Replay, Pull via Webhook (falls KWP unterstützt) oder Cron, idempotent über `AppSyncItem`. Credentials liegen per-Tenant-DEK-verschlüsselt in `DataConnection.config`. Konflikte lösen sich nach „KWP gewinnt" (LWW mit Audit-Restore) plus HiveGrid-seitigem Optimistic Locking. Ein API-Contract-Sentinel (zod-Validierung + Versions-Check) pausiert den Sync bei Drift und alarmiert den Plattform-Admin. Plantafel- und Dokumenten-Archiv-Sync laufen über die API.
|
||||
|
||||
## Benötigte Screens
|
||||
|
||||
| Screen [Route] | Kern-Inhalt | Archetyp |
|
||||
|---|---|---|
|
||||
| KWP-Setup-Wizard [`/integrations/kwp/setup`] | OAuth/API-Key-Verbindung, Credential-Eingabe (DEK-verschlüsselt), Initial-Sync-Vorschau | A5/Wizard |
|
||||
| Connection-Health-View [`/integrations/kwp`] | Verbindungsstatus (verbunden/broken), letzter Sync, Health-Probe, Re-Connect | A3/Status |
|
||||
| Sync-Log [`/integrations/kwp/log`] | Sync-Items (Push/Pull), Status, Zeit, KwpErrorReport-Einträge, Filter | A2 |
|
||||
| Konflikt-Resolution [`/integrations/kwp/conflicts`] | Konflikt-Paare (HiveGrid vs. KWP), Feld-Diff, „KWP gewinnt"-Anzeige + Audit-Restore | A5 + Diff |
|
||||
| Tenant-UI Sync-Pausen-Hinweis [Banner] | Klartext bei Contract-Drift: „KWP-Update erkannt — Sync pausiert für Sicherheit. Wir sind informiert." | Banner |
|
||||
| Admin: KWP-Sync-Status pro Tenant [`admin.hivegrid.de/integrations/kwp`] | Sync-Status je Tenant, Contract-Diff-Tool, Sync-Freigabe nach Adapter-Update | A2 + A3 |
|
||||
|
||||
## Geplante Features (muss abgedeckt sein)
|
||||
|
||||
- [ ] KWP-API-Connector als erster konkreter Adapter hinterm M33a-Interface; **kwpsync.exe NICHT bauen**
|
||||
- [ ] Credentials per-Tenant-DEK-verschlüsselt in `DataConnection.config`
|
||||
- [ ] Bidirektionaler Sync: Push (Won→Auftrag) via Outbox + rate-limited Replay; Pull via Webhook/Cron, idempotent über `AppSyncItem`
|
||||
- [ ] Konflikt „KWP gewinnt" (LWW mit Audit-Restore) + Optimistic Locking HiveGrid-seitig
|
||||
- [ ] API-Contract-Sentinel (zod-Validierung + Versions-Check) pausiert Sync bei Drift + alarmiert Plattform-Admin
|
||||
- [ ] Plantafel-Sync + Dokumenten-Archiv-Sync (KWP-Doc → Storage) über die API
|
||||
- [ ] Task-ERP-Sync (M074)
|
||||
|
||||
## Benötigte UI-Elemente (Liste, KEIN Layout — Anordnung = Davids freie Hand)
|
||||
|
||||
Verbindungs-Setup-Wizard (OAuth/API-Key-Eingabe, maskierte Credentials), Initial-Sync-Vorschau (was wird gespiegelt), Connection-Health-Statusanzeige (Ampel + letzter Heartbeat/Sync), Re-Connect-Button, Sync-Log-Tabelle (Push/Pull-Richtung, Status, Fehler-Report-Aufklappen), Konflikt-Diff-Ansicht (Feld-für-Feld HiveGrid vs. KWP, „KWP gewinnt"-Markierung, Restore-Aktion), Sync-Pausen-Banner (Klartext, Kontakt-Hinweis), Admin-Tenant-Sync-Statusliste, Contract-Diff-Tool, Sync-Freigabe-Aktion, Empty-/Loading-/Permission-Denied-States (Klartext).
|
||||
|
||||
## Davids Delta (David füllt aus)
|
||||
|
||||
- [ ] Überschriebene/geänderte Spec-Punkte:
|
||||
- [ ] Neue UI/UX-Entscheidungen:
|
||||
- [ ] Subframe-Screen-Link(s):
|
||||
- [ ] Offene Fragen an Dev:
|
||||
|
||||
## Dev-Nachzug (wir nach Davids Delta)
|
||||
|
||||
- [ ] Spec/ENTITY-MODEL an Davids Entscheidungen angepasst:
|
||||
- [ ] REQUIREMENTS/PHASE-SOURCES nachgezogen:
|
||||
- [ ] Plane-Ticket (VR-P32a–c) aktualisiert:
|
||||
Loaded 100 of 5784 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user