Commit Graph

20 Commits

Author SHA1 Message Date
egecankomur 7c23a2b4ae feat: activity assignment + team view for owner/admin
db: activities.assigneeId column (string, optional)

activity-actions: assigneeId saved on create (default: self), cleared on update
validation: assigneeId added to activitySchema
schema: assigneeId field on Activity type

activity-form-sheet: Atanan Kişi dropdown for owner/admin with member list
activity-team-view: new component — activities grouped by assignee,
  completion/edit/delete actions, overdue indicator, member avatars
activities-client: Ekip tab (owner/admin only), members + currentUserId props
activities page: fetches team memberships + user details, passes to client
activity-email-actions: filter by assigneeId ?? createdBy for both me/team modes
2026-05-12 17:40:21 +03:00
egecankomur 5ac6a1f8b0 feat: daily activity summary email
- activity-email-actions: sendDailySummaryAction — filters today's
  activities by dueDate, sends personalized email via Appwrite Messaging
  - 'me': current user's activities only
  - 'team' (owner/admin): each member gets their own activities separately
- send-summary-dialog: dialog with me/team radio (owner/admin only sees
  team option), inline error + toast on success
- activities-client: 'Günlük Özet' button in header, role prop added
- activities page: passes ctx.role to client
2026-05-12 17:26:50 +03:00
egecankomur fe86bfe6b2 fix: resolve auth/tenant loop and serialization errors
- middleware: remove auth-path→/dashboard redirect; stale session cookies
  caused dashboard→onboarding→sign-in→dashboard infinite loop
- dashboard layout: check getCurrentUser first, redirect to /sign-in
  directly instead of going through /onboarding
- getActiveContext: use admin client (users.listMemberships) for tenant
  resolution instead of session-dependent getUserTeams()
- requireTenant: validate membership before trusting stored tenantId;
  clear stale cookie and re-resolve if user is not a member
- sunum page: JSON.parse/stringify property rows before passing to
  Client Component (Appwrite SDK objects have non-plain prototypes)
2026-05-12 17:18:19 +03:00
egecankomur a3bcb464ea feat: custom password reset flow (token-based, Appwrite Messaging)
- db: new password_resets table (email, userId, tokenHash, expiresAt, usedAt)
- lib: password-reset-actions.ts — requestPasswordResetAction, verifyResetToken, resetPasswordAction
- lib: Messaging added to createAdminClient
- page: /reset-password — validates token server-side, shows form or error card
- page: /forgot-password — now uses requestPasswordResetAction (custom flow)
- page: /sign-in — shows success banner after ?reset=success redirect
2026-05-12 16:49:04 +03:00
egecankomur b71edd880b fix: harden getActiveContext and add error logging on presentations page
- getActiveContext now verifies team still exists (teams.get) before
  trusting the cookie/prefs tenantId, preventing stale E Ofis cookie
  from causing an onboarding redirect loop
- Resolved tenantId from getUserTeams() is now persisted to cookie so
  subsequent requests skip the resolution path
- Added catch+log on presentations data fetch to surface the actual
  error in server logs
2026-05-12 15:33:38 +03:00
egecankomur 84be9ec5e3 fix: auto-create tenant_settings when missing to prevent onboarding loop
- ensureSettings() creates a minimal settings row if one is missing for
  a team the user is already a member of, instead of returning null and
  letting the onboarding redirect fire
- resolveFirstValidTenantId() falls back to any membership when no team
  has settings yet, so new registrations without a completed onboarding
  still land on the correct tenant
- teams.get() is now fetched alongside listMemberships in a single
  Promise.all so the team name is available for the fallback row
2026-05-12 14:19:24 +03:00
egecankomur 3554b39800 feat: desktop image thumbnails, gallery lightbox portal, client-side compression, clickable table rows, fix header gap 2026-05-12 04:49:36 +03:00
egecankomur 3cce632eb3 feat(billing): payment infrastructure pre-prep
db: add plan, planExpiresAt, planProvider to tenant_settings (Appwrite MCP)

- schema.ts: TenantPlan type, TenantSettings plan fields
- subscription-types.ts: Emlak plan catalog (Free / Pro 499₺/ay)
- plan-limits.ts: resource limits (properties/customers/members/presentations)
  + getPlanUsage, requirePlanCapacity, PlanLimitError helpers
- subscription-actions.ts: startCheckoutAction (Polar→Shopier→mock fallback),
  activatePlanInDb / deactivatePlanInDb for webhook handlers,
  downgradeToFreeAction, getCurrentPlanAction
- /api/payments/polar/callback: verify webhook → activatePlanInDb on order/subscription events
- /api/payments/shopier/callback: verify HMAC → activate on fulfilled+paid (tenant
  email-matching TODO pending Shopier metadata support)
- /settings/billing: CurrentPlanCard with usage progress bars + UpgradeSection
- sidebar: Plan & Faturalama nav item
- PlanLimitDialog: Emlak-specific feature list
2026-05-08 15:26:18 +03:00
egecankomur 95a7cbaf0d feat: onboarding'de diğer KovakSoft uygulamalarından workspace içe aktarma 2026-05-06 23:04:26 +03:00
egecankomur 9f462c2f1f fix: filter teams by app — getUserTeams and setActiveTenant now reject cross-app teams 2026-05-06 22:31:58 +03:00
egecankomur 237ec92691 feat: tema ayarları Appwrite user prefs ile kalıcı hale getirildi
- saveThemePrefsAction: account.updatePrefs ile mevcut prefs'i merge eder
- Dashboard layout'ta account.getPrefs ile prefs server-side yüklenir
- PrefsInitializer: mount'ta dark/light, renk teması, radius, sidebar
  config'ini Appwrite'dan gelen initialPrefs ile uygular
- ThemeCustomizer: renk teması / tweakcn / radius / sidebar değişikliği
  anında Appwrite'a kaydedilir; dark/light toggle useEffect ile izlenir
- Sayfa yenileme ve farklı cihazda giriş sonrasında ayarlar korunur
2026-05-05 20:57:30 +03:00
egecankomur 1d5ad5f62f fix: presentation expiresAt — skip empty date, convert YYYY-MM-DD to end-of-day UTC
Empty string sent to Appwrite datetime column was being interpreted as creation
timestamp, making every no-expiry sunum immediately expired. Fix:
- Only include expiresAt in payload when user actually set a date
- Convert date-only string (YYYY-MM-DD) to YYYY-MM-DDT23:59:59.000Z so the
  sunum stays valid for the entire chosen day across all time zones
- Strip empty customerId/notes to avoid empty-string writes
2026-05-05 20:19:02 +03:00
egecankomur d9aff26376 fix: delete stale matches when score drops below threshold or listing type changes
matchPropertyToSearches now:
- scores every search (listing type mismatch = 0 score)
- score >= 20: create or update match
- score < 20 AND existing match: delete stale record

Prevents outdated match records after criteria/weight updates.
2026-05-05 20:03:49 +03:00
egecankomur a40e68254b feat: weighted match scoring, photo upload, property detail page
- scoring.ts: pure scoreMatch + scoreMatchBreakdown with per-criterion weights
- matching.ts: soft scoring (0-100), updates score on re-sync, threshold 20
- search-form-sheet: weight selectors (1-5) per criterion
- customer-search-actions: save/update weight fields
- storage-actions: upload/delete property images to property-images bucket
- storage-utils: getPropertyImagePreviewUrl, parseImageIds helpers
- property-image-uploader: client component with preview grid + delete
- property-form-sheet: integrated image uploader
- properties/[id]: detail page with gallery, specs, matches sidebar
- properties-client: Detay link in dropdown
- matches page: MatchesClient with click-to-breakdown dialog
- sunum page: cover image from first imageIds entry
- matches-client + match-breakdown-dialog: score breakdown per criterion
2026-05-05 19:55:34 +03:00
egecankomur 3d044c5d5b fix: onboarding createWorkspace — emlak fields (officeName/phone/createdBy), remove old CRM fields 2026-05-05 13:24:10 +03:00
egecankomur 19c1ecef47 fix: workspace settings — emlak fields (officeName/phone/email/address), add createdBy to createRow 2026-05-05 13:15:50 +03:00
egecankomur 115e5cd159 fix: lazy env var check in server.ts — prevent module-level throw during Docker build 2026-05-05 12:11:42 +03:00
egecankomur 4ef0482732 feat: all core modules — properties, customers, searches, matches, presentations, activities, investors + public sunum page
- Server actions: property/customer/search/presentation/activity/investor CRUD
- Matching engine: matchPropertyToSearches + syncMatchesForSearch on search save
- UI: form sheets + table clients for all modules
- Public /sunum/[token] page (no auth) with property card grid + expiry check
- All pages force-dynamic for auth guard compatibility
2026-05-05 12:03:48 +03:00
egecankomur 2f17c342ca feat: emlak CRM iskelet kurulumu
- schema.ts tamamen yeniden yazıldı (properties, customers, customer_searches, property_matches, presentations, investors, activities, tenant_settings)
- Sidebar emlak modüllerine güncellendi (İlanlar, Müşteriler, Yatırımcılar, Sunumlar, Aktiviteler)
- Eski CRM lib dosyaları temizlendi (finance, invoice, lead, task, software, vs.)
- Yeni modül dizinleri oluşturuldu (stub pages)
- command-search emlak navigasyonuna güncellendi
- site-header temizlendi
- Typecheck: 0 hata (chart.tsx template hariç)
2026-05-05 11:43:29 +03:00
egecankomur 37679e83e6 init: kovakemlak-crm project scaffold
- Next.js 16 + Appwrite multi-tenant emlak CRM
- Database: kovakemlak-db (properties, customers, customer_searches, property_matches, presentations, investors, activities, tenant_settings)
- Same stack as isletmem-kovakcrm (shadcn/ui template base)
- Modules: portföy, müşteri takibi, arama kriterleri, otomatik eşleştirme, sunum linki, yatırımcı portalı
2026-05-05 04:37:04 +03:00