Production-ready, multi-tenant SaaS — A GitHub App that automatically reviews Pull Requests using Google Gemini AI and posts inline comments.
┌─────────────────────────────────────────────────────────────────┐
│ GITHUB │
│ │
│ Developer opens PR ──► GitHub sends webhook ──────────┐ │
│ │ │
│ PR gets inline comments ◄── GitHub REST API ◄──┐ │ │
└──────────────────────────────────────────────────│──────│────────┘
│ │
┌──────────────────────────────────────────────────│──────│────────┐
│ CODE REVIEW BOT │ │ │
│ │ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Auth API │ │ GitHub Svc │◄───│ Webhook │ │
│ │ (JWT+RBAC) │ │ (REST Client)│ │ Controller │ │
│ └──────┬───────┘ └──────────────┘ └──────┬───────┘ │
│ │ │ │
│ ┌──────▼───────┐ ┌──────────────┐ ┌──────▼───────┐ │
│ │ Tenant API │ │ Gemini Svc │◄───│ Review Svc │ │
│ │ Repos/Usage │ │ (AI Engine) │ │ (Async/Pool) │ │
│ └──────┬───────┘ └──────────────┘ └──────┬───────┘ │
│ │ │ │
│ ┌──────▼───────────────────────────────────────▼───────┐ │
│ │ PostgreSQL (Multi-Tenant) │ │
│ │ tenants │ repos │ reviews │ comments │ usage │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
- Java 17+
- Docker & Docker Compose
- A GitHub App
- A Google Gemini API key
git clone https://github.com/your-username/code-review-bot.git
cd code-review-bot
# Copy env template and fill in your secrets
cp .env.example .envEdit .env with your values:
GITHUB_APP_ID=123456
GITHUB_WEBHOOK_SECRET=your-webhook-secret
GEMINI_API_KEY=your-gemini-key
JWT_SECRET=a-strong-secret-at-least-32-charactersPlace your GitHub App's private key file at the project root:
cp ~/Downloads/your-app.private-key.pem ./github-private-key.pemdocker compose up --buildThe app will be available at http://localhost:8080.
For local development, use smee.io or ngrok:
# Option A: smee.io (recommended for dev)
npx smee -u https://smee.io/your-channel -t http://localhost:8080/api/webhooks/github
# Option B: ngrok
ngrok http 8080Set the webhook URL in your GitHub App settings to:
https://your-url/api/webhooks/github
| Method | Endpoint | Description | Auth |
|---|---|---|---|
POST |
/api/auth/register |
Create tenant account | ❌ |
POST |
/api/auth/login |
Login, get JWT | ❌ |
GET |
/api/auth/me |
Current user info | ✅ |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
GET |
/api/repos |
List registered repos | ✅ |
POST |
/api/repos/register |
Register a repo | ✅ |
PATCH |
/api/repos/{id}/toggle |
Enable/disable repo | ✅ |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
GET |
/api/reviews |
List reviews (paginated) | ✅ |
GET |
/api/reviews/{id} |
Review detail + comments | ✅ |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
GET |
/api/usage |
Current month stats | ✅ |
GET |
/api/usage/history |
Last 6 months | ✅ |
| Method | Endpoint | Description | Auth |
|---|---|---|---|
POST |
/api/webhooks/github |
GitHub webhook receiver | HMAC |
GET |
/api/webhooks/github |
Health check | ❌ |
Interactive API docs available at: http://localhost:8080/swagger-ui.html
# Register
curl -X POST http://localhost:8080/api/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"dev@example.com","password":"securepass123","githubOrgOrUser":"my-org"}'
# Login
curl -X POST http://localhost:8080/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"dev@example.com","password":"securepass123"}'curl -X POST http://localhost:8080/api/repos/register \
-H "Authorization: Bearer <your-jwt>" \
-H "Content-Type: application/json" \
-d '{"repoFullName":"owner/repo","githubInstallationId":12345678}'curl http://localhost:8080/api/usage \
-H "Authorization: Bearer <your-jwt>"- Go to GitHub Settings → Developer Settings → GitHub Apps → New GitHub App
- Set:
- Homepage URL:
https://your-domain.com - Webhook URL:
https://your-domain.com/api/webhooks/github - Webhook Secret: Generate a strong secret
- Homepage URL:
- Permissions:
Pull requests: Read & WriteContents: Read
- Events: Subscribe to
Pull request - Generate a Private Key and download the
.pemfile - Note the App ID from the app settings page
- Install the app on your org/repos
tenants ──────────< repos ──────────< reviews ──────────< review_comments
│
└────────────< usage_tracking
- tenants: Multi-tenant accounts with plan (FREE/PRO) and RBAC roles
- repos: Registered repositories linked to tenants via installation IDs
- reviews: PR review records with status tracking and token usage
- review_comments: Individual inline comments from AI reviews
- usage_tracking: Per-tenant per-month review and token counters
| Variable | Description | Default |
|---|---|---|
GITHUB_APP_ID |
GitHub App ID | required |
GITHUB_PRIVATE_KEY_PATH |
Path to .pem file | required |
GITHUB_WEBHOOK_SECRET |
Webhook HMAC secret | required |
GEMINI_API_KEY |
Google Gemini API key | required |
JWT_SECRET |
JWT signing secret (min 32 chars) | required |
DB_URL |
PostgreSQL JDBC URL | jdbc:postgresql://localhost:5432/codereviewbot |
DB_USERNAME |
Database username | postgres |
DB_PASSWORD |
Database password | postgres |
PORT |
Server port | 8080 |
- Connect your GitHub repo to Railway
- Add a PostgreSQL service
- Set all environment variables from the table above
- Railway will auto-detect the Dockerfile and deploy
- Create a Web Service on Render
- Connect your repo, select Docker environment
- Add a PostgreSQL database
- Set environment variables, use the internal DB URL
- Deploy
src/main/java/com/codereviewbot/
├── config/ SecurityConfig, AsyncConfig, GeminiConfig
├── controller/ WebhookController, AuthController, RepoController,
│ ReviewController, UsageController
├── dto/ Request/response DTOs
├── entity/ JPA entities + enums
├── exception/ GlobalExceptionHandler, custom exceptions
├── repository/ Spring Data JPA repositories
├── security/ JwtUtil, JwtAuthenticationFilter, TenantPrincipal
└── service/ GitHubService, GeminiService, ReviewService,
TenantService, UsageTrackingService
| Plan | Reviews/Month | Price |
|---|---|---|
| FREE | 50 | $0 |
| PRO | Unlimited | Contact |
MIT