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
fatmacetin and Claude Code
f5b1593e46
chore: align Dockerfile to node:24 (matches engines pin), add openssl for prisma
...
Co-Authored-By: Claude Code <noreply@anthropic.com >
2026-10-28 21:28:57 +01:00
fatmacetin and Claude Code
f0bdf185d5
fix: pin prisma CLI in image, force NODE_ENV=production at runtime
...
Deploy platform injects NODE_ENV=development; CMD now overrides it.
Global prisma@6.19 .2 removes the npx download on every container start.
Co-Authored-By: Claude Code <noreply@anthropic.com >
2026-10-28 21:15:41 +01:00
fatmacetin and Claude Code
5871606ae6
chore: trigger redeploy with dockerfile build
...
Co-Authored-By: Claude Code <noreply@anthropic.com >
2026-10-28 21:05:59 +01:00
fatmacetin and Claude Code
c632751a7e
fix: pin node 24 + bun 1.3 for railpack — node 26 broke /_global-error prerender
...
Co-Authored-By: Claude Code <noreply@anthropic.com >
2026-10-28 20:53:29 +01: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