A serverless backend built with AWS SAM and TypeScript, providing APIs for workspace management, authentication, messaging, and more.
- Node.js (v18 or higher)
- AWS CLI configured with your credentials
- SAM CLI
- Docker (for local development)
-
Clone the repository
git clone https://github.com/HeroTools/pager-backend.git cd pager-backend -
Install dependencies
npm install
-
Set up local configuration
npm run setup:local
This creates
config/parameters.jsonfrom the example template. -
Configure your environment Edit
config/parameters.jsonwith your actual values:{ "dev": [ { "name": "openai-api-key", "value": "sk-your-openai-key-here", "type": "SecureString" }, { "name": "supabase-url", "value": "https://your-project.supabase.co", "type": "String" } ] } -
Start local development
npm run local:dev
Your API will be available at http://localhost:8081 π
This project follows a domain-driven architecture where functionality is organized by business domains. Each domain contains its own set of Lambda functions, promoting modularity and maintainability.
-
functions/- Contains all Lambda functions organized by domain:agents/- Agent management functionalityattachments/- File attachment handlingauth/- Authentication and authorizationchannels/- Channel managementconversations/- Conversation handlingembeddings/- Vector embeddings processingmembers/- Member managementmessages/- Message processingnotifications/- Notification systemreactions/- Message reactionssearch/- Search functionalityworkspaces/- Workspace managementcommon/- Shared utilities and types used across domainsmigration/- Slack workspace migrationswebhooks/- Separate webhook service stack for external integrations
-
supabase/- Supabase configuration, database migrations, and schema definitions -
scripts/- Utility scripts for generating environment variables and upserting secrets to AWS Secrets Manager -
config/- Environment-specific configuration files -
.aws-sam/- SAM CLI build artifacts and cache (auto-generated)
template.yaml- SAM template defining all AWS resources and Lambda functionssamconfig.toml- SAM CLI configuration with build caching and deployment settingstsconfig.json- TypeScript configurationpackage.json- Node.js dependencies and scriptsenv.json- Environment variables for local development
The project uses esbuild for fast bundling and tree-shaking. Only imported packages are included in the final Lambda bundles, keeping deployment sizes minimal.
Key behaviors:
- Single
template.yamlmanages all domains and functions - Build process compiles all functions but uses aggressive caching
- Deployments are incremental - only changed functions are updated
- Shared code changes in
common/trigger rebuilds for dependent functions - Template configuration changes affect all functions
# Start local API server
npm run local:dev
# Build the project
npm run build
# Lint and format code
npm run lint
npm run format| Script | Description |
|---|---|
npm run local:dev |
Start local development server |
npm run local:prod |
Start local server with prod config |
npm run deploy:dev |
Deploy to dev environment |
npm run deploy:dev:setup |
Deploy to dev with secrets setup |
npm run deploy:prod |
Deploy to production |
npm run deploy:prod:setup |
Deploy to prod with secrets setup |
npm run setup:local |
Set up local configuration |
npm run setup:aws |
Configure AWS Secrets Manager |
npm run generate:env |
Generate environment variables |
npm run build |
Build all Lambda functions |
npm run lint |
Lint and fix TypeScript code |
npm run format |
Format code with Prettier |
npm run webhooks:build |
Build webhook functions only |
npm run webhooks:deploy:dev |
Deploy webhooks to dev (with notifications) |
npm run webhooks:deploy:dev:setup |
Deploy webhooks to dev (first time, no notifications) |
npm run webhooks:deploy:prod |
Deploy webhooks to prod (with notifications) |
npm run webhooks:deploy:prod:setup |
Deploy webhooks to prod (first time, no notifications) |
The project uses AWS Secrets Manager for secure secret management:
- Local development: Uses generated
env.jsonfrom yourconfig/parameters.json - AWS deployment: Reads from AWS Secrets Manager (
/unowned/dev/or/unowned/prod/)
| Parameter | Description | Example |
|---|---|---|
openai-api-key |
OpenAI API key for AI features | sk-... |
google-client-id |
Google OAuth client ID | 123...apps.googleusercontent.com |
google-client-secret |
Google OAuth client secret | GOCSPX-... |
supabase-url |
Supabase project URL | https://xxx.supabase.co |
supabase-anon-key |
Supabase anonymous key | eyJhbGcixxxxx... |
supabase-service-role-key |
Supabase service role key | eyJhbGcixxxxx... |
pg-password |
PostgreSQL password | your-secure-password |
These are used for CORS and redirecting to the frontend. Please update them in the template.yaml file.
| Parameter | Description | Default |
|---|---|---|
frontend-url |
Frontend application URL | http://localhost:3000 |
allowed-origins |
CORS allowed origins | http://localhost:3000 |
The webhooks service is a separate CloudFormation stack that handles external integrations. It runs independently from the main API to provide isolation and scalability for webhook processing.
webhooks/
βββ template.yaml # SAM template for webhook stack
βββ samconfig.toml # SAM configuration
βββ src/
β βββ handlers/ # Webhook endpoint handlers
β β βββ webhook-handler.ts # Generic/custom webhooks
β β βββ github-webhook-handler.ts # GitHub integration
β β βββ linear-webhook-handler.ts # Linear integration
β β βββ jira-webhook-handler.ts # Jira integration
β β βββ stripe-webhook-handler.ts # Stripe integration
β βββ processors/ # Message processing
β β βββ message-processor.ts # SQS message processor
β βββ types.ts # Shared TypeScript types
- Webhook Handlers - Receive HTTP webhooks from external services
- SQS Queue - Queues messages for processing (FIFO for guaranteed ordering)
- Message Processor - Processes queued messages and saves to database
- Notification Integration - Triggers notifications when webhook messages arrive
# 1. Deploy main stack first (if not already deployed)
npm run deploy:dev:setup
# 2. Deploy webhooks without notifications (first time)
npm run webhooks:deploy:dev:setup
# 3. Redeploy webhooks with notifications enabled
npm run webhooks:deploy:dev# Development
npm run webhooks:deploy:dev
# Production
npm run webhooks:deploy:prodThe webhook stack supports the following configuration options:
| Parameter | Description | Default | Values |
|---|---|---|---|
Environment |
Target environment | dev |
dev, prod |
StackName |
CloudFormation stack name | pager-webhooks-dev |
pager-webhooks-dev, pager-webhooks-prod |
MainStackName |
Main API stack name | unowned-dev |
unowned, unowned-dev |
EnableNotifications |
Enable notification service integration | false |
true, false |
Once deployed, the following webhook endpoints are available:
| Service | Endpoint | Description |
|---|---|---|
| Custom | POST /webhooks/custom/{webhookId} |
Generic webhook for custom integrations |
| GitHub | POST /webhooks/github/{webhookId} |
GitHub repository events |
| Linear | POST /webhooks/linear/{webhookId} |
Linear issue tracking |
| Jira | POST /webhooks/jira/{webhookId} |
Jira project management |
| Stripe | POST /webhooks/stripe/{webhookId} |
Stripe payment events |
Base URL Format: https://{api-id}.execute-api.us-east-2.amazonaws.com/{environment}
- Webhook Received β Handler validates and queues message to SQS
- SQS Trigger β Message processor picks up queued messages
- Database Save β Message saved to PostgreSQL database
- Notifications β Notification service notifies channel members
- Real-time Broadcast β Message broadcast via Supabase real-time
# Build webhooks locally
npm run webhooks:build
# Test with SAM Local (if needed)
cd webhooks && sam local start-api- Create new handler in
src/handlers/ - Add HTTP API route in
template.yaml - Implement message transformation logic
- Deploy with
npm run webhooks:deploy:dev
The webhook service integrates with the main API stack using SSM Parameters:
- Webhook API URL:
/pager-webhooks-{env}/{env}/webhook-api-url - Notification Service ARN:
/{main-stack}/{env}/notification-service-function-arn
This approach allows independent deployment and deletion of stacks without dependency issues.
For your first deployment to each environment, use the setup scripts to configure AWS Secrets Manager:
# Development environment (first time)
npm run deploy:dev:setup
# Production environment (first time)
npm run deploy:prod:setupAfter initial setup, use the regular deployment commands:
# Development environment
npm run deploy:dev
# Production environment
npm run deploy:prodThe deployment will:
- Generate environment variables from configuration
- Set up AWS Secrets Manager with your configuration (setup only)
- Build all Lambda functions
- Deploy infrastructure using CloudFormation
- Configure API Gateway endpoints
- Authentication: JWT-based auth with Google OAuth integration
- Workspaces: Multi-tenant workspace management
- Messages: Real-time messaging system
- Attachments: File upload and management
- Notifications: Push notification delivery
- Search: Full-text search across content
- Embeddings: Vector search using OpenAI embeddings
- Runtime: Node.js 20.x
- Database: PostgreSQL (via Supabase)
- Storage: AWS S3 (via Supabase Storage)
- Authentication: Supabase Auth
- Secrets: AWS Secrets Manager
- Deployment: AWS SAM/CloudFormation
- Monitoring: AWS CloudWatch
- All secrets stored in AWS Secrets Manager
- Environment variables never contain plain-text secrets
- JWT token validation on protected endpoints
- CORS configured for frontend domains
- Input validation using Zod schemas
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Set up your local environment (
npm run setup:local) - Make your changes and test locally (
npm run local:dev) - Run linting and formatting (
npm run lint && npm run format) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Use TypeScript for all new code
- Follow the existing folder structure by domain
- Add tests for new functionality
- Use meaningful commit messages
- Update documentation as needed
- Run
npm run lintandnpm run formatbefore committing
- Check the Issues page
- Search existing discussions
- Create a new issue with:
- Clear description of the problem
- Steps to reproduce
- Your environment details
- Relevant logs or error messages
This project is licensed under the MIT License - see the LICENSE file for details.
- Zach Bresler - CTO - @zachbresler
- Gabriel Stein - CEO - @gabrielstein