A multi-tenant SaaS platform for tracking federal contract opportunities from SAM.gov with automated email notifications.
- 🔍 Custom Watchlists - Create filters based on NAICS codes, states, keywords, procurement types, and set-aside codes
- 📧 Smart Notifications - Choose immediate, daily, or weekly email digests
- 🏢 Multi-Tenant - Perfect for agencies managing multiple client watchlists
- 🔄 Automatic Syncing - Hourly ingestion of new opportunities from SAM.gov
- 🔐 Secure Authentication - Powered by Clerk
- Framework: Next.js 15 (App Router)
- Language: TypeScript
- Database: Neon Postgres + Drizzle ORM
- Authentication: Clerk
- Email: Resend + React Email
- Styling: Tailwind CSS + shadcn/ui
- Validation: Zod
- Deployment: Vercel
- Node.js 18+ installed
- pnpm package manager
- Accounts for:
- Clerk (authentication)
- Neon (PostgreSQL database)
- Resend (email sending)
- SAM.gov API Key (federal contracts data)
git clone <your-repo>
cd leadmagnet-site
pnpm installCopy .env.example to .env.local and fill in your credentials:
cp .env.example .env.localRequired variables:
# Clerk Authentication
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...
# Database (Neon Postgres)
DATABASE_URL=postgresql://...
# SAM.gov API (from https://api.data.gov/signup/)
SAM_API_KEY=...
# Resend Email
RESEND_API_KEY=re_...
# App Configuration
NEXT_PUBLIC_APP_URL=http://localhost:3000
# Cron Job Secret (generate a random string)
CRON_SECRET=your-random-secret-hereGenerate and run migrations:
pnpm db:generate
pnpm db:migrateOr push schema directly (development):
pnpm db:push- Create a new application in Clerk Dashboard
- Enable email/password authentication
- Copy your publishable and secret keys to
.env.local - Set up redirect URLs:
- Sign in:
/sign-in - Sign up:
/sign-up - After sign in:
/dashboard - After sign up:
/dashboard
- Sign in:
- Register at api.data.gov
- You'll receive an API key via email
- Add it to your
.env.localasSAM_API_KEY
- Create account at Resend
- Verify your sending domain
- Create an API key
- Add to
.env.localasRESEND_API_KEY - Update email "from" address in
src/lib/resend.tsto match your verified domain
pnpm devVisit http://localhost:3000
- Push your code to GitHub
- Import project in Vercel
- Add all environment variables
- Deploy
Cron jobs are automatically configured via vercel.json:
- SAM Ingest (
/api/cron/sam-ingest): Runs hourly at :00 - Match Watchlists (
/api/cron/match-watchlists): Runs hourly at :15
In Vercel dashboard:
- Go to Settings → Environment Variables
- Add
CRON_SECRET(same value as local) - Cron jobs will use this secret for authentication
# Generate migrations from schema changes
pnpm db:generate
# Run migrations
pnpm db:migrate
# Push schema directly (development)
pnpm db:push
# Open Drizzle Studio (database GUI)
pnpm db:studiosrc/
├── app/
│ ├── (auth)/ # Authentication pages
│ ├── (marketing)/ # Public marketing pages
│ ├── dashboard/ # Protected dashboard pages
│ └── api/ # API routes
│ ├── watchlists/ # Watchlist CRUD
│ └── cron/ # Scheduled jobs
├── components/
│ ├── ui/ # shadcn/ui components
│ ├── emails/ # React Email templates
│ └── app-sidebar.tsx # Dashboard sidebar
├── db/
│ ├── schema.ts # Drizzle schema
│ └── index.ts # Database client
└── lib/
├── sam.ts # SAM.gov API client
├── resend.ts # Email helpers
├── validators.ts # Zod schemas
└── utils.ts # Utility functions
GET /api/watchlists- List organization's watchlistsPOST /api/watchlists- Create new watchlistGET /api/watchlists/[id]- Get single watchlistPUT /api/watchlists/[id]- Update watchlistDELETE /api/watchlists/[id]- Soft delete watchlistGET /api/watchlists/[id]/preview- Preview SAM.gov results
POST /api/cron/sam-ingest- Ingest opportunities from SAM.govPOST /api/cron/match-watchlists- Match watchlists and send notifications
- Rate limit: Unknown, implement delays between requests
- Date range: Maximum 1 year between
postedFromandpostedTo - Pagination: Max 1000 records per request, use
offsetfor more - Date format:
MM/dd/yyyy(required) - Active filter: Only opportunities with
active === "Yes"are stored
See src/db/schema.ts for full schema. Key tables:
users- User accounts (synced from Clerk)organizations- Multi-tenant organizationsorganization_members- User-org relationshipssubscriptions- Plan limits and billingwatchlists- Saved searches with filtersopportunities- Cached SAM.gov opportunitiesuser_opportunity_notifications- Match trackingemail_logs- Email delivery trackingusage_events- Analytics and billing events
- Use
pnpm db:studioto inspect database during development - Check cron job logs in Vercel dashboard under "Logs" tab
- Test email templates using Resend's test mode
- Use Clerk's development mode for easier testing
MIT
For issues or questions, please open a GitHub issue.