Commit Graph

5 Commits

Author SHA1 Message Date
kovakmedya 12631cf9c5 perf+fix: file download proxy + drop awaits on audit/notifications/finance sync
Two problems reported by the user:

1. File downloads broken on the lab side.
   The link in JobFilesPanel pointed straight at Appwrite's
   /storage/.../view URL. Storage permissions are scoped to the job's two
   teams, but the browser only has a session cookie for our app domain,
   not for db.kovaksoft.com — so the cross-origin request hit Appwrite
   as a guest and 401'd.

   New /api/jobs/[jobId]/files/[fileId]/download route. requireTenant()
   first, then verify the caller's tenant is one of (clinicTenantId,
   labTenantId) on the parent job, then storage.getFileDownload via the
   admin SDK and stream the buffer back with Content-Disposition:
   attachment so the browser saves it under the original filename.
   listJobFiles now hands out that relative URL instead of the Appwrite
   one — same anchor in the panel, just routed through us.

2. Saves and edits feel slow whenever a notification is involved.
   Every mutation was awaiting logAudit, createNotification and
   syncFinanceForJob in sequence. None of these need to block the user
   response — audit is best-effort logging, notifications are async UX,
   and the finance sync is idempotent and re-runs on the next mutation
   anyway. Switched all 46 call sites across the action modules to
   void-fire-and-forget (matching the pattern we already used in
   clinic-pricing-actions). Net effect: each mutation drops ~3 sequential
   Appwrite roundtrips before the server action returns.
2026-05-22 01:05:25 +03:00
kovakmedya 4186d95447 feat(upload): bump per-file cap to 200MB end-to-end
Cluster: Appwrite container _APP_STORAGE_LIMIT 30000000 → 209715200
  (200MB) in /root/services/appwrite/.env on kovaksoft-coolify, then
  docker compose up -d to roll the worker pool with the new value.
  Backup of the .env left at .env.bak.<date>.

Bucket: job-files maximumFileSize updated to 209715200 via Appwrite MCP
  (storage_update_bucket).

App: MAX_FILE_BYTES in both the upload API route and the original server
  action raised to 200MB. Client-side panel guard relaxed accordingly —
  one large file is now allowed to fill the entire batch (the 200MB
  proxy/serverActions cap is the bottleneck, not the per-file rule).
  Error copy updated.

isletmem and any other tenants on the cluster also get the new limit,
which is the desired behaviour — old 30MB ceiling was a relic of an
Appwrite default that no DLS workflow can actually live with.
2026-05-21 21:24:11 +03:00
kovakmedya 6b1b44502a fix(upload): convert File to Buffer via InputFile.fromBuffer before sending to storage.createFile
node-appwrite's storage.createFile happily takes the Web File API today,
but Next.js's multipart parser had already consumed the request body by
the time the SDK tries to stream it again — the SDK's second pass dies
with 'Unexpected end of form'. isletmem-kovakcrm's logo-actions uses the
documented pattern: arrayBuffer → Buffer → InputFile.fromBuffer(buf,
name). Adopting the same approach in uploadJobFilesAction.

The middlewareClientMaxBodySize bump from the previous commit still
matters (lifts the 10MB cap so the body even reaches us), but on its own
it wasn't enough: the Web File handoff itself was broken.

InputFile is exported from 'node-appwrite/file' (separate entry point —
the helper isn't on the main package export).
2026-05-21 21:08:26 +03:00
kovakmedya 2bf130105e fix(upload): bump middlewareClientMaxBodySize to 100mb
Next 16 caps any request body that flows through middleware at 10MB by
default. Our auth middleware matches every path, so /jobs/:id POSTs from
the file upload form hit 'Request body exceeded 10MB / Unexpected end of
form' the moment a user picked anything bigger than ~10MB total — the
server action never even ran.

serverActions.bodySizeLimit alone isn't enough; the new
middlewareClientMaxBodySize knob (Next 16) is the one that gates
middleware-handled bodies. Set both to 100mb so the 30MB-per-file bucket
limit is what actually matters.

The key isn't in NextConfig's TS types yet (Next 16.1), so it's assigned
via a narrow cast on the side rather than dropped into the object literal.

Also added console.log/error breadcrumbs to uploadJobFilesAction so the
next mystery upload failure shows up in the dev server log immediately
instead of silently bouncing back as 'Bağlantı hatası'.
2026-05-21 21:05:33 +03:00
kovakmedya 2c6c074a06 feat: job status/step flow, file upload, finance sync, notifications
Job lifecycle
  - acceptJobAction (lab): pending → in_progress + currentStep=olcu
  - advanceStepAction (lab): step ilerletir, son adım sonrası status=sent
  - markDeliveredAction (clinic): sent → delivered
  - cancelJobAction: pending iş iptali (her iki taraf)
  - job_status_history her step transition'da idempotent kayıt
  - Detay sayfası interactive panel + Aşama Geçmişi kartı

Job files (Appwrite Storage job-files bucket, 30MB/file)
  - uploadJobFilesAction: çoklu dosya, mimeType'tan kind sınıflandırma
    (scan/image/document), her iki team'e read permission, partial-fail
    rollback (storage + row temizliği)
  - deleteJobFileAction: yetkilendirilmiş silme, file + row birlikte
  - JobFilesPanel: client-side select + upload + liste + indir + sil
  - next.config bodySizeLimit 3mb → 100mb (toplu yükleme için)

Finance sync (idempotent)
  - syncFinanceForJob helper: sent/delivered transition'larında klinik
    payable + lab receivable rows (jobId+tenantId+type unique kontrolü,
    her tarafta tek satır garanti)
  - markFinancePaidAction / reopenFinanceAction: manuel ödendi/geri al
  - /finance sayfası: stat kartlar (bekleyen alacak/borç, aylık gelir/gider)
    + hareketler tablosu, role-aware kopyalar
  - Memory rule [[feedback_cross_entity_sync_helpers]]: best-effort, never
    re-throws

Notifications
  - createNotification helper, connection (request/approve) ve job
    (create/accept/sent/delivered) eventlerinde tetikleniyor
  - /notifications sayfası + tek tek / hepsi okundu işaretle
  - Header'a Bell ikonu + okunmamış count badge (layout SSR'de besler)
  - Middleware PROTECTED_PREFIXES'e /notifications ekli
2026-05-21 20:17:33 +03:00