{"id":47733398,"url":"https://github.com/ulpio/vergo","last_synced_at":"2026-04-02T22:01:44.075Z","repository":{"id":311779197,"uuid":"1044973288","full_name":"Ulpio/vergo","owner":"Ulpio","description":"SaaS starter em Go: multi-tenant, RBAC, JWT, Postgres, sqlc, CI","archived":false,"fork":false,"pushed_at":"2026-03-29T06:09:51.000Z","size":159,"stargazers_count":1,"open_issues_count":13,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-29T08:16:14.773Z","etag":null,"topics":["boilerplate","go","jwt","multi-tenant","postgresql","rbac","saas","sqlc"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Ulpio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-26T13:24:38.000Z","updated_at":"2026-03-29T05:52:56.000Z","dependencies_parsed_at":"2025-08-26T19:16:30.308Z","dependency_job_id":"4e61de72-9c06-468f-82a2-7d84aa6cbd5f","html_url":"https://github.com/Ulpio/vergo","commit_stats":null,"previous_names":["ulpio/vergo"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/Ulpio/vergo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ulpio%2Fvergo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ulpio%2Fvergo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ulpio%2Fvergo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ulpio%2Fvergo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Ulpio","download_url":"https://codeload.github.com/Ulpio/vergo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Ulpio%2Fvergo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31317831,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T21:35:00.834Z","status":"ssl_error","status_checked_at":"2026-04-02T21:34:59.806Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["boilerplate","go","jwt","multi-tenant","postgresql","rbac","saas","sqlc"],"created_at":"2026-04-02T22:01:41.723Z","updated_at":"2026-04-02T22:01:44.038Z","avatar_url":"https://github.com/Ulpio.png","language":"Go","readme":"\n# Vergo\n\n**Production-ready multi-tenant SaaS backend in Go.**\n\n[![CI](https://github.com/Ulpio/vergo/actions/workflows/ci.yml/badge.svg)](https://github.com/Ulpio/vergo/actions/workflows/ci.yml)\n[![CD](https://github.com/Ulpio/vergo/actions/workflows/cd.yml/badge.svg)](https://github.com/Ulpio/vergo/actions/workflows/cd.yml)\n[![CodeQL](https://github.com/Ulpio/vergo/actions/workflows/codeql.yml/badge.svg)](https://github.com/Ulpio/vergo/actions/workflows/codeql.yml)\n[![Go](https://img.shields.io/badge/Go-1.25-00ADD8?logo=go\u0026logoColor=white)](https://go.dev)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)\n\nVergo is a complete SaaS backend that handles the infrastructure every B2B application needs — authentication, organizations, billing, webhooks, storage, and observability — so you can focus on your product's domain logic.\n\n---\n\n## What can you build with Vergo?\n\nVergo provides the backend foundation for any multi-tenant B2B SaaS. Fork it, add your domain logic, ship:\n\n- **Project management tool** (like Linear, Asana) — orgs, members, RBAC, and audit are ready\n- **Developer platform** (like Vercel, Railway) — API keys, webhooks, and billing are built-in\n- **Internal tooling platform** — tenant isolation, role-based access, and file storage out of the box\n- **Collaboration SaaS** (like Notion, Figma) — multi-org, invites, and plan gating from day one\n- **API-first product** — full Swagger docs, API key auth, webhook delivery with retries\n- **Marketplace / Platform** — Stripe subscriptions, usage tracking, feature gating per plan\n\nEvery feature is production-grade: hashed tokens, HMAC-signed webhooks, structured logs, distributed tracing, fuzz-tested auth. Not a tutorial project.\n\n---\n\n## Architecture\n\n```\n                                    +-------------------+\n                                    |   Stripe / S3     |\n                                    +--------+----------+\n                                             |\nClient ──\u003e Gin Router ──\u003e Middleware Chain ──\u003e Handlers ──\u003e Domain Services ──\u003e PostgreSQL\n           (rate limit)   (auth, tenant,      (HTTP)       (business logic)    (sqlc queries)\n                           RBAC, plan gate)\n                                                              |\n                                                     Webhook Dispatcher ──\u003e External URLs\n                                                     (background, retries)\n```\n\n### Design decisions\n\n| Decision | Rationale |\n|----------|-----------|\n| **sqlc** over GORM/ent | Type-safe SQL without magic. Queries are plain `.sql` files, generated Go code is reviewed in CI |\n| **Domain services** over repository pattern | Each domain owns its queries and business rules. No shared generic repository |\n| **Gin** as HTTP framework | Mature, fast, great middleware ecosystem. Easy to swap if needed |\n| **`database/sql`** over pgx pool | Simpler interface, works with sqlc out of the box, compatible with all Postgres tooling |\n| **Hash-based tokens** (API keys, reset) | Plaintext never stored. SHA-256 hashed at rest, compared by hash lookup |\n| **Background dispatcher** for webhooks | Decoupled delivery with exponential backoff. No external queue dependency for MVP |\n\n---\n\n## Features\n\n| Category | What's included |\n|----------|----------------|\n| **Auth** | Signup, login, refresh token rotation, forgot/reset password, logout, logout-all |\n| **Multi-tenant** | Organizations, memberships (owner/admin/member), tenant middleware via `X-Org-ID` |\n| **RBAC** | Role-based access control per organization with `RequireRole` middleware |\n| **API Keys** | Programmatic access with `sk_...` tokens (SHA-256 hashed, optional expiry) |\n| **Billing** | Stripe Checkout, subscriptions, webhook handler, plan gating (`free`/`pro`/`enterprise`) |\n| **Webhooks** | CRUD endpoints, HMAC-SHA256 signing, dispatcher with exponential backoff (5 retries) |\n| **Storage** | S3-compatible presigned uploads/downloads with file metadata tracking |\n| **Audit** | Immutable audit log with actor, action, entity, metadata, and filterable queries |\n| **Data Layer** | PostgreSQL + sqlc type-safe generated queries across 11 migrations |\n| **Observability** | OpenTelemetry (traces + metrics), structured logging (slog), Jaeger, Prometheus |\n| **Security** | Fuzz testing (JWT + RBAC), rate limiting, graceful shutdown, SQL lint (sqlfluff) |\n| **DX** | Dev Container, Swagger UI, Makefile (20+ targets), hot-reload (air), Dependabot |\n| **CI/CD** | Build, test, vet, golangci-lint, sqlc + swagger freshness checks, Docker multi-arch push to GHCR |\n\n---\n\n## Quickstart\n\n```bash\ngit clone git@github.com:Ulpio/vergo.git\ncd vergo\ncp .env.example .env\n\n# Start Postgres + infra\ndocker compose up -d\n\n# Run API\nmake run\n```\n\n```bash\n# Register a user\ncurl -s localhost:8080/v1/auth/signup \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"email\":\"demo@example.com\",\"password\":\"secret123\"}' | jq .\n\n# Create an org\nTOKEN=$(curl -s localhost:8080/v1/auth/login \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"email\":\"demo@example.com\",\"password\":\"secret123\"}' | jq -r .access_token)\n\ncurl -s localhost:8080/v1/orgs \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"name\":\"Acme Corp\"}' | jq .\n\n# Create a project (with org context)\nORG_ID=$(curl -s localhost:8080/v1/context \\\n  -H \"Authorization: Bearer $TOKEN\" | jq -r .org_id)\n\ncurl -s localhost:8080/v1/projects \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"X-Org-ID: $ORG_ID\" \\\n  -H 'Content-Type: application/json' \\\n  -d '{\"name\":\"My First Project\",\"description\":\"Built with Vergo\"}' | jq .\n```\n\n**Swagger UI**: http://localhost:8080/swagger/index.html\n\n### Dev Container\n\nOpen in VS Code / Cursor with everything pre-installed:\n\n1. Install [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension\n2. **Ctrl+Shift+P** \u003e *\"Dev Containers: Reopen in Container\"*\n\nIncludes: Go 1.25, PostgreSQL 16, migrate, golangci-lint, swag, air, sqlfluff.\n\n### Docker (Production)\n\n```bash\ndocker build -t vergo .\ndocker run -p 8080:8080 --env-file .env vergo\n```\n\nPre-built images on every push to main:\n```bash\ndocker pull ghcr.io/ulpio/vergo:main\n```\n\n---\n\n## API Reference\n\nFull interactive docs available at `/swagger/index.html` when running locally.\n\n### Public\n\n| Method | Path | Description |\n|--------|------|-------------|\n| POST | `/v1/auth/signup` | Register |\n| POST | `/v1/auth/login` | Login (returns JWT pair) |\n| POST | `/v1/auth/refresh` | Rotate token pair |\n| POST | `/v1/auth/logout` | Revoke refresh token |\n| POST | `/v1/auth/forgot-password` | Request password reset |\n| POST | `/v1/auth/reset-password` | Reset password with token |\n| POST | `/v1/billing/webhook` | Stripe webhook (signature verified) |\n| GET | `/healthz` | Health check |\n\n### Authenticated (Bearer JWT or API Key)\n\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | `/v1/me` | Current user profile |\n| POST | `/v1/auth/logout-all` | Revoke all sessions |\n| GET/POST | `/v1/context` | Get/set active org |\n| POST | `/v1/orgs` | Create organization |\n| GET | `/v1/orgs/:id` | Get organization |\n\n### Tenant-scoped (requires org context)\n\n| Method | Path | Minimum Role | Description |\n|--------|------|-------------|-------------|\n| POST/PATCH/DELETE | `/v1/orgs/:id/members*` | admin | Manage members |\n| DELETE | `/v1/orgs/:id` | owner | Delete organization |\n| CRUD | `/v1/projects*` | member | Project management |\n| GET | `/v1/audit` | admin | Filterable audit log |\n| CRUD | `/v1/api-keys*` | member | API key management |\n| CRUD | `/v1/webhooks/endpoints*` | member | Webhook configuration |\n| POST | `/v1/webhooks/test` | member | Test webhook delivery |\n| POST | `/v1/billing/checkout-session` | member | Start Stripe checkout |\n| GET | `/v1/billing/subscription` | member | Current subscription |\n| GET | `/v1/billing/usage` | member | Usage vs plan limits |\n| CRUD | `/v1/storage/*` | member | File uploads/downloads |\n\n---\n\n## Project Structure\n\n```\ncmd/api/                           # Application entrypoint\ninternal/\n  auth/                            # JWT, refresh tokens, password reset\n  domain/\n    user/                          # Registration, login, password management\n    org/                           # Organizations + memberships\n    project/                       # Project CRUD\n    audit/                         # Immutable audit trail\n    apikey/                        # API key lifecycle\n    webhook/                       # Endpoints + background dispatcher\n    billing/                       # Stripe integration + plan limits\n    file/                          # File metadata\n    userctx/                       # Active org context\n  http/\n    handlers/                      # Request/response handling\n    middleware/                    # Auth, tenant, RBAC, rate limit, plan gate\n    router/                        # Route registration + dependency wiring\n  repo/                            # sqlc generated type-safe queries\n  pkg/                             # Shared infrastructure (config, db, telemetry, logging)\n  storage/s3/                      # S3-compatible storage client\ndb/\n  migrations/                      # 11 SQL migrations\n  queries/                         # sqlc query definitions\n```\n\n---\n\n## Configuration\n\nAll configuration via environment variables. Copy `.env.example` to `.env` and adjust:\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `APP_PORT` | `8080` | HTTP port |\n| `APP_ENV` | `dev` | `dev` enables Swagger UI, `production` sets Gin to release mode |\n| `DB_*` | localhost | PostgreSQL connection |\n| `JWT_ACCESS_SECRET` | `dev-access` | Access token signing key |\n| `JWT_REFRESH_SECRET` | `dev-refresh` | Refresh token signing key |\n| `S3_BUCKET` / `S3_ENDPOINT` | - | S3-compatible storage (MinIO locally) |\n| `STRIPE_SECRET_KEY` | - | Stripe API key for billing |\n| `STRIPE_WEBHOOK_SECRET` | - | Stripe webhook signature verification |\n| `OTEL_EXPORTER_OTLP_ENDPOINT` | - | OTLP gRPC endpoint for traces/metrics |\n| `METRICS_PORT` | `0` | Prometheus scrape port (0 = disabled) |\n| `RATE_LIMIT_RPS` / `RATE_LIMIT_BURST` | `20` / `40` | Rate limiter config |\n\n---\n\n## Development\n\n```bash\nmake help              # Show all targets\nmake dev               # Hot-reload with air\nmake test              # Unit tests\nmake test-fuzz         # Fuzz tests (JWT + RBAC)\nmake lint              # golangci-lint\nmake check             # vet + lint + test (CI equivalent)\nmake swagger           # Regenerate Swagger docs\nmake sqlc              # Regenerate sqlc queries\nmake docker-up         # Start Postgres + infra\nmake docker-reset      # Reset database (drop volumes)\nmake migrate-up        # Run pending migrations\nmake migrate-create NAME=xyz  # Create new migration\n```\n\n---\n\n## Tech Stack\n\n| Layer | Technology |\n|-------|-----------|\n| Language | Go 1.25 |\n| HTTP | Gin |\n| Database | PostgreSQL 16 |\n| Query generation | sqlc |\n| Auth | JWT (golang-jwt/v5) + bcrypt |\n| Billing | Stripe Go SDK v82 |\n| Storage | AWS SDK v2 (S3-compatible) |\n| Observability | OpenTelemetry, slog, Jaeger, Prometheus |\n| CI/CD | GitHub Actions, GHCR, Docker multi-arch |\n| Code quality | golangci-lint, sqlfluff, CodeQL, Dependabot |\n\n---\n\n## License\n\n[MIT](./LICENSE)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fulpio%2Fvergo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fulpio%2Fvergo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fulpio%2Fvergo/lists"}