Initial import: property management SaaS + security hardening + admin dashboard

Property Management Network — Next.js 16 (App Router), Better Auth,
Drizzle ORM over PostgreSQL, Stripe, OpenAI, Resend.

Includes:
- Security hardening: access-control/IDOR fixes, TLS-by-default DB layer,
  constant-time cron auth, strict security headers, atomic AI quota gating,
  HTML/email output encoding, demo-backdoor disabled in production.
- Superadmin dashboard at /admin (overview/MRR, server-paginated users with
  ban/impersonate/plan/delete, billing, platform activity + admin audit log,
  AI usage, system health) via the Better Auth admin plugin.
- Seed/migration utility scripts under scripts/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leon Serfaty
2026-06-23 20:36:07 -04:00
co-authored by Claude Opus 4.8
commit 857b9a7811
291 changed files with 38996 additions and 0 deletions
+9
View File
@@ -0,0 +1,9 @@
import { Resend } from "resend"
// Use a placeholder when no key is configured so the constructor doesn't throw
// at module load (it's imported on the auth path). Sends will fail gracefully
// and are caught in sendEmail().
export const resend = new Resend(process.env.RESEND_API_KEY || "re_placeholder")
export const FROM_EMAIL = process.env.RESEND_FROM_EMAIL ?? "noreply@propertymanagement.network"
export const APP_NAME = process.env.NEXT_PUBLIC_APP_NAME ?? "Property Management Network"
+171
View File
@@ -0,0 +1,171 @@
import { resend, FROM_EMAIL, APP_NAME } from "./client"
function escapeHtml(value: unknown): string {
return String(value ?? "")
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;")
}
interface SendEmailOptions {
to: string
subject: string
html: string
from?: string
}
export async function sendEmail({ to, subject, html, from }: SendEmailOptions) {
const { data, error } = await resend.emails.send({
from: from ?? `${APP_NAME} <${FROM_EMAIL}>`,
to,
subject,
html,
})
if (error) {
console.error("Email send failed:", error)
return { success: false, error }
}
return { success: true, id: data?.id }
}
// ── Email templates ──────────────────────────────────────────────
export function rentDueReminderHtml({
tenantName,
propertyName,
unitNumber,
amount,
dueDate,
paymentLink,
}: {
tenantName: string
propertyName: string
unitNumber: string
amount: string
dueDate: string
paymentLink?: string
}) {
return `
<!DOCTYPE html>
<html>
<body style="font-family: sans-serif; background: #09090b; color: #fff; padding: 40px 20px; max-width: 560px; margin: 0 auto;">
<div style="background: #16161f; border: 1px solid rgba(255,255,255,0.08); border-radius: 12px; padding: 32px;">
<h1 style="font-size: 20px; margin: 0 0 8px; color: #fff;">Rent Due Reminder</h1>
<p style="color: rgba(255,255,255,0.6); margin: 0 0 24px;">Hi ${escapeHtml(tenantName)},</p>
<p style="color: rgba(255,255,255,0.6); margin: 0 0 24px;">
Your rent payment of <strong style="color:#fff">${escapeHtml(amount)}</strong> for
<strong style="color:#fff">${escapeHtml(propertyName)} — Unit ${escapeHtml(unitNumber)}</strong>
is due on <strong style="color:#fff">${escapeHtml(dueDate)}</strong>.
</p>
${paymentLink ? `
<a href="${escapeHtml(paymentLink)}" style="display: inline-block; background: #6366f1; color: #fff; padding: 12px 24px; border-radius: 8px; text-decoration: none; font-weight: 600;">
Pay Rent Now
</a>
` : ""}
<p style="color: rgba(255,255,255,0.4); font-size: 12px; margin: 24px 0 0;">
Property Management Network
</p>
</div>
</body>
</html>`
}
export function rentOverdueHtml({
tenantName,
propertyName,
unitNumber,
amount,
dueDate,
}: {
tenantName: string
propertyName: string
unitNumber: string
amount: string
dueDate: string
}) {
return `
<!DOCTYPE html>
<html>
<body style="font-family: sans-serif; background: #09090b; color: #fff; padding: 40px 20px; max-width: 560px; margin: 0 auto;">
<div style="background: #16161f; border: 1px solid rgba(239,68,68,0.3); border-radius: 12px; padding: 32px;">
<h1 style="font-size: 20px; margin: 0 0 8px; color: #ef4444;">Rent Overdue</h1>
<p style="color: rgba(255,255,255,0.6); margin: 0 0 24px;">Hi ${escapeHtml(tenantName)},</p>
<p style="color: rgba(255,255,255,0.6); margin: 0 0 24px;">
Your rent payment of <strong style="color:#fff">${escapeHtml(amount)}</strong> for
<strong style="color:#fff">${escapeHtml(propertyName)} — Unit ${escapeHtml(unitNumber)}</strong>
was due on <strong style="color:#ef4444">${escapeHtml(dueDate)}</strong> and is now overdue.
Please make payment as soon as possible.
</p>
<p style="color: rgba(255,255,255,0.4); font-size: 12px; margin: 24px 0 0;">
Property Management Network
</p>
</div>
</body>
</html>`
}
export function leaseExpiryHtml({
tenantName,
propertyName,
unitNumber,
leaseEnd,
daysLeft,
}: {
tenantName: string
propertyName: string
unitNumber: string
leaseEnd: string
daysLeft: number
}) {
return `
<!DOCTYPE html>
<html>
<body style="font-family: sans-serif; background: #09090b; color: #fff; padding: 40px 20px; max-width: 560px; margin: 0 auto;">
<div style="background: #16161f; border: 1px solid rgba(245,158,11,0.3); border-radius: 12px; padding: 32px;">
<h1 style="font-size: 20px; margin: 0 0 8px; color: #f59e0b;">Lease Expiring Soon</h1>
<p style="color: rgba(255,255,255,0.6); margin: 0 0 24px;">Hi ${escapeHtml(tenantName)},</p>
<p style="color: rgba(255,255,255,0.6); margin: 0 0 24px;">
Your lease for <strong style="color:#fff">${escapeHtml(propertyName)} — Unit ${escapeHtml(unitNumber)}</strong>
expires on <strong style="color:#f59e0b">${escapeHtml(leaseEnd)}</strong>
(${escapeHtml(daysLeft)} days from now). Please contact your landlord to discuss renewal.
</p>
<p style="color: rgba(255,255,255,0.4); font-size: 12px; margin: 24px 0 0;">
Property Management Network
</p>
</div>
</body>
</html>`
}
export function maintenanceUpdateHtml({
tenantName,
title,
status,
resolutionNotes,
}: {
tenantName: string
title: string
status: string
resolutionNotes?: string
}) {
return `
<!DOCTYPE html>
<html>
<body style="font-family: sans-serif; background: #09090b; color: #fff; padding: 40px 20px; max-width: 560px; margin: 0 auto;">
<div style="background: #16161f; border: 1px solid rgba(255,255,255,0.08); border-radius: 12px; padding: 32px;">
<h1 style="font-size: 20px; margin: 0 0 8px;">Maintenance Update</h1>
<p style="color: rgba(255,255,255,0.6); margin: 0 0 24px;">Hi ${escapeHtml(tenantName)},</p>
<p style="color: rgba(255,255,255,0.6); margin: 0 0 12px;">
Your maintenance request "<strong style="color:#fff">${escapeHtml(title)}</strong>"
has been updated to: <strong style="color:#6366f1; text-transform: capitalize;">${escapeHtml(status).replace("_", " ")}</strong>
</p>
${resolutionNotes ? `<p style="color: rgba(255,255,255,0.5); margin: 0 0 24px; font-size: 14px;">${escapeHtml(resolutionNotes)}</p>` : ""}
<p style="color: rgba(255,255,255,0.4); font-size: 12px; margin: 24px 0 0;">Property Management Network</p>
</div>
</body>
</html>`
}