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
+63
View File
@@ -0,0 +1,63 @@
import "server-only";
import { validateEvent, WebhookVerificationError } from "@polar-sh/sdk/webhooks";
const POLAR_API_BASE = "https://api.polar.sh";
const ACCESS_TOKEN = process.env.POLAR_ACCESS_TOKEN ?? "";
const WEBHOOK_SECRET = process.env.POLAR_WEBHOOK_SECRET ?? "";
export const POLAR_PRODUCT_ID = process.env.POLAR_PRODUCT_ID ?? "";
export function isPolarEnabled(): boolean {
return (
process.env.PAYMENT_PROVIDER === "polar" &&
Boolean(ACCESS_TOKEN) &&
Boolean(POLAR_PRODUCT_ID)
);
}
export type PolarCheckout = {
id: string;
url: string;
};
export async function createPolarCheckout(params: {
orderId: string;
tenantId: string;
userEmail: string;
successUrl: string;
}): Promise<PolarCheckout> {
const res = await fetch(`${POLAR_API_BASE}/v1/checkouts/`, {
method: "POST",
headers: {
Authorization: `Bearer ${ACCESS_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
products: [POLAR_PRODUCT_ID],
customer_email: params.userEmail,
success_url: params.successUrl,
return_url: params.successUrl,
metadata: {
crm_order_id: params.orderId,
tenant_id: params.tenantId,
},
}),
});
if (!res.ok) {
const text = await res.text();
throw new Error(`Polar checkout oluşturulamadı: ${text}`);
}
return res.json() as Promise<PolarCheckout>;
}
// Polar resmi SDK ile webhook doğrulama ve parse
// Hata fırlatırsa imza geçersiz demektir
export function verifyAndParsePolarWebhook(
headers: Record<string, string>,
rawBody: string,
): ReturnType<typeof validateEvent> {
return validateEvent(rawBody, headers, WEBHOOK_SECRET);
}