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ı
This commit is contained in:
egecankomur
2026-05-05 04:37:04 +03:00
commit 37679e83e6
383 changed files with 53525 additions and 0 deletions
+43
View File
@@ -0,0 +1,43 @@
import "server-only";
import { headers } from "next/headers";
import { ID, Permission, Role } from "node-appwrite";
import { createAdminClient } from "./server";
import { DATABASE_ID, TABLES, type AuditAction } from "./schema";
export async function logAudit(args: {
tenantId: string;
userId: string;
action: AuditAction;
entityType: string;
entityId: string;
changes?: Record<string, unknown>;
}) {
try {
const h = await headers();
const ipAddress =
h.get("x-forwarded-for")?.split(",")[0]?.trim() || h.get("x-real-ip") || undefined;
const userAgent = h.get("user-agent")?.slice(0, 500) || undefined;
const { tablesDB } = createAdminClient();
await tablesDB.createRow(
DATABASE_ID,
TABLES.auditLogs,
ID.unique(),
{
tenantId: args.tenantId,
userId: args.userId,
action: args.action,
entityType: args.entityType,
entityId: args.entityId,
changes: args.changes ? JSON.stringify(args.changes).slice(0, 10000) : undefined,
ipAddress,
userAgent,
},
[Permission.read(Role.team(args.tenantId))],
);
} catch {
// audit failures must never block the user-facing operation
}
}