Commit Graph
100 Commits
Author SHA1 Message Date
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
Z User c8b4be55f3 e558113a-99ae-4e5a-9db1-dcd3475a4e04 2026-10-27 16:28:08 +00:00
Z User 6c42c6525a feat: Data Management (DSGVO Art. 15/20/30 — export, inventory, retention)
- Data Management API: inventory (Art. 30 Verarbeitungsverzeichnis) + export
- JSON export with SHA-256 checksum (GoBD Jahresarchiv)
- CSV export (DATEV/Excel-compatible)
- Export history (audit-logged)
- Retention periods (8/6 years per GoBD)
- Art. 17 erasure notice (pseudonymization, legal precedence)
- 159 records across 10 categories with legal basis per category
2026-10-27 16:27:42 +00:00
Z User 1dd2563172 Merge branch 'main' of https://github.com/cetinmustafa83/aos
# Conflicts:
#	.env
#	.gitignore
#	Caddyfile
#	bun.lock
#	components.json
#	db/custom.db
#	eslint.config.mjs
#	next.config.ts
#	package.json
#	postcss.config.mjs
#	prisma/schema.prisma
#	public/logo.svg
#	public/manifest.json
#	public/robots.txt
#	src/app/api/aos/accounting/bank/[id]/match/route.ts
#	src/app/api/aos/accounting/bank/import/route.ts
#	src/app/api/aos/accounting/route.ts
#	src/app/api/aos/accounting/vat/[id]/submit/route.ts
#	src/app/api/aos/api-tokens/[id]/revoke/route.ts
#	src/app/api/aos/api-tokens/route.ts
#	src/app/api/aos/audit/route.ts
#	src/app/api/aos/calendar/route.ts
#	src/app/api/aos/contracts/[id]/sign/route.ts
#	src/app/api/aos/contracts/route.ts
#	src/app/api/aos/crm/companies/[id]/route.ts
#	src/app/api/aos/crm/deals/route.ts
#	src/app/api/aos/crm/route.ts
#	src/app/api/aos/dashboard/route.ts
#	src/app/api/aos/estimates/[id]/accept/route.ts
#	src/app/api/aos/estimates/[id]/convert/route.ts
#	src/app/api/aos/estimates/route.ts
#	src/app/api/aos/expenses/[id]/convert/route.ts
#	src/app/api/aos/expenses/route.ts
#	src/app/api/aos/finance/[id]/finalize/route.ts
#	src/app/api/aos/finance/route.ts
#	src/app/api/aos/kb/generate/route.ts
#	src/app/api/aos/kb/route.ts
#	src/app/api/aos/leads/[id]/route.ts
#	src/app/api/aos/leads/convert/route.ts
#	src/app/api/aos/leads/explain/route.ts
#	src/app/api/aos/leads/route.ts
#	src/app/api/aos/licenses/route.ts
#	src/app/api/aos/modules/route.ts
#	src/app/api/aos/notifications/route.ts
#	src/app/api/aos/portal/approvals/[id]/decide/route.ts
#	src/app/api/aos/portal/companies/[id]/notifications/route.ts
#	src/app/api/aos/portal/companies/[id]/route.ts
#	src/app/api/aos/portal/companies/route.ts
#	src/app/api/aos/projects/[id]/tasks/route.ts
#	src/app/api/aos/projects/[id]/time/route.ts
#	src/app/api/aos/projects/route.ts
#	src/app/api/aos/reporting/route.ts
#	src/app/api/aos/search/route.ts
#	src/app/api/aos/seed/route.ts
#	src/app/api/aos/settings/route.ts
#	src/app/api/aos/setup/test-mail/route.ts
#	src/app/api/aos/tasks/[id]/comments/route.ts
#	src/app/api/aos/tickets/[id]/reply/route.ts
#	src/app/api/aos/tickets/[id]/summarize/route.ts
#	src/app/api/aos/tickets/route.ts
#	src/app/api/aos/timesheet/route.ts
#	src/app/api/aos/webhooks/route.ts
#	src/app/api/mcp/route.ts
#	src/app/api/route.ts
#	src/app/api/v1/companies/route.ts
#	src/app/api/v1/invoices/route.ts
#	src/app/api/v1/licenses/route.ts
#	src/app/api/v1/openapi/route.ts
#	src/app/globals.css
#	src/app/layout.tsx
#	src/app/page.tsx
#	src/components/aos/app-shell.tsx
#	src/components/aos/command-menu.tsx
#	src/components/aos/company-drawer.tsx
#	src/components/aos/create-deal-dialog.tsx
#	src/components/aos/footer.tsx
#	src/components/aos/invoice-dialog.tsx
#	src/components/aos/locale-switcher.tsx
#	src/components/aos/mobile-bottom-nav.tsx
#	src/components/aos/notifications-bell.tsx
#	src/components/aos/onboarding-checklist.tsx
#	src/components/aos/onboarding-overlay.tsx
#	src/components/aos/portal-shell.tsx
#	src/components/aos/primitives.tsx
#	src/components/aos/sidebar-nav.tsx
#	src/components/aos/top-bar.tsx
#	src/components/aos/views/accounting.tsx
#	src/components/aos/views/api.tsx
#	src/components/aos/views/audit.tsx
#	src/components/aos/views/calendar.tsx
#	src/components/aos/views/contracts.tsx
#	src/components/aos/views/crm.tsx
#	src/components/aos/views/dashboard.tsx
#	src/components/aos/views/estimates.tsx
#	src/components/aos/views/expenses.tsx
#	src/components/aos/views/finance.tsx
#	src/components/aos/views/global-settings.tsx
#	src/components/aos/views/kb.tsx
#	src/components/aos/views/leads.tsx
#	src/components/aos/views/licenses.tsx
#	src/components/aos/views/projects.tsx
#	src/components/aos/views/reporting.tsx
#	src/components/aos/views/settings.tsx
#	src/components/aos/views/setup-wizard.tsx
#	src/components/aos/views/support.tsx
#	src/components/aos/views/timesheet.tsx
#	src/components/theme-provider.tsx
#	src/components/theme-toggle.tsx
#	src/components/ui/accordion.tsx
#	src/components/ui/alert-dialog.tsx
#	src/components/ui/alert.tsx
#	src/components/ui/aspect-ratio.tsx
#	src/components/ui/avatar.tsx
#	src/components/ui/badge.tsx
#	src/components/ui/breadcrumb.tsx
#	src/components/ui/button.tsx
#	src/components/ui/calendar.tsx
#	src/components/ui/card.tsx
#	src/components/ui/carousel.tsx
#	src/components/ui/chart.tsx
#	src/components/ui/checkbox.tsx
#	src/components/ui/collapsible.tsx
#	src/components/ui/command.tsx
#	src/components/ui/context-menu.tsx
#	src/components/ui/dialog.tsx
#	src/components/ui/drawer.tsx
#	src/components/ui/dropdown-menu.tsx
#	src/components/ui/form.tsx
#	src/components/ui/hover-card.tsx
#	src/components/ui/input-otp.tsx
#	src/components/ui/input.tsx
#	src/components/ui/label.tsx
#	src/components/ui/menubar.tsx
#	src/components/ui/navigation-menu.tsx
#	src/components/ui/pagination.tsx
#	src/components/ui/popover.tsx
#	src/components/ui/progress.tsx
#	src/components/ui/radio-group.tsx
#	src/components/ui/resizable.tsx
#	src/components/ui/scroll-area.tsx
#	src/components/ui/select.tsx
#	src/components/ui/separator.tsx
#	src/components/ui/sheet.tsx
#	src/components/ui/sidebar.tsx
#	src/components/ui/skeleton.tsx
#	src/components/ui/slider.tsx
#	src/components/ui/sonner.tsx
#	src/components/ui/switch.tsx
#	src/components/ui/table.tsx
#	src/components/ui/tabs.tsx
#	src/components/ui/textarea.tsx
#	src/components/ui/toast.tsx
#	src/components/ui/toaster.tsx
#	src/components/ui/toggle-group.tsx
#	src/components/ui/toggle.tsx
#	src/components/ui/tooltip.tsx
#	src/hooks/use-fetch.ts
#	src/hooks/use-i18n.ts
#	src/hooks/use-mobile.ts
#	src/hooks/use-toast.ts
#	src/lib/api-auth.ts
#	src/lib/db.ts
#	src/lib/format.ts
#	src/lib/i18n.ts
#	src/lib/seed.ts
#	src/lib/utils.ts
#	src/lib/webhook.ts
#	src/store/aos.ts
#	tailwind.config.ts
#	tsconfig.json
2026-10-27 12:24:25 +00:00
Z User fa8dd46571 refactor: professional code quality audit
- Fix all TypeScript compilation errors (0 errors in src/)
- Add try/catch error handling to ALL API routes (38 handlers)
- Fix empty catch blocks (api-auth.ts now logs warnings)
- Add aria-labels to all icon-only buttons (WCAG 2.1 AA)
- Fix Prisma type mismatches (OR filter, Person.companyId, Estimate.projectId, Ticket.createdAt)
- Fix webhook PATCH route (moved to [id]/route.ts)
- Fix mobile-bottom-nav type safety
- Fix KB route where-clause type
- Fix test-mail banner null vs undefined
- Fix task comment fetch: add cancellation + error toast
- ESLint: 0 errors, 0 warnings
- 175 files, 24.741 lines of code
2026-10-27 12:23:32 +00:00
Z User 969202764a Initial commit 2026-10-27 06:25:53 +00:00