Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
3c1fb16
chore: update node version
dahal May 19, 2025
b4d9e5a
feat: prisma => drizzle and next 15 upgrade attempt
dahal May 21, 2025
8142e2b
feat: fix typesafety issues and refactor prisma query with drizzle
dahal May 21, 2025
bb7412b
feat: reformat files
dahal May 21, 2025
fa2d25a
feat: contd. type, import and query refactor
dahal May 21, 2025
a6d890d
feat: export proper schema and their types, and reformat
dahal May 21, 2025
fd64b86
feat: add few missing packages, few more to come
dahal May 21, 2025
7873bf5
fix: fixing type and enum imports
dahal May 21, 2025
be9089e
chore: reformat
dahal May 21, 2025
160a1eb
feat: install missing packages
dahal May 23, 2025
3835eee
fix: enum imports
dahal May 23, 2025
e616d05
fix: typesafety issues
dahal May 23, 2025
f39d244
fix: more typesafety issues
dahal May 23, 2025
dcf5f10
feat: more typesafety issue fixes on components
dahal May 23, 2025
9218833
fix: isLoading vs isPending trpc state
dahal May 23, 2025
b1b0e13
fix: some interesting typesafety fixes
dahal May 23, 2025
a33cdb8
chore: referencing file with `@/component`
dahal May 23, 2025
bd5bf34
chore: remove unwanted imports
dahal May 23, 2025
2b5e1ee
fix: typecheck
dahal May 23, 2025
8ae2ebd
fix: typecheck
dahal May 23, 2025
8f1ec6a
chore: remove un-necessary import
dahal May 23, 2025
4c910ee
chore: some more typesafety issues
dahal May 23, 2025
339a6e6
feat: component cleanup - checking in
dahal May 23, 2025
0b95fe2
chore: more import and typesafety cleanups
dahal May 23, 2025
fb8e501
feat: fix some more typesafety issues and missing packages
dahal May 24, 2025
9730b27
feat: refactor and document `@captable/db` package
dahal May 24, 2025
3637e06
fix: database, schema, enum all things db import
dahal May 24, 2025
2903a97
feat: replace prisma with drizzle query
dahal May 24, 2025
52aaeca
feat: more prisma - drizzle conversion
dahal May 24, 2025
8171704
feat: more db prisma - drizzle migration, and cuid as primary default id
dahal May 24, 2025
974c48f
fix: drizzling and some high level fixes
dahal May 24, 2025
b563505
fix: some more prisma to drizzle migration
dahal May 24, 2025
d73a407
fix: finally replace prisma with drizzle
dahal May 24, 2025
3ad159d
chore: removing additional layer
dahal May 24, 2025
3543ffc
1
dahal May 24, 2025
50243d6
chore: fixing build errors
dahal May 24, 2025
f88beea
feat: just to many fixes to count, including email getting its own pa…
dahal May 25, 2025
460b64d
chore: reformat
dahal May 25, 2025
476df5c
fix: email stuffs
dahal May 25, 2025
fcf029d
feat: get the build to work -- close
dahal May 26, 2025
e3e5396
feat: create utils package, cleanup email package, and fix more build…
dahal May 26, 2025
20be72b
feat: create cursor/rules for all apps and packages
dahal May 26, 2025
c851c24
fix: email component imports
dahal May 27, 2025
65903b0
chore: looks like NODE_ENV=staging is not a thing
dahal May 27, 2025
a6abd98
chore: fix build warning
dahal May 27, 2025
4f981fd
feat: next.config.js => next.config.ts
dahal May 27, 2025
0d60e90
feat: build finally works 🎉
dahal May 27, 2025
e870d02
feat: finalize email package setup and refactor
dahal May 27, 2025
c6c1c7b
chore: reformat
dahal May 27, 2025
d6b79f2
fix: fixing trpc error
dahal May 27, 2025
37d03b9
fix: fixing some components to make them dark/light compatible
dahal May 27, 2025
744351a
fix: logger package
dahal May 27, 2025
e9035d4
chore: lock in bun 1.2.15
dahal May 29, 2025
3d2c6d8
feat: upgrade next to 15.3.2
dahal May 29, 2025
f8b6e88
feat: updating auth function so migrating to better-auth becomes easier
dahal May 29, 2025
a927971
feat: creating better auth tables
dahal May 29, 2025
dfba6ae
feat: another steps forward to replace next-auth with better-auth
dahal May 29, 2025
154fb1e
feat: next-auth to better-auth - a work in progress
dahal May 30, 2025
95e6052
feat: fixing some session exports
dahal May 30, 2025
305232f
fix: next-auth to better-auth migration, types and other stuffs
dahal May 30, 2025
95d197d
feat: remove all references and files for next-auth
dahal May 30, 2025
bd7c7e1
feat: missing pieces on auth package
dahal May 30, 2025
4ecb32a
feat: seperate client and server for clientSideSession and serverSide…
dahal May 31, 2025
3a235a4
fix: auth related imports
dahal May 31, 2025
cd96d4c
feat: add missing headers
dahal May 31, 2025
0964b76
chore: add missing headers
dahal May 31, 2025
eff0950
feat: fix build errors, and some email package re/org
dahal May 31, 2025
623a75b
fix: email package build errors
dahal May 31, 2025
d3af458
chore: turbo upgrade
dahal May 31, 2025
9ee4817
feat: re/org theme code and fix dark/light mode flickering
dahal May 31, 2025
62ccd1d
whole lot of changes including dark/lite mode support
dahal May 31, 2025
ead4b9b
feat: add missing package
dahal Jun 1, 2025
cd81f52
feat: refactor rbac to its own package (#554)
dahal Jun 1, 2025
9c41244
WIP - reinventing the wheel, with our own queue system
dahal Jun 2, 2025
ad21aaf
chore: reformat
dahal Jun 2, 2025
533ecd5
chore: rename serverless-queue to just queue
dahal Jun 2, 2025
235420a
feat: index table as per the queries we run on jobs
dahal Jun 2, 2025
efc1b31
feat: convert class to function, and update some function names
dahal Jun 2, 2025
b0e2704
chore: fixing some type errors
dahal Jun 2, 2025
492b75f
feat: dev job runner, also fix dx command
dahal Jun 2, 2025
fb68ab2
feat: cleanup jobs demo mode logger
dahal Jun 2, 2025
92f3a0e
feat: update documentations
dahal Jun 2, 2025
27e2d4e
Merge pull request #555 from captableinc/feat/queue
dahal Jun 2, 2025
745ee01
feat: re-organize queue package
dahal Jun 4, 2025
3b6f0e9
feat: supporting both long running process and serverless, and 100% t…
dahal Jun 4, 2025
aa05ee6
Merge pull request #557 from captableinc/feat/queue-refactor
dahal Jun 4, 2025
c5c341b
chore: update queue docs with some relevant information
dahal Jun 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cursor/rules/packages/email.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ await sendEmail({
template: <WelcomeEmail
userName="John Doe"
companyName="Acme Corp"
loginUrl="https://app.captable.com/login"
loginUrl="https://cloud.captable.inc/login"
/>
})
```
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@

👷 **Incorporation** (wip) - Captable, Inc. helps you incorporate your company in minutes, with all the necessary legal documents and filings taken care of.

👷 **Cap table management** (wip) - Captable, Inc. helps you keep track of your companys ownership structure, including who owns what percentage of the company, how much stock/options has been issued, and more.
👷 **Cap table management** (wip) - Captable, Inc. helps you keep track of your company's ownership structure, including who owns what percentage of the company, how much stock/options has been issued, and more.

✅ **Fundraise** - Captable, Inc. can help you raise capital, whether its signing standard or custom SAFE or creating and managing fundraising rounds, tracking investor commitments, and more.

✅ **Investor updates** - Delight your investors and team members by sending them regular updates on your companys progress.
✅ **Investor updates** - Delight your investors and team members by sending them regular updates on your company's progress.

✅ **eSign Documents** - Sign SAFE, NDA, contracts, offere letters or any type of documents with Captable Sign.

Expand All @@ -78,7 +78,9 @@ We have a community of developers, designers, and entrepreneurs who are passiona

- [Next.js](https://nextjs.org)
- [Tailwind](https://tailwindcss.com)
- [Prisma ORM](https://prisma.io)
- [Drizzle ORM](https://orm.drizzle.team)
- [tRPC](https://trpc.io)
- [NextAuth.js](https://next-auth.js.org)

---

Expand Down Expand Up @@ -106,7 +108,7 @@ When contributing to <strong>Captable, Inc.</strong>, whether on GitHub or in ot

- <a href="https://docs.docker.com/get-docker/" target="_blank">Install Docker</a> & <a href="https://docs.docker.com/compose/install/" target="_blank">Docker Compose</a>
- <a href="https://github.com/captableinc/captable/fork" target="_blank">Fork</a> & clone the forked repository
- <a href="https://pnpm.io/installation" target="_blank">Install node and pnpm</a>. (optional)
- <a href="https://bun.sh/docs/installation" target="_blank">Install node and bun</a>. (optional)
- Copy `.env.example` to `.env`

```bash
Expand Down
63 changes: 44 additions & 19 deletions apps/captable/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,34 @@ We have a community of developers, designers, and entrepreneurs who are passiona

- [Next.js](https://nextjs.org)
- [Tailwind](https://tailwindcss.com)
- [Prisma ORM](https://prisma.io)
- [Drizzle ORM](https://orm.drizzle.team)

---
<h3 id="background-jobs">Background Jobs</h3>

Captable uses a custom job queue system for handling background tasks like:
- 📧 Email notifications (welcome, password reset, invites)
- 📄 PDF generation (e-signatures, documents)
- 🔄 Data processing and synchronization

**Development Setup:**
```bash
# Start with job processing (recommended)
bun dx

# Or start jobs separately
bun run jobs:dev
```

**Job Management:**
```bash
bun run jobs # Process pending jobs
bun run test-jobs # Queue sample test jobs
bun run jobs stats # View queue statistics
```

Jobs are automatically processed in production via Cron jobs.


<h3 id="start">Getting started</h3>
When contributing to <strong>Captable, Inc.</strong>, whether on GitHub or in other community spaces:
Expand All @@ -106,7 +131,7 @@ When contributing to <strong>Captable, Inc.</strong>, whether on GitHub or in ot

- <a href="https://docs.docker.com/get-docker/" target="_blank">Install Docker</a> & <a href="https://docs.docker.com/compose/install/" target="_blank">Docker Compose</a>
- <a href="https://github.com/captableinc/captable/fork" target="_blank">Fork</a> & clone the forked repository
- <a href="https://pnpm.io/installation" target="_blank">Install node and pnpm</a>. (optional)
- <a href="https://bun.sh/docs/installation" target="_blank">Install node and bun</a>. (optional)
- Copy `.env.example` to `.env`

```bash
Expand All @@ -117,10 +142,10 @@ When contributing to <strong>Captable, Inc.</strong>, whether on GitHub or in ot

```bash

# With pnpm installed
pnpm dx
# With bun installed
bun dx

# Without pnpm installed
# Without bun installed
docker compose up

```
Expand All @@ -129,8 +154,8 @@ When contributing to <strong>Captable, Inc.</strong>, whether on GitHub or in ot

```bash

docker compose exec app pnpm db:migrate
docker compose exec app pnpm db:seed
docker compose exec app bun db:migrate
docker compose exec app bun db:seed

```

Expand All @@ -143,15 +168,15 @@ When contributing to <strong>Captable, Inc.</strong>, whether on GitHub or in ot
- Emails will be intercepted: [http://localhost:8025](http://localhost:8025)
- SMTP will be on PORT `http://localhost:1025`
- Postgres will be on PORT `http://localhost:5432`
- Prisma studio will be on PORT `http://localhost:5555`
- Database studio will be on PORT `http://localhost:5555`

- Frequently used commands
- `docker compose up` - Start the development environment
- `docker compose down` - Stop the development environment
- `docker compose logs -f` - View logs of the running services
- `docker compose up --build` - Rebuild the docker image
- `docker compose run app pnpm db:migrate` - Run database migrations
- `docker compose run app pnpm db:seed` - Seed the database
- `docker compose run app bun db:migrate` - Run database migrations
- `docker compose run app bun db:seed` - Seed the database

---

Expand Down Expand Up @@ -218,23 +243,23 @@ When contributing to <strong>Captable, Inc.</strong>, whether on GitHub or in ot
- Run the following command to install dependencies

```bash
pnpm install
bun install
```

- Run the following command to migrate and seed the database

```bash
pnpm db:migrate
pnpm db:seed
bun db:migrate
bun db:seed
```

- Run the following command to start the development server

```bash
pnpm dev
bun dev

# On a different terminal, run the following command to start the mail server
pnpm email:dev
bun email:dev
```

- App will be running on [http://localhost:3000](http://localhost:3000)
Expand All @@ -243,10 +268,10 @@ When contributing to <strong>Captable, Inc.</strong>, whether on GitHub or in ot
- Postgres will be on PORT `http://localhost:5432`

- Frequently used commands
- `pnpm dev` - Start the development server
- `pnpm email:dev` - Start the mail server
- `pnpm db:migrate` - Run database migrations
- `pnpm db:seed` - Seed the database
- `bun dev` - Start the development server
- `bun email:dev` - Start the mail server
- `bun db:migrate` - Run database migrations
- `bun db:seed` - Seed the database

<h4 id="changes">Implement your changes</h4>

Expand Down
30 changes: 30 additions & 0 deletions apps/captable/app/api/cron/cleanup-jobs/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { logger } from "@captable/logger";
import { cleanupJobs } from "@captable/queue";
import { type NextRequest, NextResponse } from "next/server";

const log = logger.child({ module: "cron-cleanup" });

export async function GET(request: NextRequest) {
// Verify cron secret
const authHeader = request.headers.get("authorization");
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return new Response("Unauthorized", { status: 401 });
}

try {
const cleaned = await cleanupJobs(7); // Clean jobs older than 7 days

log.info({ cleaned }, "Job cleanup completed");

return NextResponse.json({
success: true,
cleaned,
});
} catch (error) {
log.error({ error }, "Job cleanup failed");
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 },
);
}
}
63 changes: 63 additions & 0 deletions apps/captable/app/api/cron/process-jobs/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { logger } from "@captable/logger";
import { processJobs } from "@captable/queue";
import { type NextRequest, NextResponse } from "next/server";
import "@/jobs"; // Import to register all jobs

const log = logger.child({ module: "cron-jobs" });

export async function GET(request: NextRequest) {
// Verify cron secret for security
const authHeader = request.headers.get("authorization");
const expectedAuth = `Bearer ${process.env.CRON_SECRET}`;

if (!expectedAuth || authHeader !== expectedAuth) {
log.warn({ authHeader }, "Unauthorized cron job access attempt");
return new Response("Unauthorized", { status: 401 });
}

try {
const startTime = Date.now();

// Process jobs in batches
let totalProcessed = 0;
let batchCount = 0;
const maxBatches = 10; // Prevent infinite loops

while (batchCount < maxBatches) {
const processed = await processJobs(20); // Process 20 jobs per batch
totalProcessed += processed;
batchCount++;

if (processed === 0) {
break; // No more jobs to process
}

// Small delay between batches
await new Promise((resolve) => setTimeout(resolve, 100));
}

const duration = Date.now() - startTime;

log.info(
{
totalProcessed,
batches: batchCount,
duration,
},
"Cron job processing completed",
);

return NextResponse.json({
success: true,
processed: totalProcessed,
batches: batchCount,
duration,
});
} catch (error) {
log.error({ error }, "Cron job processing failed");
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 },
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const ForgotPassword = () => {
},
});
const onSubmit = async (values: z.infer<typeof inputSchema>) => {
await mutateAsync(values.email);
await mutateAsync(values);
};

return (
Expand Down
29 changes: 24 additions & 5 deletions apps/captable/jobs/auth-verification-email.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { env } from "@/env";
import { BaseJob } from "@/jobs/base";
import { sendMail } from "@/server/mailer";
import type { Job } from "pg-boss";
import { logger } from "@captable/logger";
import { BaseJob } from "@captable/queue";

const log = logger.child({ module: "auth-verification-email-job" });

export type AuthVerificationEmailPayloadType = {
email: string;
Expand All @@ -11,6 +12,8 @@ export type AuthVerificationEmailPayloadType = {
const sendAuthVerificationEmail = async (
payload: AuthVerificationEmailPayloadType,
) => {
log.info({ email: payload.email }, "Sending auth verification email");

// Dynamic import to avoid build-time processing
const { render } = await import("@captable/email");
const { AccountVerificationEmail } = await import(
Expand All @@ -28,14 +31,30 @@ const sendAuthVerificationEmail = async (
subject: "Verify your account",
html,
});

log.info(
{ email: payload.email },
"Auth verification email sent successfully",
);
};

export { sendAuthVerificationEmail };

export class AuthVerificationEmailJob extends BaseJob<AuthVerificationEmailPayloadType> {
readonly type = "email.auth-verify";
protected readonly options = {
maxAttempts: 5, // Critical for account verification
retryDelay: 1000,
priority: 3, // High priority
};

async work(job: Job<AuthVerificationEmailPayloadType>): Promise<void> {
await sendAuthVerificationEmail(job.data);
async work(payload: AuthVerificationEmailPayloadType): Promise<void> {
await sendAuthVerificationEmail(payload);
}
}

// Create and register the job instance
const authVerificationEmailJob = new AuthVerificationEmailJob();
authVerificationEmailJob.register();

export { authVerificationEmailJob };
Loading