feat: complete SSR CRM and refine auth UI
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
import { createAuthEngine, SqlAuthStore, type AuthStore } from "@wrnexus/auth";
|
||||
import { getDb } from "@wrnexus/db";
|
||||
import { dbPermissionStore } from "@wrnexus/authz/db";
|
||||
import { ensureCrmWorkspace } from "./workspace.ts";
|
||||
|
||||
// Config is imported before the runtime opens its configured database. This
|
||||
// forwarding store resolves getDb() only when an auth operation actually runs.
|
||||
const store = new Proxy({} as AuthStore, {
|
||||
get(_target, property) {
|
||||
const value = Reflect.get(new SqlAuthStore(getDb()), property);
|
||||
return typeof value === "function" ? value.bind(new SqlAuthStore(getDb())) : value;
|
||||
},
|
||||
});
|
||||
|
||||
export const auth = createAuthEngine({
|
||||
store,
|
||||
secret: process.env.AUTH_SECRET ?? "northstar-crm-development-secret-change-me",
|
||||
issuer: "Northstar CRM",
|
||||
onSignedIn(ctx, returnTo) {
|
||||
const destination =
|
||||
returnTo?.startsWith("/") && !returnTo.startsWith("//") ? returnTo : "/dashboard";
|
||||
return Response.redirect(new URL(destination, ctx.url), 303);
|
||||
},
|
||||
onSignedOut(ctx) {
|
||||
return Response.redirect(new URL("/", ctx.url), 303);
|
||||
},
|
||||
async onSuccessfulSignUp(_ctx, user) {
|
||||
await dbPermissionStore(getDb()).assignRole(user.id, "sales-rep");
|
||||
await ensureCrmWorkspace(user.id);
|
||||
return { autoSignIn: true, redirectTo: "/dashboard" };
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import { getDb } from "@wrnexus/db";
|
||||
|
||||
/** Give every real CRM user a useful workspace on first access. */
|
||||
export async function ensureCrmWorkspace(ownerId: string): Promise<void> {
|
||||
if (!ownerId) return;
|
||||
const db = getDb();
|
||||
await db.exec(
|
||||
"INSERT OR IGNORE INTO crm_contacts (owner_id,name,email,company,phone,status) VALUES (?,?,?,?,?,?)",
|
||||
[ownerId, "Ada Lovelace", "ada@example.test", "Analytical Engines", "+1 555 0101", "customer"],
|
||||
);
|
||||
await db.exec(
|
||||
"INSERT OR IGNORE INTO crm_contacts (owner_id,name,email,company,phone,status) VALUES (?,?,?,?,?,?)",
|
||||
[ownerId, "Grace Hopper", "grace@example.test", "Compiler Labs", "+1 555 0102", "lead"],
|
||||
);
|
||||
const existingDeal = await db.one<{ count: number }>(
|
||||
"SELECT COUNT(*) count FROM crm_deals WHERE owner_id = ?",
|
||||
[ownerId],
|
||||
);
|
||||
if (Number(existingDeal?.count ?? 0) === 0) {
|
||||
const contact = await db.one<{ id: number }>(
|
||||
"SELECT id FROM crm_contacts WHERE owner_id = ? AND email = ?",
|
||||
[ownerId, "ada@example.test"],
|
||||
);
|
||||
await db.exec(
|
||||
"INSERT INTO crm_deals (owner_id,contact_id,title,value_cents,stage,close_date) VALUES (?,?,?,?,?,?)",
|
||||
[ownerId, contact?.id ?? null, "Enterprise rollout", 12500000, "proposal", "2026-12-15"],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user