LeakOps monitors failed payments, dunning, proration errors, coupon abuse and more — so you can recover lost revenue automatically.
This repository is the Go (Fiber) backend for LeakOps.
- Language: Go
- Web Framework: Fiber
- ORM: GORM
- Database: PostgreSQL
- Payment Gateways Monitored: Stripe, Dodo Payments
- Billing (LeakOps's own subscriptions): Dodo Payments
- Email: Resend
- File Storage: Supabase Storage (S3-compatible)
- Auth: JWT, Google OAuth, GitHub OAuth
- Background Jobs: Custom retry engine (Day 1/3/7 schedule)
- Email Resend (for dunning and notifications)
Leakops-backend/
├── internal/
│ ├── config/ # Environment variable loading
│ ├── db/ # Database connection + auto-migration
│ ├── email/ # Dunning + notification emails (Resend)
│ ├── gateway/ # Stripe/Dodo webhook verification, retry logic
│ ├── handlers/ # HTTP request handlers
│ ├── middlewares/ # Auth (JWT) and CORS middleware
│ ├── models/ # Database models (GORM)
│ ├── retry/ # Background retry engine (Day 1/3/7 schedule)
│ ├── routes/ # Route registration
│ ├── services/ # LeakOps's own billing + storage services
│ └── utils/ # Shared helpers (encryption, webhook signature verification)
├── server/
│ └── main.go # Entry point
├── docker-compose.yml # Local PostgreSQL for development
├── go.mod
└── README.md
Before setting up the project locally, make sure you have:
- Go 1.21 or later
- Docker (for running PostgreSQL locally)
- A code editor (VS Code recommended)
- Accounts on the following services (all have free tiers):
- Stripe (Sandbox/Test mode)
- Dodo Payments (Test mode)
- Resend (for sending emails)
- Supabase (for file storage)
- Google Cloud Console (for Google OAuth)
- GitHub Developer Settings (for GitHub OAuth)
git clone https://github.com/<your-username>/Leakops-backend.git
cd Leakops-backendThis project uses Docker Compose to run a local PostgreSQL instance for development.
docker compose up -dThis starts a PostgreSQL container based on the credentials defined in your .env file (see below).
Copy the example file and fill in your own values:
cp .env.example .envFill in the following variables in .env:
# Server
PORT=8080
FRONTEND_URL=http://localhost:3000
BASE_URL=http://127.0.0.1:8080
# Auth
JWT_SECRET=your-random-secret-key
ENCRYPTION_KEY=your-32-character-encryption-key
# PostgreSQL (must match docker-compose.yml)
POSTGRES_USER=XXXXXXX
POSTGRES_PASSWORD=XXXXXXX
POSTGRES_DB=XXXXXX
DATABASE_URL=postgres://XXXXXXXXXX
# Google OAuth
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_REDIRECT_URI=http://127.0.0.1:8080/api/v1/auth/google/callback
# GitHub OAuth
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
GITHUB_REDIRECT_URI=http://127.0.0.1:8080/api/v1/auth/github/callback
# Resend (email)
RESEND_API_KEY=
RESEND_FROM_EMAIL=
# Supabase Storage (S3-compatible, for profile pictures)
SUPABASE_S3_ENDPOINT=
SUPABASE_S3_REGION=
SUPABASE_S3_ACCESS_KEY_ID=
SUPABASE_S3_SECRET_ACCESS_KEY=
SUPABASE_BUCKET_NAME=
SUPABASE_PUBLIC_URL=
# LeakOps's own Dodo account (for billing/subscriptions)
LEAKOPS_DODO_API_KEY=
LEAKOPS_DODO_ENVIRONMENT=test
LEAKOPS_DODO_WEBHOOK_SECRET=
DODO_PRODUCT_STARTER=
DODO_PRODUCT_GROWTH=
DODO_PRODUCT_SCALE=Note: Founders connect their own Stripe/Dodo API keys through the app itself (via /gateway/connect) — these are never stored in .env. Only LeakOps's own billing account needs a key in .env.
Important: ENCRYPTION_KEY must be exactly 32 characters (used for AES-256 encryption of stored gateway credentials). Generate one with:
python3 -c "import secrets, string; print(''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(32)))"go mod tidygo run server/main.goOn success, you should see:
Database connected successfully
Migration completed successfully!!
Retry engine started
Leakops backend listening on port :8080
The API is now available at http://127.0.0.1:8080/api/v1.
Since Stripe/Dodo need a public URL to send webhooks to, use ngrok during local development:
ngrok http 8080Update BASE_URL in your .env with the ngrok URL, then restart the server. Founder-connected gateway webhooks are auto-registered when a gateway is connected via /gateway/connect — no manual webhook setup is needed for that flow.
All endpoints are prefixed with /api/v1.
| Endpoint | Description |
|---|---|
POST /auth/signup, POST /auth/login |
Email/password auth |
GET /auth/google, GET /auth/github |
OAuth login |
POST /gateway/connect |
Connect a Stripe/Dodo account |
GET /dashboard/summary |
Revenue-at-risk and recovery stats |
GET /dashboard/payments |
List of failed payments |
GET /dashboard/export |
CSV export of failed payments |
POST /billing/checkout |
Start a LeakOps subscription checkout |
POST /profile/picture |
Upload a profile picture |
POST /feedback |
Submit product feedback |
- Fork this repository and clone your fork locally.
- Create a new branch for your change:
git checkout -b feature/your-feature-name
- Follow the existing code structure and conventions — handlers go in
internal/handlers/, routes ininternal/routes/, models ininternal/models/, etc. Keep new gateway integrations behind thePaymentGatewayinterface ininternal/gateway/interface.go. - Test your changes locally before submitting — make sure
go build ./...passes and manually verify the affected endpoints with a tool like Postman. - Do not commit your
.envfile or any real API keys/secrets. Only commit changes to.env.exampleif you add new required variables. - Open a Pull Request against the
mainbranch with a clear description of what you changed and why. - For significant changes (new features, architecture changes), please open an issue first to discuss before submitting a PR.