// workflows/client-signed.ts
export async function onClientSigned(contract: Contract) {
const project = await projects.createFromQuote(contract.quoteId);
await tasks.seed(project.id, templates.forService(project.service));
await invoices.scheduleInstallments(contract.quoteId, { deposit: 0.5 });
await calendar.book("kickoff", { client: contract.clientId, within: "3d" });
await notify.owner(`${contract.client.name} signed — ${project.name} is ready`);
}
// automations/overdue.ts
export const overdueInvoices = schedule("0 9 * * *", async () => {
for (const invoice of await invoices.pastDue()) {
await reminders.send(invoice, { tone: invoice.daysLate > 14 ? "firm" : "friendly" });
await tasks.create({ title: `Follow up: ${invoice.number}`, due: "tomorrow" });
}
});
// reports/revenue.ts
export function revenue(payments: Payment[]) {
return payments
.filter((p) => !p.voidedAt)
.reduce((total, p) => total + p.amountCents, 0);
}
// pipeline/stages.ts
export const stages = ["lead", "proposal", "active", "retainer"] as const;
export function advance(deal: Deal) {
const next = stages[stages.indexOf(deal.stage) + 1];
return next ? { ...deal, stage: next, movedAt: now() } : deal;
}
// intake/webhook.ts
export async function POST(request: Request) {
const lead = parseLead(await request.json());
await clients.upsert(lead);
await tasks.create({ title: `Reply to ${lead.name}`, due: "today" });
return Response.json({ ok: true });
}
// workflows/client-signed.ts
export async function onClientSigned(contract: Contract) {
const project = await projects.createFromQuote(contract.quoteId);
await tasks.seed(project.id, templates.forService(project.service));
await invoices.scheduleInstallments(contract.quoteId, { deposit: 0.5 });
await calendar.book("kickoff", { client: contract.clientId, within: "3d" });
await notify.owner(`${contract.client.name} signed — ${project.name} is ready`);
}
// automations/overdue.ts
export const overdueInvoices = schedule("0 9 * * *", async () => {
for (const invoice of await invoices.pastDue()) {
await reminders.send(invoice, { tone: invoice.daysLate > 14 ? "firm" : "friendly" });
await tasks.create({ title: `Follow up: ${invoice.number}`, due: "tomorrow" });
}
});
// reports/revenue.ts
export function revenue(payments: Payment[]) {
return payments
.filter((p) => !p.voidedAt)
.reduce((total, p) => total + p.amountCents, 0);
}
// pipeline/stages.ts
export const stages = ["lead", "proposal", "active", "retainer"] as const;
export function advance(deal: Deal) {
const next = stages[stages.indexOf(deal.stage) + 1];
return next ? { ...deal, stage: next, movedAt: now() } : deal;
}
// intake/webhook.ts
export async function POST(request: Request) {
const lead = parseLead(await request.json());
await clients.upsert(lead);
await tasks.create({ title: `Reply to ${lead.name}`, due: "today" });
return Response.json({ ok: true });
}