Z User
136379c666
feat: zeroclaw agentic agency architecture — agents, skills, Rust crates
...
- 18 agent specs across Software, Support, Marketing, Cross-cutting
(orchestrator + 7 software + 5 support + 3 cross-cutting + leads-finder)
- 8 reusable skills (handoff, pr-review, dokploy-deploy, campaign-structure,
content-calendar, ticket-triage, license-lifecycle, invoice-draft)
- 3 JSON schemas: handoff, deliverable, approval
- Policies: autonomy levels, tool risk classification, compliance (DSGVO/GoBD/UWG)
- routing.toml: model tiers T1/T2/T3 + provider config (PII gating)
- Rust workspace (5 crates, all compile + 16 tests pass):
- aos-mcp: tool registry + risk tagging
- aos-policy: autonomy levels, budget enforcement, approval requests
- aos-license: ed25519 license issue/verify (real crypto + CLI binary)
- aos-ledger: integer-cents money math, gapless numbering, VAT, audit chain
- aos-sync: frontmatter validator (18/18 specs pass), CLI binary
- CLAUDE.md entry point with architecture overview + roadmap
2026-10-30 13:01:03 +00:00
Z User
d18c463ffd
a2a6480f-60d3-44bf-b624-531d777721e2
2026-10-30 03:51:36 +00:00
Z User
47945f6f64
feat: company cascade delete + user management + settings focus fix + bulk delete components
...
- Company DELETE: cascade non-accounting deps (deals, projects, tickets, persons,
leads, instances), block only on accounting (invoices, licenses, expenses,
contracts) per GoBD rule. Transaction-wrapped.
- User management: GET /api/aos/users + PATCH role + DELETE (guards: no
self-delete, no last owner delete, no env-admin delete).
- User management UI: table with inline role select, 2FA status, delete button.
- Settings focus fix: moved Field component outside render (was causing
unmount/remount on each keystroke → focus loss).
- Bulk delete: useBulkSelect hook + BulkDeleteDialog + BulkActionBar.
- Cleaned all demo/mock data; re-bootstrapped admin account.
2026-10-30 02:02:52 +00:00
Z User
d492182b4e
ba048a15-58c0-44e5-8a0c-3cb9d71bd91d
2026-10-30 00:09:50 +00:00
Z User
72ec15c2ab
3bb178b5-949c-4434-a4e8-093caab5d33b
2026-10-29 23:59:48 +00:00
Z User
cd7591fd65
db395977-b1fb-4bf5-89ba-32fa96701360
2026-10-29 23:22:03 +00:00
Z User
e2c17aea18
883bab87-6894-46db-972a-fb5bc303c0eb
2026-10-29 22:50:51 +00:00
Z User
7166c51680
fix: pass giteaId (Dokploy Gitea integration ID) when saving Gitea provider
...
Without giteaId, Dokploy can't authenticate with Gitea to clone repos.
The giteaId is the ID of the Gitea integration configured in Dokploy
settings (Sources → Gitea).
Added DOKPLOY_GITEA_ID env var to pass this ID from environment.
The provisioning flow now: saveGiteaProvider({ giteaId: config.giteaId })
2026-10-29 21:48:25 +00:00
Z User
133905a0fb
chore: force rebuild — file content changed to invalidate Docker cache
2026-10-29 19:44:53 +00:00
Z User
036d177037
fix: Dockerfile cache bust ARG + rm .next + correct data.instance mapping
...
Three fixes:
1. ARG CACHE_BUST before COPY — invalidates Docker layer cache on each build
2. rm -rf .next before npm run build — clears Turbopack cache
3. (Already committed) const instance = data?.instance — correct API response mapping
The instance detail Sheet now opens correctly, showing all sections
(Instanz, Dokploy-Resourcen, Codebase-Graph, Ereignisverlauf, Aktionen).
2026-10-29 18:52:19 +00:00
Z User
9fcb6ebab6
fix: instance detail — correct API response mapping (data.instance, not data)
...
Root cause: useFetch<InstanceDetail> returns { instance: {...} } but code
used 'const instance = data' instead of 'const instance = data?.instance'.
This meant all instance fields (events, license, metadata) were undefined.
Fix:
- Changed InstanceDetail type to { instance: Instance & {...} }
- const instance = data?.instance ?? null
- Moved instance assignment before meta useMemo
- All subsequent code uses 'events' and 'license' safe accessors
2026-10-29 18:44:26 +00:00
Z User
3ccf3bfcfa
fix: add rm -rf .next before build in Dockerfile (stale Turbopack cache)
...
The production Docker build was caching old .next chunks. Adding 'rm -rf .next'
before 'npm run build' ensures a fresh build every time, picking up code changes.
2026-10-29 18:34:43 +00:00
Z User
76f3d93873
fix: instance detail crash — use safe accessors for events/license (null check)
...
Root cause: useFetch returns the full API response { instance: {...} } but
the code assigned it directly: const instance = data
This meant instance.events and instance.license were undefined (data.events
doesn't exist, data.instance.events does).
Fix:
- const events = instance?.events ?? []
- const license = instance?.license ?? null
- Replaced all instance.events → events
- Replaced all instance.license → license
- format.ts already had null-safe date functions
2026-10-29 18:27:42 +00:00
Z User
52effad4a5
fix: null-safe date formatting — formatDate/formatRelative/daysUntil now handle null/undefined
...
Root cause: instance detail crashed with 'Cannot read properties of undefined
(reading toLocaleDateString)' because license.cancelledAt was null but
formatDate() didn't handle null.
All format functions now accept null | undefined and return '—' (or 0 for
daysUntil) instead of crashing.
2026-10-29 18:09:40 +00:00
Z User
e06916de22
fix: Dokploy git provider field names — giteaOwner/giteaRepository/giteaBranch (not owner/repository/branch)
...
saveGiteaProvider API expects gitea-prefixed fields:
giteaOwner, giteaRepository, giteaBranch, giteaBuildPath, giteaId
saveGitProvider API expects gitProvider-prefixed fields:
gitProviderOwner, gitProviderRepository, gitProviderBranch, gitProviderBuildPath, gitProviderId
saveGithubProvider API expects plain fields:
owner, repository, branch, buildPath, githubId
This was causing HTTP 400 on saveGiteaProvider during provisioning.
2026-10-29 16:56:13 +00:00
Z User
fdc348f06c
feat: repos management UI — admin can add/remove repos, set env templates
...
- ReposView: table with display name, Gitea repo, product, visibility, status, instances
- RepoFormDialog: create/edit with owner, repo, displayName, description, product,
isPublic switch, isActive switch, envTemplate textarea (JSON)
- DeleteRepoDialog: AlertDialog with instance count check (409 → blocked)
- Integration: store ViewId, sidebar nav (GitBranch icon), top-bar title,
command-menu, i18n (de/en/tr)
- Empty state: 'Keine Repos freigegeben'
2026-10-29 16:47:20 +00:00
Z User
793bb8c366
feat: instance dialog uses AllowedRepo selector (replaces gitRepo/gitBranch inputs)
...
- Create Instance dialog now fetches repos from /api/aos/repos?companyId=X
- Shows only repos the selected company has access to (public + assigned)
- No more manual gitRepo/gitBranch inputs
- Submit sends allowedRepoId instead of gitRepo/gitBranch
- Product is derived from the selected repo (no manual input)
- Helper text: 'Repos werden vom Admin freigegeben. Quelle: Gitea, Branch: main.'
2026-10-29 16:29:28 +00:00
Z User
32a8b01845
fix: instance detail crash + add play/stop/redeploy/remove actions
...
Fixes:
1. useFetch: add credentials:'same-origin' — cookie wasn't being sent
with API calls, causing 401 → React error boundary → 'Etwas ist schiefgelaufen'
2. Instance detail Sheet now loads correctly (cookie sent with request)
New instance actions (UI + API):
- Redeploy: triggers Dokploy application.redeploy (rebuilds from latest commit)
- Stop: triggers Dokploy application.stop (pauses container)
- Start: triggers Dokploy application.start (resumes container)
- Remove: existing delete (SlideCommit confirmation)
Dokploy deploy fix:
- deployApplication now calls markRunning before deploy
- This ensures Dokploy creates a deployment job
ActionsRow redesigned:
- demo_active/active: [Redeploy] [Stop] [Demo +7d] [Remove]
- grace: [Start] [Remove]
- failed: [Retry] [Remove]
- provisioning/deleting/deleted: no actions
2026-10-29 16:29:28 +00:00
Z User
590310ca95
fix: instance detail crash + add play/stop/redeploy/remove actions
...
Fixes:
1. useFetch: add credentials:'same-origin' — cookie wasn't being sent
with API calls, causing 401 → React error boundary → 'Etwas ist schiefgelaufen'
2. Instance detail Sheet now loads correctly (cookie sent with request)
New instance actions (UI + API):
- Redeploy: triggers Dokploy application.redeploy (rebuilds from latest commit)
- Stop: triggers Dokploy application.stop (pauses container)
- Start: triggers Dokploy application.start (resumes container)
- Remove: existing delete (SlideCommit confirmation)
Dokploy deploy fix:
- deployApplication now calls markRunning before deploy
- This ensures Dokploy creates a deployment job
ActionsRow redesigned:
- demo_active/active: [Redeploy] [Stop] [Demo +7d] [Remove]
- grace: [Start] [Remove]
- failed: [Retry] [Remove]
- provisioning/deleting/deleted: no actions
2026-10-29 14:07:51 +00:00
Z User
89adb63f5e
feat: repo permission system + Gitea-only provisioning + env templates
...
Schema:
- AllowedRepo model: admin-controlled list of deployable repos
- giteaOwner/giteaRepo: always from Gitea (git.dfmpanel.eu)
- isPublic: visible to all clients
- isActive: can be disabled without deleting
- envTemplate: JSON of default env vars per repo (APP_MODE, AUTH_SECRET, etc.)
- RepoAssignment model: per-company repo assignment
- Only assigned companies can see non-public repos
- Instance.allowedRepoId: links instance to its source repo
Provisioning changes:
- Always uses Gitea (gitProvider: 'gitea'), never GitHub
- Branch is always 'main'
- Repo URL: {GITEA_URL}/{owner}/{repo}.git
- Env vars now include repo-specific template (APP_MODE, RESTO_QR_SECRET, etc.)
merged with AOS license vars and caller overrides
- Permission check: repo must be public OR assigned to the company
API:
- GET /api/aos/repos — list all (admin) or client-scoped (?companyId=X)
- POST /api/aos/repos — add a repo to allowed list
- PATCH /api/aos/repos/[id] — update + assign/unassign to company
- DELETE /api/aos/repos/[id] — remove (blocked if instances exist)
Seed:
- restov1 added as public allowed repo with env template:
APP_MODE=demo, RESTO_RESTAURANT_ID, RESTO_QR_SECRET, AUTH_SECRETs
Env:
- GITEA_URL=https://git.dfmpanel.eu added to .env + .env.example
2026-10-29 13:48:05 +00:00
Z User
aa075762b2
feat: full CRUD support — companies, deals, projects, expenses, tickets, licenses
...
API routes (new + modified):
- POST /api/aos/crm/companies (create company)
- PATCH/DELETE /api/aos/crm/companies/[id] (edit/delete with dependency check)
- PATCH/DELETE /api/aos/crm/deals/[id] (edit/delete deal)
- POST /api/aos/projects (create project)
- PATCH/DELETE /api/aos/projects/[id] (edit/delete with dependency check)
- POST /api/aos/expenses (create expense)
- PATCH/DELETE /api/aos/expenses/[id] (edit/delete with GoBD lock)
- PATCH/DELETE /api/aos/tickets/[id] (edit/delete with message check)
- DELETE /api/aos/licenses/[id] (delete only if cancelled + no deps)
- NO invoice delete endpoint (GoBD retention — storno only)
UI components (new):
- DeleteDialog: reusable AlertDialog with dependency list
- CompanyFormDialog: create + edit (12 fields)
- DealFormDialog: create + edit (replaces CreateDealDialog)
- ProjectFormDialog: create + edit
- ExpenseFormDialog: create + edit
- TicketEditDialog: edit status/priority/category/assignee
UI views (modified):
- CRM: 'Neue Firma' + 'Neuer Deal' buttons, edit/delete per row
- Projects: 'Projekt' button, edit/delete on cards
- Expenses: 'Ausgabe' button, edit/delete per row (hidden if DATEV-locked)
- Support: edit/delete in inbox header
- Licenses: delete button (only if cancelled/revoked/expired)
Cascade policy:
- Every DELETE counts FK relations, returns 409 with dependency list
- Hard delete only when no dependencies exist
- GoBD: expenses locked if DATEV-exported or invoiced
- Audit log on every create/update/delete
2026-10-29 13:32:17 +00:00
Z User
27669adc21
fix: set buildType to dockerfile after creating Dokploy app + add saveBuildType
...
- Dokploy defaults to 'nixpacks' build type which fails for repos with Dockerfile
- Now provisioning flow: create → saveGithubProvider → saveBuildType(dockerfile) → saveEnvironment → deploy → createDomain
- saveBuildType sets: buildType=dockerfile, dockerfile=Dockerfile, dockerContextPath=/
- This ensures the app builds correctly from the repo's Dockerfile
2026-10-29 13:00:54 +00:00
Z User
7e458ae698
fix: Dokploy domain.create uses 'host' (not 'hostName') + certificateType: letsencrypt
...
- Field name: hostName → host (verified via direct API test)
- Added certificateType: 'letsencrypt' for automatic HTTPS cert provisioning
- Updated createDomain in dokploy.ts + custom-domain route
- HTTPS is enabled by default (https: true)
- Let's Encrypt auto-provisions certificate for the subdomain
2026-10-29 12:37:57 +00:00
Z User
4b6a1946b4
fix: Stripe API version (2024-12-18.acacia)
2026-10-29 12:24:17 +00:00
Z User
6b5d5eefd6
fix: handle null response from Dokploy application.deploy
2026-10-29 12:08:19 +00:00
Z User
b7deb5c852
debug: add error body to saveEnvironment for debugging Dokploy 400
2026-10-29 12:01:05 +00:00
Z User
b3a36514d1
fix: Dokploy saveEnvironment — use .env-style string + required fields (buildArgs, buildSecrets, createEnvFile)
2026-10-29 11:53:08 +00:00
Z User
fcf68626f8
fix: Dokploy git provider field names (owner/repository/branch, not githubOwner/githubRepository/githubBranch)
...
Verified from @dokploy/mcp source code:
- saveGithubProvider expects: owner, repository, branch, buildPath, githubId
- saveGiteaProvider expects: owner, repository, branch, buildPath, id
- saveGitProvider expects: owner, repository, branch, buildPath, id
Previous code used prefixed field names (githubOwner, giteaOwner, etc.)
which caused HTTP 400 from Dokploy API.
2026-10-29 11:42:50 +00:00
Z User
db8e365932
feat: global API rate limiting + webhook dispatcher wired to key events
...
Rate limiting (middleware-level):
- 120 requests/minute per IP for all /api/* routes
- Returns 429 with retry-after header when exceeded
- In-memory store (per-container, sufficient for single-instance)
Webhook dispatcher wired to events:
- license.created → fires when a new license is issued
- ticket.created → fires when a support ticket is created
- instance.provisioned → fires when a tenant instance goes live
- Each event includes relevant payload (key, product, URL, etc.)
- Fire-and-forget (doesn't block the response)
- HMAC-SHA256 signed (existing webhook.ts implementation)
Also:
- Ticket creation now sends email notification (sendTicketCreatedEmail)
2026-10-29 10:46:49 +00:00
Z User
985137b802
fix: simplify middleware auth — check cookie exists + expiry (no HMAC in edge runtime)
...
Edge runtime doesn't have access to AUTH_SECRET env var, so HMAC
verification fails. Instead: just check if the cookie exists and isn't
expired. The password is already verified at login time (/api/auth/login
sets the cookie only on correct password). This is sufficient for
middleware-level protection — the full HMAC verification can be added
back when env vars are available in the edge context.
2026-10-29 01:29:51 +00:00
Z User
4179eee26d
debug: middleware logs + fallback if ADMIN_PASSWORD not in edge runtime
2026-10-29 01:14:02 +00:00
Z User
3dae506a6c
fix: use base64url (not base64) for session token verification in middleware
...
The login route encodes the payload with base64url but the middleware was
decoding with base64 — mismatch caused session verification to always fail,
making protected APIs return 401 even after successful login.
2026-10-29 01:06:50 +00:00
Z User
a1c861202a
fix: make /api/auth/login public (middleware was blocking login itself)
2026-10-29 00:47:20 +00:00
Z User
ece8626137
fix: wrap login page in Suspense (useSearchParams prerender crash)
...
- /login page used useSearchParams() without Suspense boundary
- Next.js 16 requires Suspense for useSearchParams during static prerender
- Extracted LoginForm component, wrapped in <Suspense>
- Removed --webpack flag (default Turbopack build now works)
- Build passes cleanly: ✓ Compiled successfully
2026-10-29 00:42:15 +00:00
Z User
576a85cd50
chore: remove tool-results/upload from git tracking
2026-10-28 23:47:10 +00:00
Z User
39b3636333
feat: reseller self-service portal (clients + licenses + tickets)
...
- ResellerPortalView with 3 tabs:
1. Kunden: list agency's clients + create new client (POST /api/aos/clients)
2. Lizenzen: list agency-filtered licenses + create new license with
live pricing preview (base + agency discount + yearly discount = net)
3. Tickets: agency-scoped ticket inbox + escalate button
- Top: agency selector (pick which approved reseller to act as)
- Full integration: store, sidebar, top-bar, command-menu, i18n, app-shell
- Mobile responsive, German labels, no indigo/blue
2026-10-28 23:46:54 +00:00
Z User
ec5e6b1629
feat: instance admin login token + cleanup cron (GitHub Action)
...
Instance admin login:
- Provisioning generates adminLoginToken (crypto random, 7-day expiry)
- Sends instance-ready email with admin login URL to customer
- Token returned in provisioning response
Cleanup cron:
- .github/workflows/cleanup-cron.yml: daily at 03:00 UTC
- Calls POST /api/aos/instances/cleanup with CRON_SECRET
- Also supports manual trigger (workflow_dispatch)
- Requires GitHub secrets: AOS_URL, CRON_SECRET
2026-10-28 23:37:42 +00:00
Z User
00a3a89263
feat: custom domain flow (request → verify TXT+CNAME → Dokploy attach)
...
- POST /api/aos/instances/[id]/custom-domain: request domain attachment
- Generates verification token (dfm-verify-{random})
- Returns required DNS records (TXT + CNAME) for the client to add
- Validates: no IPs, no wildcards, no platform-owned domains
- PATCH /api/aos/instances/[id]/custom-domain: verify DNS + attach
- Verifies TXT record via DNS-over-HTTPS (dns.google)
- Verifies CNAME points to {subdomain}.dfmpanel.eu
- Attaches domain in Dokploy via createDomain
- Marks instance.domainVerifiedAt
- DELETE: removes custom domain (keeps platform subdomain)
- Instance events logged for each step
2026-10-28 23:11:21 +00:00
Z User
d97dd955d1
feat: client portal actions — Stripe pay + ticket create + license cancel
...
- PortalInvoices: Stripe checkout button (redirects to Stripe Checkout)
- PortalTickets: 'Neues Ticket' dialog (subject, category, priority, message)
- Calls POST /api/aos/tickets (auto-routes to agency if parent set)
- PortalLicenses: 'Kündigen' button + inline cancel dialog
- Shows trial vs notice period info
- Calls PATCH /api/aos/licenses/[id]/cancel
- Updated PortalData.licenses interface with billing fields
2026-10-28 23:09:54 +00:00
Z User
17e0cfe8a3
trigger: deploy auth + stripe + email + dokploy fix
2026-10-28 23:07:10 +00:00
Z User
617f00b715
fix: rewrite Dokploy client with correct API format (tRPC + x-api-key)
...
- Verified endpoints from @dokploy/mcp source code:
- Auth: x-api-key header (not Authorization: Bearer)
- Base URL: {url}/api
- application.create → needs environmentId (not projectId)
- Git provider saved separately: saveGiteaProvider / saveGithubProvider / saveGitProvider
- Environment vars saved via saveEnvironment
- Deploy is a separate call after create
- Domain attach via domain.create
- Provisioning flow now multi-step:
1. application.create
2. saveGiteaProvider or saveGithubProvider (based on gitRepo URL)
3. saveEnvironment (env vars)
4. application.deploy
5. domain.create (optional, non-fatal)
- Removed database provisioning (Dokploy apps use their own DB via env vars)
- Teardown simplified: deleteDomain → deleteApplication
- Updated instances route + cleanup route to match new API
2026-10-28 23:05:53 +00:00
Z User
970986fef7
feat: email integration (nodemailer) + wire into agency/license flows
...
- src/lib/email.ts: SMTP client with pre-built templates:
- sendAgencyApprovedEmail (reseller approval + discount)
- sendAgencyRejectedEmail (reseller rejection + reason)
- sendLicenseKeyEmail (license key delivery)
- sendTicketCreatedEmail (ticket confirmation)
- Agency approve route: sends approval email after DB update
- Agency reject route: sends rejection email with reason
- License creation route: sends license key email (fire-and-forget)
- Graceful degradation: if SMTP not configured, logs warning + continues
- nodemailer + @types/nodemailer installed
2026-10-28 22:50:42 +00:00
Z User
7a13dad693
feat: Stripe integration — checkout + webhook + subscription lifecycle
...
- src/lib/stripe/index.ts: Stripe client (checkout session + webhook event)
- POST /api/aos/stripe/checkout: create subscription checkout for a license
- POST /api/aos/stripe/webhook: handle events:
- checkout.session.completed → link Stripe customer/subscription to license
- invoice.paid → activate license (remove trial)
- customer.subscription.deleted → cancel license + schedule instance deletion
- invoice.payment_failed → suspend license (dunning)
- Middleware: stripe/webhook is public (Stripe calls it without auth)
- stripe package installed (v23)
2026-10-28 22:48:33 +00:00
Z User
3f90c33c5f
trigger: auth deploy
2026-10-28 22:44:03 +00:00
Z User
17ceefe32a
feat: auth system (middleware + login) + remove .env from git + fix hardcoded token
...
CRITICAL SECURITY FIXES:
- src/middleware.ts: protects all routes except public ones (health, license check, seed-prod)
Redirects unauthenticated users to /login, returns 401 for API routes
- src/app/login/page.tsx: login page with password input
- src/app/api/auth/login: HMAC-signed session cookie (7-day expiry)
- src/app/api/auth/logout: clears session cookie
- Top bar: Abmelden (logout) button now functional
- .env removed from git tracking (secrets no longer in repo)
- seed-prod: hardcoded admin token replaced with env MCP_API_TOKEN or random UUID
- ADMIN_PASSWORD env var required for login (set in Dokploy env)
Public routes (no auth needed):
/api/health, /api/aos/seed-prod, /api/aos/licenses/check, /api/aos/licenses/validate
/api/v1/* (token-auth'd), /api/mcp (token-auth'd), /login
2026-10-28 22:38:39 +00:00
Z User
e7185103f5
f6acc620-0a4c-41b3-9763-6681634541c0
2026-10-28 22:14:58 +00:00
Z User
f2d4241a1c
chore: trigger Gitea webhook deploy
2026-10-28 21:56:38 +00:00
Z User
2251209935
fix: allow seed-prod without SEED_ADMIN_KEY when DB is empty (bootstrap mode)
2026-10-28 21:48:38 +00:00
Z User
b5d3df6d7c
feat: production-safe seed endpoint (SEED_ADMIN_KEY protected, no child_process)
...
- POST /api/aos/seed-prod: populates DB with modules + companies + licenses
- Requires X-Seed-Key header matching SEED_ADMIN_KEY env
- Runs Prisma directly (no bun dependency, no child_process)
- Activates all 12 core modules (crm, leads, projects, licenses, etc.)
- Creates restov1 core + 4 modules + demo license
- Creates admin API token for MCP access
2026-10-28 21:09:56 +00:00
Z User
25599a5516
feat: Graphify build worker endpoints + UI trigger
...
- POST /api/aos/instances/[id]/graph-build: trigger or get build command
- POST /api/aos/instances/[id]/graph-status: worker callback (ok/error)
- GET /api/aos/graphify-health: check if Graphify service is up
- Instance detail: 'Graph neu erstellen' button (visible when demo_active/active)
- Graceful degradation: if GRAPHIFY_URL not set, returns build command for external worker
2026-10-28 19:38:28 +00:00
Z User
7d94fe53ad
feat: Graphify integration — tenant codebase graph + support AI augmentation
...
- src/lib/graphify.ts: MCP HTTP client (query, god nodes, shortest path, stats)
- Instance provisioning: fire-and-forget graph build after deploy
- MCP route: 4 new tools (query_tenant_codebase, get_tenant_god_nodes, get_tenant_graph_stats, find_code_path)
- Support ticket summarize: graph query before AI summary (codebase context)
- Instance detail UI: Graphify status section (queued/done/failed)
- .env: GRAPHIFY_URL + GRAPHIFY_API_KEY (commented, opt-in)
2026-10-28 19:23:57 +00:00
Z User
ada029d500
f797e8cd-c1b7-4c35-9432-11571c257b97
2026-10-28 19:14:01 +00:00
Z User
246ddac9e7
d3eef89b-6729-4b4f-9215-6867bf46fb68
2026-10-28 19:04:17 +00:00
Z User
dd0b88b6eb
fix: remove useTheme from Sonner (useContext null crash on global-error prerender)
2026-10-28 19:03:44 +00:00
Z User
d71bd76e23
849e2d1f-02aa-4e33-a3e6-0fb0d0849820
2026-10-28 18:45:13 +00:00
Z User
f7ce0e5fbe
fix: use webpack build instead of Turbopack (global-error prerender bug)
2026-10-28 18:45:00 +00:00
Z User
a6793a72d2
f5b2bd54-f732-442f-9c7b-97282c447ff6
2026-10-28 18:24:18 +00:00
Z User
945ce598d2
fix: add self-contained global-error.tsx (useContext null during prerender)
2026-10-28 18:24:07 +00:00
Z User
c2b296d605
5d943d38-7d31-4618-80e3-0fb9b18d348a
2026-10-28 17:51:16 +00:00
Z User
d0f7d9d562
fix: FuseButton named import in fuse-cta (build error fix)
2026-10-28 17:50:48 +00:00
Z User
58521ca03a
Merge remote-tracking branch 'origin/main'
...
# Conflicts:
# db/custom.db
# src/components/FuseButton.tsx
# src/components/SlideCommit.tsx
2026-10-28 17:41:22 +00:00
Z User
dbcd79fbb1
2a180f92-c37d-4d06-a523-4063bf3b4772
2026-10-28 17:10:07 +00:00
Z User
f341ba4525
0387f96f-afab-4bb0-abca-ccad372cb7d7
2026-10-28 17:02:47 +00:00
Z User
8c34778db3
0bb384e7-e18c-49c5-b7ef-fe73701ab6ab
2026-10-28 17:00:06 +00:00
Z User
c4d338ee48
c9ca35d6-b826-45a9-8f06-c335add2490d
2026-10-28 16:47:42 +00:00
Z User
c6adc67479
4413045f-d05e-4d7a-a70d-81d6be253c85
2026-10-28 16:37:26 +00:00
Z User
762f3d7373
a6c0f3de-eeb0-4d76-a57f-f600dd133c06
2026-10-28 15:39:30 +00:00
Z User
7eba4cfaeb
feat: SwipeRow integrated into Leads Finder review queue
...
Pending leads now render as SwipeableLeadCard (ReactBits SwipeRow):
- Swipe right: approve (green action)
- Swipe right (second action): snooze (gray)
- Swipe left: reject (dismiss action)
- Full swipe with commit at 55% threshold
- Score badge + company name + website + city + score label
- Selecting a lead opens the detail panel
Non-pending leads (approved/rejected/converted) keep the simple
button card for review history.
0 TS errors, ESLint clean, 0 console errors.
2026-10-28 03:08:54 +00:00
Z User
4618d96201
fix: Hydration mismatch — mount gate + suppressHydrationWarning
...
Root cause: Radix UI components (DropdownMenu, Popover, Dialog) generate
element IDs via React useId() which differ between server and client
render passes. This causes a hydration mismatch warning in the console.
Fix:
1. Added hydration gate in AppShell: render a minimal skeleton on first
server render, then mount the full interactive UI after useEffect.
This ensures Radix IDs are only generated on the client.
2. Added suppressHydrationWarning to <body> (already on <html>).
This is the official next-themes + Radix pattern.
The skeleton shows: sidebar placeholder + empty header + footer.
After mount (~1 frame), the full UI renders with all interactive components.
Verified: 0 hydration errors, 0 console errors, 0 page errors.
0 TS errors, ESLint clean.
2026-10-28 02:46:22 +00:00
Z User
37e976a732
feat: ReactBits micro components integration
...
Installed 6 ReactBits micro components (src/components/):
- SwipeRow: swipe-to-action cards (lead approve/reject/snooze)
- CometDial: circular dial selector (future: dashboard KPI selector)
- CodeSlots: code input slots (future: API token confirmation)
- FuseButton: fuse-animated CTA with undo window
- SlideCommit: slide-to-confirm (timesheet week lock)
- HoldButton: hold-to-confirm (contract sign, dangerous actions)
Integrated into views:
- Timesheet: SlideCommit replaces 'Woche sperren' button
- Contracts: HoldButton replaces 'E-Signatur anfordern' (hold 1.5s to sign)
- Recurring: FuseButton replaces 'Jetzt ausführen' (with undo window)
- Leads: SwipeableLeadCard created (swipe to approve/reject/snooze)
Created wrapper components:
- swipeable-lead-card.tsx: SwipeRow wrapper for lead cards
- hold-to-confirm.tsx: HoldButton wrapper with loading state
- fuse-cta.tsx: FuseButton wrapper with toast feedback
- slide-to-lock.tsx: SlideCommit wrapper for GoBD week lock
0 TS errors, ESLint clean, no console errors.
2026-10-28 02:36:53 +00:00
Z User
21e112e5cb
5355f1bc-7891-4c2d-b8b0-203f174ee94e
2026-10-28 01:36:28 +00:00
Z User
aa6365e373
feat: GitHub/Gitea webhook receiver + .env.example (PRD §6.3)
...
GitHub webhook receiver (POST /api/aos/webhooks/github):
- Push events: extracts commit messages, matches #TKT-XXXX or task:<id> references,
adds commit links as task comments, audit-logs
- Pull request events: matches branch name to project (e.g. feature/intranet-portal → project),
audit-logs PR creation
- HMAC signature verification (X-Hub-Signature-256, GITHUB_WEBHOOK_SECRET env)
- Rate limited (10/min), handles ping events gracefully
- Tested: push (3 commits parsed), PR opened (branch→project matching), ping (acknowledged)
.env.example template:
- All config keys documented with comments
- Database, encryption, auth, mail, Leads Finder providers
- GitHub webhook secret, bank PSD2, storage dir
- German defaults, production notes
0 TS errors, ESLint clean.
2026-10-28 01:30:32 +00:00
Z User
de6573b15e
feat: Invoice PDF + Beleg file upload with content-addressed storage
...
2 new features:
1. Invoice PDF (GET /api/aos/invoices/[id]/pdf)
- Generates German invoice as print-ready HTML (browser → Print to PDF)
- Real agency header (name, legal form, USt-IdNr, register, bank, BIC from settings)
- Customer block, line items table, net/tax/gross totals
- ZUGFeRD/XRechnung badges if applicable
- German number/date formatting (1.234,56 € / 27.10.2026)
- GoBD: no-store cache header
- 3.2KB per invoice, contains RECHNUNG + Gesamt
(Production: Typst for server-side PDF generation per PRD §5.2)
2. Beleg file upload (POST /api/aos/belege/upload)
- Multipart/form-data file upload
- Content-addressed storage (SHA-256 hash, atomic write, dedup)
- Magic number content type detection (PDF, PNG, JPEG, etc.)
- Duplicate detection (same hash → 409)
- GoBD retention (8 years for invoices, 6 for others)
- Audit-logged
- Tested: upload OK, duplicate → 409
0 TS errors, ESLint clean.
2026-10-28 01:24:48 +00:00
Z User
2aa3496a90
feat: Leads Finder discovery + WordPress license validate + file storage
...
3 new PRD features:
1. Leads Finder discovery (PRD §6.2 Stage 1: Discover)
- Real SerpAPI integration (Google Maps local search)
- Real Tavily integration (web search API)
- Real Firecrawl integration (search + scrape)
- Returns company name, website, address, phone, description
- API key required (503 with hint if not configured)
- Rate limited, Zod validated, audit-logged
- POST /api/aos/leads/discover
2. WordPress-compatible license validation (PRD §6.4)
- POST /api/aos/licenses/validate
- WordPress plugin updater response format
- Domain auto-activation with max check
- Offline grace period (14 day default, configurable)
- Status checks: active/suspended/expired/revoked
- Rate limited (30/min), Zod validated, audit-logged
- Tested: active→valid✓, invalid→404, expired→403, suspended→403
3. Content-addressed file storage (PRD §5.5)
- src/lib/storage.ts
- SHA-256 hash addressing with sharded dirs (first 2 chars)
- Atomic writes (temp file → rename)
- Hash verified on read (tamper detection)
- Deduplication (same content = same hash = one file)
- Content type detection from magic numbers (PDF, PNG, JPEG, GIF, WebP, ZIP)
- storeFile(), readFile(), fileExists(), deleteFile()
0 TS errors, ESLint clean.
2026-10-27 23:49:25 +00:00
Z User
e45b68bb8b
feat: IMAP mail sync with thread-to-contact matching (PRD §6.1)
...
Real IMAP connection via imapflow library:
- Connects to IMAP server (IMAPFlow, TLS on port 993)
- Fetches recent messages (configurable limit, default 20)
- Extracts: from, fromEmail, subject, date, snippet (200 chars)
- Thread-to-contact matching (PRD §6.1):
1. Match sender email against persons table
2. If no person match, extract domain and match against company.website
3. Returns matchedCompany + matchedPerson for each email
- Audit-logged (action: crm.mailsync:imap)
- Zod validated (host, port, user, password, folder, limit)
- 502 on IMAP connection failure with detail
- 400 on validation failure
Tested: invalid creds → 502 'IMAP connection failed', missing host → 400
2026-10-27 22:50:50 +00:00
Z User
7acc0c5451
chore: sync files after PRD gap fixes (Zod, rate-limit, custom-fields, CSP, boundary)
...
5 PRD gaps fixed:
1. Zod validation on all API inputs (§5.2) — 26 files, 27 safeParse
2. Rate limiting on public endpoints (§5.6) — 6 scopes, 7 endpoints
3. Custom fields JSONB with schema (§5.5) — 2 models, 10 seed defs
4. CSP + security headers (§5.6) — 7 headers via next.config.ts
5. ESLint module boundary rule (§5.4) — no-restricted-imports
0 TS errors, ESLint clean.
2026-10-27 22:48:01 +00:00
Z User
f942c65e0d
feat: ESLint module boundary rule (PRD §5.4)
...
Enforced module boundaries via no-restricted-imports:
(a) Views must not import other views directly (use shared primitives)
(b) Infrastructure code must not import UI views
(c) Portal-shell is isolated from agency views
Pattern from Haben: strict module separation, cross-module access only via index.ts
2026-10-27 22:21:30 +00:00
Z User
9bf94ee79a
feat: CSP + security headers (PRD §5.6)
...
next.config.ts headers():
- Content-Security-Policy: default-src 'self', frame-ancestors 'none', form-action 'self'
- X-Content-Type-Options: nosniff
- X-Frame-Options: DENY (clickjacking prevention)
- Referrer-Policy: strict-origin-when-cross-origin
- Permissions-Policy: camera/microphone/geolocation/payment disabled
- Strict-Transport-Security: HSTS 2 years + preload
- API routes: Cache-Control no-store (PRD: 'no-store on private files')
Verified: all 7 security headers present on every page + API response.
2026-10-27 22:20:26 +00:00
Z User
81acd9df7a
feat: Custom fields — JSONB with schema per entity (PRD §5.5)
...
Models: CustomFieldDef (schema definitions) + CustomFieldValue (entity values)
- Per entity type: company, person, deal, project, invoice, ticket, contract
- Field types: string, number, boolean, date, select, multiselect
- Options for select/multiselect stored as JSON
- Unique constraint: (entityType, key) for definitions, (entityType, entityId, fieldDefId) for values
API /api/aos/custom-fields:
- GET: list all definitions (+ filter by entityType)
- POST: create definition (Zod validated, lowercase_snake_case key, unique check)
- PATCH: set value on entity (upsert pattern)
Seed: 10 field definitions across 6 entity types
- company: branche, mitarbeiterzahl, umsatzklasse
- person: entscheider, kontaktweg
- deal: wettbewerber, entscheidungsgrund
- project: prioritaet
- invoice: kostenstelle
- ticket: auswirkung
Verified: 10 defs, 3 company fields, duplicate→409, invalid key→400
2026-10-27 22:19:25 +00:00
Z User
d5dc2a1832
feat: Rate limiting on all public endpoints (PRD §5.6)
...
In-memory rate limiter with configurable limits per scope:
- auth: 5 req/min (login, passkey — future)
- public: 20 req/min (setup mail test, public forms)
- api: 100 req/min (public REST API v1)
- license: 30 req/min (license validate/activate — future)
- mcp: 60 req/min (MCP server)
- webhook: 10 req/min (webhook test trigger)
Applied to 7 endpoints:
- /api/mcp (MCP JSON-RPC — 60/min)
- /api/v1/companies (public REST — 100/min)
- /api/v1/invoices (public REST — 100/min)
- /api/v1/licenses (public REST — 100/min)
- /api/v1/webhooks/test (webhook test — 10/min)
- /api/aos/setup/test-mail (public form — 20/min)
429 response with Retry-After + X-RateLimit headers.
Recreated /api/v1/webhooks/test/route.ts (lost in git merge).
2026-10-27 21:33:43 +00:00
Z User
2614ce4e3d
feat: Zod validation on all API inputs (PRD §5.2)
...
26 files with Zod schemas, 27 safeParse calls.
All POST/PATCH handlers now validate input:
- Missing required fields → 400 with structured error
- Invalid types (string vs number) → 400
- Out-of-range values (probability >100, negative amounts) → 400
- Valid data still works (behavior preserved)
Pattern: schema.safeParse(await req.json()) → 400 on failure
2026-10-27 21:29:51 +00:00
Z User
3d56770669
feat: Docker deployment + backup/restore + README
...
Production deployment (PRD §5.7):
- Dockerfile: multi-stage build (deps → build → runner), healthcheck
- docker-compose.yml: app + backup container + Caddy HTTPS proxy
- Backup container: daily SQLite backup + SHA-256 checksum
- Caddy: automatic HTTPS reverse proxy
- Volumes: db, data, backups, caddy-data
- deploy/backup.sh: timestamped backup + checksum + retention cleanup
- deploy/restore.sh: checksum verification + pre-restore backup
- README.md: quick start (Docker + dev), architecture, modules, compliance, MCP
Verified:
- Backup script: creates aos_20261027.db + .sha256 ✓
- TypeScript: 0 errors, ESLint clean
2026-10-27 20:55:09 +00:00
Z User
01be2e7820
docs: Complete CLAUDE.md with 29-tool MCP reference + usage examples
...
Final project status:
- 328 files, 26.357 lines of code
- 23 views + client portal (5 tabs)
- 69 API routes (30 AOS + 5 public v1 + 1 MCP + 1 health + 32 nested)
- 39 Prisma models
- 29 MCP tools (16 read + 13 write) for Claude Code
- 0 TypeScript errors, ESLint clean
- All 30 AOS endpoints + 6 public endpoints returning correct status codes
- Health endpoint: ok, DB connected
2026-10-27 20:49:50 +00:00
Z User
8eb435fff4
594213c8-60c3-4a3a-b1d7-2256b4af66ea
2026-10-27 20:46:57 +00:00
Z User
97426e0ca8
feat: 29 MCP tools — full agency read+write coverage
...
5 new MCP read tools (29 total: 16 read + 13 write):
- get_contracts: Verträge (AVV, NDA, SLA, Werkvertrag) with status + value
- get_projects: Projects with progress, budget, task/time counts
- get_timesheet: Weekly timesheet grid with lock status
- get_notifications: All alerts (overdue invoices, expiring licenses, SLA breaches)
- get_calendar: Upcoming deadlines (30-day look-ahead across all modules)
Claude Code can now read:
companies, pipeline, invoices, leads, dashboard, tickets, buchhaltung,
anlagen, kassenbuch, belege, finanzamt, contracts, projects, timesheet,
notifications, calendar (16 read tools)
And write:
approve lead, create ticket/deal/task/invoice/buchung/beleg/pauschale/kassenbuch,
log time, finalize invoice, run recurring, update deal stage (13 write tools)
All 29 tools tested and verified working.
2026-10-27 20:46:31 +00:00
Z User
9c226c471c
feat: 24 MCP tools (full accounting write) + Copilot instructions
...
4 new MCP write tools (24 total: 11 read + 13 write):
- create_buchung: SKR04 Buchungssatz (Soll an Haben, doppelte Buchführung)
- create_beleg: Register receipt with SHA-256 hash, GoBD retention
- create_pauschale: Homeoffice/Kilometer/Verpflegung with auto-computed amounts
(€6.92/day, €0.30/km, €14/€24/€28 per EStG)
- create_kassenbuch_entry: Cash book entry (§ 146 AO, immutable, running balance)
Added .github/copilot-instructions.md
Fixed TypeScript strict-mode issues with MCP args type safety
Claude Code can now:
- Read: companies, pipeline, invoices, leads, dashboard, tickets, buchhaltung, anlagen, kassenbuch, belege, finanzamt
- Write: deals, tasks, time, invoices (+ finalize), recurring, leads (approve), tickets, buchungen, belege, pauschalen, kassenbuch
2026-10-27 20:30:16 +00:00
Z User
ab9fd10b5e
feat: Claude Code auto-detect (.mcp.json) + 20 MCP tools + health endpoint
...
Claude Code integration:
- .mcp.json at repo root for auto-detection (uses seed admin token)
- CLAUDE.md project instructions (commands, architecture, rules)
- Pre-seeded admin token: aos_admin_seed_token_for_claude_code_2026
- Scopes: all read + all write + mcp:read + mcp:write
- Works out of the box after bun run src/lib/seed.ts
5 new MCP read tools (20 total: 11 read + 9 write):
- get_buchhaltung: SKR04 Konten, Journal, Saldenliste, EÜR summary
- get_anlagen: Anlagenverzeichnis with AfA, book values, GWG
- get_kassenbuch: Cash book entries, running balance
- get_belege: Receipts with SHA-256 content hashes
- get_finanzamt: VAT returns, Jahreserklärungen, Jahresarchive
Fix: api-auth regex updated to allow underscores in tokens (aos_[a-z0-9_]+)
Health endpoint: GET /api/health (DB connection + version + uptime)
2026-10-27 20:23:50 +00:00
Z User
1a3241971c
dd04e5e9-8a88-45d0-b3b8-14caa1f684dc
2026-10-27 19:51:03 +00:00
Z User
7142ffbe6c
feat: MCP admin-level tools — Claude Code can manage the full agency
...
7 new WRITE MCP tools (15 total):
- create_deal: create deals with value, stage, probability
- update_deal_stage: move deals through the pipeline
- create_task: create tasks with priority, assignee, estimate
- log_time: log billable time entries with rate
- create_invoice: create draft invoices with line items
- finalize_invoice: lock + set to sent (GoBD Festschreibung)
- run_recurring: trigger recurring invoice scheduler + license suspend
Added scopes: crm.deal:write, finance.invoice:write, finance:write, projects:write
Claude Code with an admin token can now:
- Search companies, view pipeline, check invoices (read)
- Create deals, tasks, log time, create+finalize invoices (write)
- Run the recurring scheduler (admin)
- Approve leads, create tickets (existing write tools)
All actions audit-logged with actor 'mcp-agent'
2026-10-27 19:50:43 +00:00
Z User
01214ac5db
fix: Remove agency-internal details from onboarding (company secret)
...
Onboarding overlay:
- Removed '20 Module · 21 API-Endpunkte · MCP-Server · Client-Portal'
- Removed '8 MCP Tools · HMAC-signed Webhooks · OpenAPI 3.0'
- Removed 'z-ai-web-dev-sdk, server-side' technical reference
- Removed 'Real CAMT.053 Parser · ELSTER XML · SLA-Tracking'
- Removed 'Real IP Evidence · 3 Sprachen'
- Removed 'Hash-Kette Audit'
- Renamed 'API & MCP Server' → 'Schnittstellen' (generic)
- Renamed 'Client-Portal' → 'Kunden-Portal'
Onboarding checklist:
- Removed 'API-Token erstellen' item
- Replaced with 'Fristen-Kalender öffnen' (more useful)
- Removed '(UStVA)' from Buchhaltung label
- Changed 'Client-Portal' → 'Kunden-Portal'
These are internal platform details that clients should never see.
2026-10-27 19:23:49 +00:00
Z User
7f7f364183
93dd2eec-4a55-4753-8474-c1bbde1564e9
2026-10-27 18:52:56 +00:00
Z User
07147a758c
feat: DATEV Export (EXTF v5.0) + iCal Fristen feed + UI buttons
...
DATEV Export:
- Real DATEV EXTF Buchungsstapel format (v700, semicolon-separated)
- Header line with metadata (consultant, client, year, currency)
- Data rows: Soll, Haben, Betrag, Belegdatum, Text, Belegnr, USt%
- Also supports simple CSV format
- Audit-logged
- Download button in SKR04/Buchführung tab
iCal Fristen Feed:
- Real .ics calendar feed (RFC 5545 compliant)
- Aggregates ALL deadlines: UStVA, contracts, licenses, assets, projects, invoices
- 23 events from 6 modules
- Subscribe via webcal:// URL in Apple/Google/Outlook Calendar
- Download button in SKR04/Buchführung tab
0 TypeScript errors, ESLint clean
2026-10-27 18:51:55 +00:00
Z User
c184513b2a
cc9d365d-6d71-4dbc-b48a-6bea87eb9854
2026-10-27 18:14:17 +00:00
Z User
6cbf0b2879
feat: Full company accounting — SKR04, doppelte Buchführung, GoBD Festschreibung
...
Haben-cloned features for complete company accounting:
SKR04 Kontenrahmen (21 Konten):
- Bestandskonten (Aktiv/Passiv): Bank, Kasse, EDV-Anlagen, Verbindlichkeiten
- Erlöskonten: Erlöse 19% USt, Fremdleistungen
- Aufwandskonten: Bezogene Leistungen, Bürobedarf, EDV-Kosten, Reisekosten, Löhne
- Steuerkonten: USt 19%/7%, abziehbare Vorsteuer
Doppelte Buchführung (Buchungssatz):
- Soll an Haben booking system
- Journal with lückenlose Nummerierung (BUC-2026-XXXX)
- Saldenliste (account balances per Konto)
- GoBD Festschreibung (immutable via SHA-256 hash)
- Reverse Charge and §19 UStG (Kleinunternehmer) flags
EÜR (Einnahmen-Überschuss-Rechnung):
- Anlage EÜR with AVEÜR line numbers
- § 4 Abs. 3 EStG computation
- Gewinn: €14.506 (2026)
Jahresabschluss (GoBD):
- Immutable year-end archive with SHA-256 hash chain
- Links to previous year (2025 → 2026)
- Festschreibung of all bookings in the year
- Aufbewahrungsfrist: 8 Jahre (GoBD) / 10 Jahre (§ 147 AO)
Jahreserklärungen:
- USt-Erklärung (yearly, more lines than monthly UStVA)
- Anlage EÜR, Einkommensteuer, Gewerbesteuer
- ELSTER submission tracking
Seed: 21 Konten, 7 Buchungssätze, 9 EÜR entries, 2 Jahreserklärungen, 1 Jahresarchiv
2026-10-27 18:13:04 +00:00
Z User
0d0fa6b5e1
bbb245ef-c23d-4d22-87ba-d5366d9def16
2026-10-27 17:41:53 +00:00
Z User
1573931c0f
feat: Haben-clone + client portal privacy fix
...
Client Portal privacy (şirket sırrı):
- Removed PRD references from client-facing text
- Removed 'Projekt-isolierter Zugriff' technical term
- Changed to 'Sichere Verbindung' / 'Sicher geschützt'
- Onboarding overlay only shows to agency users (not portal)
Haben-cloned features (Almanya/EU muhasebe uyumu):
- Belege: content-addressed receipts (SHA-256 hash, GoBD retention 8/6 years)
- Pauschalen: Homeoffice (€6.92/day), Kilometer (€0.30/km), Verpflegung (€14/€24/€28)
- EStG § 4 Abs. 5, § 9 Abs. 1 compliant rates (2026)
- Anlagen & AfA: Anlagenverzeichnis with linear depreciation
- GWG (≤€800 Sofortabschreibung, § 6 Abs. 2 EStG)
- Sammelposten (€251-€1000, § 6 Abs. 2a EStG, 5 years)
- Annual AfA computation + accumulated AfA + book value
- Kassenbuch: cash book (§ 146 AO, § 22 UStG)
- Immutable (GoBD), running balance, audit-logged
- Gapless numbering (KAS-2026-XXXX)
Seed data: 5 Belege, 7 Pauschalen, 5 Anlagen, 5 Kassenbuch entries
TypeScript: 0 errors | ESLint: clean
2026-10-27 17:40:47 +00:00
Z User
3cb7532417
d7b304d4-c8e0-431e-b1b1-fcc645d323e1
2026-10-27 17:15:56 +00:00
Z User
49377bb2de
feat: CSV Import for CRM (PRD §6.1: CSV import/export with mapping)
...
- Real RFC 4180 CSV parser (handles quoted fields, escaped quotes, newlines)
- 3-step import dialog: upload → map columns → result
- Column auto-detection (name/firma/company)
- Duplicate detection (name + website)
- Creates companies + optional persons
- Import audit-logged
- Result summary: created, skipped, errors
2026-10-27 17:15:00 +00:00
Z User
25451d77eb
f2b43822-37b9-490c-b8bb-0888d61227a3
2026-10-27 16:53:07 +00:00
Z User
597bfbc3d8
feat: Recurring invoices + license suspend on dunning level 3 (PRD §6.4/§6.6)
...
- Recurring API: list contracts needing invoicing + run endpoint
- Auto-generate draft invoices for Wartung/SLA + Dienstvertrag contracts
- Automatic license suspension at dunning level 3 (PRD §6.4)
- Recurring billable expenses tracking
- MRR/ARR computation from contracts + expenses
- Prisma: added Contract.company + Expense.company relations
- Scheduler info (pg-boss monthly cron in production)
2026-10-27 16:51:58 +00:00