Files
property-management-network/scripts/verify-admin.ts
T
Leon SerfatyandClaude Opus 4.8 857b9a7811 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>
2026-06-23 20:36:07 -04:00

51 lines
2.4 KiB
TypeScript

/**
* Exercises the REAL admin-queries against the live DB to prove the admin
* dashboard data layer works end-to-end. Run after seed-users + seed-admin.
* Run: npx tsx scripts/verify-admin.ts
*/
import { config } from "dotenv"
config({ path: ".env.local" })
process.env.DATABASE_SSL = process.env.DATABASE_SSL ?? "disable"
async function main() {
const q = await import("../lib/db/admin-queries")
const { pool } = await import("../lib/db")
const overview = await q.getAdminOverviewStats()
const dist = await q.getPlanDistribution()
const users = await q.getUsersPage({ page: 1, pageSize: 5 })
const ai = await q.getAiUsageAggregates()
const sys = await q.getSystemCounts()
console.log("── Overview ─────────────────────────────")
console.log(` total users: ${overview.totalUsers}`)
console.log(` paid / free: ${overview.paidUsers} / ${overview.freeUsers}`)
console.log(` MRR / ARR: $${overview.mrr} / $${overview.arr}`)
console.log(` lifetime revenue: $${overview.lifetimeRevenue}`)
console.log(` properties/tenants: ${overview.totalProperties} / ${overview.totalTenants}`)
console.log(` AI calls this month:${overview.aiCallsThisMonth}`)
console.log(` active (30d): ${overview.activeUsers30d}`)
console.log(` plan distribution: ${JSON.stringify(dist)}`)
console.log("── Users page (first 5) ─────────────────")
console.log(` total matched: ${users.total} (pageCount ${users.pageCount})`)
for (const u of users.rows) {
console.log(` ${u.email} [${u.plan}] props=${u.propertyCount} tenants=${u.tenantCount} role=${u.role ?? "user"} banned=${u.banned ?? false}`)
}
console.log("── AI usage ─────────────────────────────")
console.log(` this month total: ${ai.totalThisMonth}`)
console.log(` by type: ${JSON.stringify(ai.byType)}`)
console.log("── System counts ────────────────────────")
console.log(` ${JSON.stringify(sys.counts)}`)
// sanity assertions
const ok = overview.totalUsers >= 11 && users.total >= 11
console.log(`\n${ok ? "✓ PASS" : "✗ CHECK"} — expected >= 11 users (10 landlords + admin)`)
await pool.end()
}
main().catch((e) => {
console.error("verify-admin failed:", e)
process.exit(1)
})