Showing preview only (2,053K chars total). Download the full file or copy to clipboard to get everything.
Repository: moasq/production-saas-starter
Branch: main
Commit: 701bff660c62
Files: 479
Total size: 1.8 MB
Directory structure:
gitextract__wbx865y/
├── .editorconfig
├── .gitignore
├── CLAUDE.md
├── Caddyfile
├── DEVELOPMENT.md
├── LICENSE
├── README.md
├── SECURITY.md
├── SETUP.md
├── docker-compose.production.yml
├── go-b2b-starter/
│ ├── .air.toml
│ ├── .claude/
│ │ └── CLAUDE.md
│ ├── .dockerignore
│ ├── .gitignore
│ ├── .gitlab-ci.yml
│ ├── Dockerfile
│ ├── Makefile
│ ├── README.md
│ ├── cmd/
│ │ └── api/
│ │ └── main.go
│ ├── deps/
│ │ ├── Dockerfile
│ │ └── docker-compose.yml
│ ├── docs/
│ │ ├── README.md
│ │ ├── adding-a-module.md
│ │ ├── api-development.md
│ │ ├── architecture.md
│ │ ├── authentication.md
│ │ ├── billing.md
│ │ ├── database.md
│ │ ├── event-bus.md
│ │ └── file-manager.md
│ ├── example.env
│ ├── go.mod
│ ├── go.sum
│ ├── internal/
│ │ ├── api/
│ │ │ └── provider.go
│ │ ├── bootstrap/
│ │ │ ├── init_mods.go
│ │ │ └── root.go
│ │ ├── db/
│ │ │ ├── README.md
│ │ │ ├── adapters/
│ │ │ │ ├── cognitive_store.go
│ │ │ │ ├── document_store.go
│ │ │ │ ├── file_asset_store.go
│ │ │ │ ├── organization_store.go
│ │ │ │ └── subscription_store.go
│ │ │ ├── cmd/
│ │ │ │ ├── init.go
│ │ │ │ └── providers.go
│ │ │ ├── core/
│ │ │ │ ├── connection.go
│ │ │ │ ├── errors.go
│ │ │ │ └── transaction.go
│ │ │ ├── helpers/
│ │ │ │ └── helpers.go
│ │ │ ├── inject.go
│ │ │ └── postgres/
│ │ │ ├── adapter_impl/
│ │ │ │ ├── cognitive_store.go
│ │ │ │ ├── document_store.go
│ │ │ │ ├── file_asset_store.go
│ │ │ │ ├── organization_store.go
│ │ │ │ └── subscription_store.go
│ │ │ ├── connection.go
│ │ │ ├── db_config.go
│ │ │ ├── init.go
│ │ │ ├── postgres_manager.go
│ │ │ ├── retry.go
│ │ │ ├── sqlc/
│ │ │ │ ├── gen/
│ │ │ │ │ ├── cognitive.sql.go
│ │ │ │ │ ├── db.go
│ │ │ │ │ ├── documents.sql.go
│ │ │ │ │ ├── error.go
│ │ │ │ │ ├── example_resource.sql.go
│ │ │ │ │ ├── exec.go
│ │ │ │ │ ├── file_manager.sql.go
│ │ │ │ │ ├── models.go
│ │ │ │ │ ├── organizations.sql.go
│ │ │ │ │ ├── querier.go
│ │ │ │ │ ├── resource_embeddings.sql.go
│ │ │ │ │ ├── store.go
│ │ │ │ │ └── subscription_billing.sql.go
│ │ │ │ ├── migrations/
│ │ │ │ │ ├── 000001_create_file_manager_schema.down.sql
│ │ │ │ │ ├── 000001_create_file_manager_schema.up.sql
│ │ │ │ │ ├── 000002_create_organizations_schema.down.sql
│ │ │ │ │ ├── 000002_create_organizations_schema.up.sql
│ │ │ │ │ ├── 000003_enforce_role_enum.down.sql
│ │ │ │ │ ├── 000003_enforce_role_enum.up.sql
│ │ │ │ │ ├── 000004_create_subscription_billing_schema.down.sql
│ │ │ │ │ ├── 000004_create_subscription_billing_schema.up.sql
│ │ │ │ │ ├── 000005_update_quota_tracking_schema.down.sql
│ │ │ │ │ ├── 000005_update_quota_tracking_schema.up.sql
│ │ │ │ │ ├── 000006_create_example_resources.down.sql
│ │ │ │ │ ├── 000006_create_example_resources.up.sql
│ │ │ │ │ ├── 000007_create_resource_embeddings.down.sql
│ │ │ │ │ ├── 000007_create_resource_embeddings.up.sql
│ │ │ │ │ ├── 000008_create_documents_schema.down.sql
│ │ │ │ │ ├── 000008_create_documents_schema.up.sql
│ │ │ │ │ ├── 000009_create_cognitive_schema.down.sql
│ │ │ │ │ └── 000009_create_cognitive_schema.up.sql
│ │ │ │ ├── query/
│ │ │ │ │ ├── cognitive.sql
│ │ │ │ │ ├── documents.sql
│ │ │ │ │ ├── example_resource.sql
│ │ │ │ │ ├── file_manager.sql
│ │ │ │ │ ├── organizations.sql
│ │ │ │ │ └── subscription_billing.sql
│ │ │ │ └── sqlc.yml
│ │ │ └── types_transform.go
│ │ ├── docs/
│ │ │ ├── api/
│ │ │ │ ├── handler.go
│ │ │ │ └── routes.go
│ │ │ ├── cmd/
│ │ │ │ └── init.go
│ │ │ └── gen/
│ │ │ ├── docs.go
│ │ │ ├── swagger.json
│ │ │ └── swagger.yaml
│ │ ├── modules/
│ │ │ ├── auth/
│ │ │ │ ├── README.md
│ │ │ │ ├── adapters/
│ │ │ │ │ └── stytch/
│ │ │ │ │ ├── adapter.go
│ │ │ │ │ ├── config.go
│ │ │ │ │ ├── jwks_cache.go
│ │ │ │ │ ├── jwt_parser.go
│ │ │ │ │ ├── mock_adapter.go
│ │ │ │ │ ├── rbac_policy.go
│ │ │ │ │ └── token_verifier.go
│ │ │ │ ├── auth.go
│ │ │ │ ├── cmd/
│ │ │ │ │ └── init.go
│ │ │ │ ├── context.go
│ │ │ │ ├── errors.go
│ │ │ │ ├── handler.go
│ │ │ │ ├── middleware.go
│ │ │ │ ├── permissions.go
│ │ │ │ ├── provider.go
│ │ │ │ ├── rbac.go
│ │ │ │ ├── resolvers.go
│ │ │ │ ├── roles.go
│ │ │ │ └── routes.go
│ │ │ ├── billing/
│ │ │ │ ├── README.md
│ │ │ │ ├── app/
│ │ │ │ │ └── services/
│ │ │ │ │ ├── check_quota_availability_service.go
│ │ │ │ │ ├── consume_invoice_quota_service.go
│ │ │ │ │ ├── get_billing_status_service.go
│ │ │ │ │ ├── module.go
│ │ │ │ │ ├── process_webhook_event_service.go
│ │ │ │ │ ├── refresh_subscription_status_service.go
│ │ │ │ │ ├── subscription_service_dec.go
│ │ │ │ │ ├── sync_subscription_service.go
│ │ │ │ │ ├── verify_and_consume_quota_service.go
│ │ │ │ │ └── verify_payment_service.go
│ │ │ │ ├── cmd/
│ │ │ │ │ ├── init.go
│ │ │ │ │ └── provider.go
│ │ │ │ ├── domain/
│ │ │ │ │ ├── errors.go
│ │ │ │ │ ├── repository.go
│ │ │ │ │ └── types.go
│ │ │ │ ├── handler.go
│ │ │ │ ├── infra/
│ │ │ │ │ ├── adapters/
│ │ │ │ │ │ └── status_provider.go
│ │ │ │ │ ├── polar/
│ │ │ │ │ │ └── polar_adapter.go
│ │ │ │ │ └── repositories/
│ │ │ │ │ ├── organization_adapter.go
│ │ │ │ │ └── subscription_repository.go
│ │ │ │ ├── provider.go
│ │ │ │ └── routes.go
│ │ │ ├── cognitive/
│ │ │ │ ├── app/
│ │ │ │ │ └── services/
│ │ │ │ │ ├── document_listener.go
│ │ │ │ │ ├── embedding_service.go
│ │ │ │ │ ├── interface.go
│ │ │ │ │ └── rag_service.go
│ │ │ │ ├── cmd/
│ │ │ │ │ └── init.go
│ │ │ │ ├── domain/
│ │ │ │ │ ├── ai_provider.go
│ │ │ │ │ ├── entity.go
│ │ │ │ │ ├── errors.go
│ │ │ │ │ └── repository.go
│ │ │ │ ├── handler.go
│ │ │ │ ├── infra/
│ │ │ │ │ ├── ai/
│ │ │ │ │ │ ├── assistant_provider.go
│ │ │ │ │ │ └── text_vectorizer.go
│ │ │ │ │ └── repositories/
│ │ │ │ │ ├── chat_repository.go
│ │ │ │ │ ├── embedding_repository.go
│ │ │ │ │ └── helpers.go
│ │ │ │ ├── module.go
│ │ │ │ ├── provider.go
│ │ │ │ └── routes.go
│ │ │ ├── documents/
│ │ │ │ ├── app/
│ │ │ │ │ └── services/
│ │ │ │ │ ├── document_service.go
│ │ │ │ │ └── interface.go
│ │ │ │ ├── cmd/
│ │ │ │ │ └── init.go
│ │ │ │ ├── domain/
│ │ │ │ │ ├── entity.go
│ │ │ │ │ ├── errors.go
│ │ │ │ │ ├── events/
│ │ │ │ │ │ └── document_events.go
│ │ │ │ │ └── repository.go
│ │ │ │ ├── handler.go
│ │ │ │ ├── infra/
│ │ │ │ │ └── repositories/
│ │ │ │ │ └── document_repository.go
│ │ │ │ ├── module.go
│ │ │ │ ├── provider.go
│ │ │ │ └── routes.go
│ │ │ ├── files/
│ │ │ │ ├── README.md
│ │ │ │ ├── cmd/
│ │ │ │ │ ├── init.go
│ │ │ │ │ └── provider.go
│ │ │ │ ├── config/
│ │ │ │ │ └── config.go
│ │ │ │ ├── constants.go
│ │ │ │ ├── domain/
│ │ │ │ │ ├── entity.go
│ │ │ │ │ ├── helpers.go
│ │ │ │ │ ├── repository.go
│ │ │ │ │ ├── service.go
│ │ │ │ │ └── validator.go
│ │ │ │ ├── infra/
│ │ │ │ │ └── file_metadata_repository.go
│ │ │ │ └── internal/
│ │ │ │ └── infra/
│ │ │ │ ├── composite_repository.go
│ │ │ │ ├── db_repository.go
│ │ │ │ ├── mock_r2_repository.go
│ │ │ │ └── r2_repository.go
│ │ │ ├── organizations/
│ │ │ │ ├── account_handler.go
│ │ │ │ ├── app/
│ │ │ │ │ └── services/
│ │ │ │ │ ├── member_service.go
│ │ │ │ │ ├── member_service_impl.go
│ │ │ │ │ ├── organization_service.go
│ │ │ │ │ └── organization_service_interface.go
│ │ │ │ ├── cmd/
│ │ │ │ │ └── init.go
│ │ │ │ ├── domain/
│ │ │ │ │ ├── auth_provider.go
│ │ │ │ │ ├── entity.go
│ │ │ │ │ ├── errors.go
│ │ │ │ │ ├── events/
│ │ │ │ │ │ └── organization_events.go
│ │ │ │ │ └── repository.go
│ │ │ │ ├── infra/
│ │ │ │ │ └── repositories/
│ │ │ │ │ ├── account_repository.go
│ │ │ │ │ ├── organization_repository.go
│ │ │ │ │ ├── slug_generator.go
│ │ │ │ │ ├── stytch_member_repository.go
│ │ │ │ │ ├── stytch_organization_repository.go
│ │ │ │ │ └── stytch_role_repository.go
│ │ │ │ ├── member_handler.go
│ │ │ │ ├── module.go
│ │ │ │ ├── organization_handler.go
│ │ │ │ ├── provider.go
│ │ │ │ └── routes.go
│ │ │ └── paywall/
│ │ │ ├── README.md
│ │ │ ├── cmd/
│ │ │ │ └── init.go
│ │ │ ├── context.go
│ │ │ ├── errors.go
│ │ │ ├── middleware.go
│ │ │ ├── provider.go
│ │ │ └── subscription.go
│ │ └── platform/
│ │ ├── eventbus/
│ │ │ ├── bus.go
│ │ │ ├── cmd/
│ │ │ │ ├── init.go
│ │ │ │ └── provider.go
│ │ │ ├── event.go
│ │ │ ├── events.go
│ │ │ └── middleware.go
│ │ ├── llm/
│ │ │ ├── README.md
│ │ │ ├── cmd/
│ │ │ │ └── init.go
│ │ │ ├── domain/
│ │ │ │ ├── errors.go
│ │ │ │ └── service.go
│ │ │ └── infra/
│ │ │ └── openai_client.go
│ │ ├── logger/
│ │ │ ├── cmd/
│ │ │ │ ├── init.go
│ │ │ │ └── provider.go
│ │ │ ├── domain/
│ │ │ │ ├── logger.go
│ │ │ │ └── options.go
│ │ │ ├── factory.go
│ │ │ └── internal/
│ │ │ └── zerologger/
│ │ │ ├── factory.go
│ │ │ └── logger.go
│ │ ├── ocr/
│ │ │ ├── README.md
│ │ │ ├── cmd/
│ │ │ │ └── init.go
│ │ │ ├── domain/
│ │ │ │ ├── entity.go
│ │ │ │ ├── errors.go
│ │ │ │ └── service.go
│ │ │ └── infra/
│ │ │ ├── config.go
│ │ │ ├── mistral_ocr_client.go
│ │ │ └── mock_ocr_client.go
│ │ ├── polar/
│ │ │ ├── client.go
│ │ │ ├── cmd/
│ │ │ │ └── init.go
│ │ │ ├── config.go
│ │ │ ├── inject.go
│ │ │ └── webhook.go
│ │ ├── redis/
│ │ │ ├── README.md
│ │ │ ├── cmd/
│ │ │ │ ├── init.go
│ │ │ │ └── provider.go
│ │ │ ├── config.go
│ │ │ ├── init.go
│ │ │ ├── redis.go
│ │ │ └── store.go
│ │ ├── server/
│ │ │ ├── cmd/
│ │ │ │ ├── di.go
│ │ │ │ └── init.go
│ │ │ ├── config/
│ │ │ │ └── config.go
│ │ │ ├── domain/
│ │ │ │ ├── health.go
│ │ │ │ ├── http_server.go
│ │ │ │ ├── middleware.go
│ │ │ │ ├── middleware_resolver.go
│ │ │ │ ├── server.go
│ │ │ │ └── server_.go
│ │ │ ├── errors/
│ │ │ │ └── errors.go
│ │ │ ├── gin/
│ │ │ │ └── gin.go
│ │ │ ├── logging/
│ │ │ │ ├── logger.go
│ │ │ │ └── security_logger.go
│ │ │ ├── metrics/
│ │ │ │ └── prometheus.go
│ │ │ └── middleware/
│ │ │ ├── cors.go
│ │ │ ├── ip_protection.go
│ │ │ ├── ratelimit.go
│ │ │ ├── recovery.go
│ │ │ ├── request_id.go
│ │ │ ├── request_size_limit.go
│ │ │ ├── sanatization.go
│ │ │ ├── security_headers.go
│ │ │ ├── timeout.go
│ │ │ └── validator.go
│ │ └── stytch/
│ │ ├── client.go
│ │ ├── cmd/
│ │ │ └── provider.go
│ │ ├── config.go
│ │ ├── errors.go
│ │ ├── inject.go
│ │ └── rbac_policy.go
│ ├── pkg/
│ │ ├── httperr/
│ │ │ ├── errors.go
│ │ │ └── http_error.go
│ │ ├── pagination/
│ │ │ ├── pagination.go
│ │ │ ├── pramas.go
│ │ │ └── util.go
│ │ ├── response/
│ │ │ └── response.go
│ │ └── slugify/
│ │ └── slugify.go
│ └── scripts/
│ ├── migrate_down.sh
│ ├── migrate_up.sh
│ └── run_tests_with_coverage.sh
├── next_b2b_starter/
│ ├── .claude/
│ │ └── CLAUDE.md
│ ├── .dockerignore
│ ├── .env.example
│ ├── .eslintrc.json
│ ├── .npmrc
│ ├── Dockerfile
│ ├── README.md
│ ├── STYTCH_CONFIGURATION.md
│ ├── app/
│ │ ├── api/
│ │ │ ├── auth/
│ │ │ │ └── session/
│ │ │ │ └── refresh/
│ │ │ │ └── route.ts
│ │ │ └── billing/
│ │ │ └── webhook/
│ │ │ └── route.ts
│ │ ├── auth/
│ │ │ └── page.tsx
│ │ ├── authenticate/
│ │ │ └── page.tsx
│ │ ├── dashboard/
│ │ │ ├── knowledge/
│ │ │ │ ├── components/
│ │ │ │ │ ├── chat-interface.tsx
│ │ │ │ │ ├── chat-message.tsx
│ │ │ │ │ ├── document-list.tsx
│ │ │ │ │ ├── document-sources.tsx
│ │ │ │ │ ├── document-upload.tsx
│ │ │ │ │ ├── knowledge-content.tsx
│ │ │ │ │ └── knowledge-sidebar.tsx
│ │ │ │ ├── layout.tsx
│ │ │ │ └── page.tsx
│ │ │ ├── layout.tsx
│ │ │ ├── page.tsx
│ │ │ └── settings/
│ │ │ ├── components/
│ │ │ │ ├── invite-member.tsx
│ │ │ │ ├── member-list.tsx
│ │ │ │ ├── profile-section.tsx
│ │ │ │ ├── profile-tab.tsx
│ │ │ │ ├── settings-content.tsx
│ │ │ │ └── subscription-tab.tsx
│ │ │ ├── layout.tsx
│ │ │ └── page.tsx
│ │ ├── globals.css
│ │ ├── head.tsx
│ │ ├── layout.tsx
│ │ ├── not-found.tsx
│ │ ├── page.tsx
│ │ ├── robots.ts
│ │ ├── signup/
│ │ │ └── page.tsx
│ │ └── sitemap.ts
│ ├── components/
│ │ ├── auth/
│ │ │ ├── can.tsx
│ │ │ ├── permission-gate.tsx
│ │ │ └── stytch-provider.tsx
│ │ ├── billing/
│ │ │ ├── plans-modal.tsx
│ │ │ ├── subscription-alerts.tsx
│ │ │ └── subscription-paywall.tsx
│ │ ├── common/
│ │ │ └── obfuscated-email.tsx
│ │ ├── layout/
│ │ │ ├── dashboard-layout.tsx
│ │ │ ├── header.tsx
│ │ │ ├── sidebar.tsx
│ │ │ └── user-menu.tsx
│ │ ├── seo/
│ │ │ └── jsonld.tsx
│ │ └── ui/
│ │ ├── accordion.tsx
│ │ ├── alert.tsx
│ │ ├── avatar.tsx
│ │ ├── badge.tsx
│ │ ├── button.tsx
│ │ ├── calendar.tsx
│ │ ├── card.tsx
│ │ ├── checkbox.tsx
│ │ ├── date-picker.tsx
│ │ ├── dialog.tsx
│ │ ├── dropdown-menu.tsx
│ │ ├── form.tsx
│ │ ├── input.tsx
│ │ ├── label.tsx
│ │ ├── popover.tsx
│ │ ├── progress.tsx
│ │ ├── scroll-area.tsx
│ │ ├── select.tsx
│ │ ├── separator.tsx
│ │ ├── sheet-header.tsx
│ │ ├── sheet.tsx
│ │ ├── skeleton.tsx
│ │ ├── slider.tsx
│ │ ├── switch.tsx
│ │ ├── table.tsx
│ │ ├── tabs.tsx
│ │ └── textarea.tsx
│ ├── components.json
│ ├── docs/
│ │ ├── 01-getting-started.md
│ │ ├── 02-authentication.md
│ │ ├── 03-permissions-and-roles.md
│ │ ├── 04-payments-and-billing.md
│ │ ├── 05-making-api-requests.md
│ │ ├── 06-creating-pages.md
│ │ ├── 07-creating-apis.md
│ │ ├── 08-using-hooks.md
│ │ ├── 09-adding-a-feature.md
│ │ ├── 10-server-actions.md
│ │ ├── 11-feature-guards.md
│ │ ├── 12-subscription-patterns.md
│ │ ├── API-LOGGING.md
│ │ └── README.md
│ ├── hooks/
│ │ ├── use-signup-flow.ts
│ │ └── use-toast.ts
│ ├── lib/
│ │ ├── actions/
│ │ │ ├── auth/
│ │ │ │ ├── consume-magic-link.ts
│ │ │ │ ├── logout.ts
│ │ │ │ └── send-magic-link.ts
│ │ │ └── billing/
│ │ │ ├── cancel-subscription.ts
│ │ │ ├── create-checkout.ts
│ │ │ ├── get-products.ts
│ │ │ ├── get-subscription-status.ts
│ │ │ └── verify-payment.ts
│ │ ├── api/
│ │ │ └── api/
│ │ │ ├── client/
│ │ │ │ └── api-client.ts
│ │ │ ├── dto/
│ │ │ │ ├── auth.dto.ts
│ │ │ │ ├── cognitive.dto.ts
│ │ │ │ ├── document.dto.ts
│ │ │ │ ├── member.dto.ts
│ │ │ │ ├── organization.dto.ts
│ │ │ │ ├── profile.dto.ts
│ │ │ │ └── rbac.dto.ts
│ │ │ └── repositories/
│ │ │ ├── cognitive-repository.ts
│ │ │ ├── document-repository.ts
│ │ │ ├── member-repository.ts
│ │ │ ├── profile-repository.ts
│ │ │ ├── rbac-repository.ts
│ │ │ └── signup-repository.ts
│ │ ├── auth/
│ │ │ ├── README.md
│ │ │ ├── bootstrap.ts
│ │ │ ├── config-types.ts
│ │ │ ├── constants.ts
│ │ │ ├── permission-utils.ts
│ │ │ ├── permissions.ts
│ │ │ ├── server-constants.ts
│ │ │ ├── server-permissions.ts
│ │ │ ├── stytch/
│ │ │ │ └── server.ts
│ │ │ ├── stytch-client.ts
│ │ │ ├── stytch-server.ts
│ │ │ ├── stytch.ts
│ │ │ ├── subscription.ts
│ │ │ └── token-utils.ts
│ │ ├── contexts/
│ │ │ ├── auth-context.tsx
│ │ │ └── stytch-config-context.tsx
│ │ ├── hooks/
│ │ │ ├── mutations/
│ │ │ │ ├── use-chat.ts
│ │ │ │ ├── use-delete-document.ts
│ │ │ │ ├── use-invite-member.ts
│ │ │ │ ├── use-remove-member.ts
│ │ │ │ ├── use-resend-invitation.ts
│ │ │ │ ├── use-update-profile.ts
│ │ │ │ └── use-upload-document.ts
│ │ │ ├── queries/
│ │ │ │ ├── query-keys.ts
│ │ │ │ ├── use-documents-query.ts
│ │ │ │ ├── use-members-query.ts
│ │ │ │ ├── use-products-query.ts
│ │ │ │ ├── use-profile-query.ts
│ │ │ │ ├── use-sessions-query.ts
│ │ │ │ └── use-subscription-query.ts
│ │ │ └── use-permissions.ts
│ │ ├── models/
│ │ │ ├── cognitive.model.ts
│ │ │ ├── document.model.ts
│ │ │ ├── member.model.ts
│ │ │ └── signup.model.ts
│ │ ├── polar/
│ │ │ ├── client.ts
│ │ │ ├── config.ts
│ │ │ ├── current-subscription.ts
│ │ │ ├── plans.ts
│ │ │ ├── server-meters.ts
│ │ │ ├── server-products.ts
│ │ │ ├── subscription.ts
│ │ │ └── usage.ts
│ │ ├── providers/
│ │ │ └── query-provider.tsx
│ │ ├── stores/
│ │ │ └── sidebar-store.ts
│ │ ├── types/
│ │ │ └── loadable.ts
│ │ ├── utils/
│ │ │ ├── api-logger.ts
│ │ │ ├── password-generator.ts
│ │ │ └── server-action-helpers.ts
│ │ └── utils.ts
│ ├── lint/
│ │ └── README.md
│ ├── next-env.d.ts
│ ├── next.config.ts
│ ├── package.json
│ ├── postcss.config.js
│ ├── proxy.ts
│ ├── scripts/
│ │ ├── convert-svg-to-png.js
│ │ ├── generate-favicons.js
│ │ └── generate-og-images.js
│ ├── stores/
│ │ └── ui-store.ts
│ ├── tailwind.config.ts
│ └── tsconfig.json
└── setup.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
indent_style = space
indent_size = 4
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.go]
indent_style = tab
[*.{js,ts,tsx,json,yml,yaml}]
indent_style = space
indent_size = 2
================================================
FILE: .gitignore
================================================
# --- Global OS Files ---
.DS_Store
Thumbs.db
# --- Global Editor Files ---
.idea/
.vscode/
*.swp
*.swo
# --- Secrets (Safety Net) ---
# We ignore these here just in case someone accidentally
# creates an .env file in the root.
.env
.env.*
# But allow .env.example and example.env files (templates for users)
!.env.example
!**/.env.example
!**/example.env
*.pem
*.key
# --- Claude Code ---
# Ignore .claude/ contents but allow CLAUDE.md files
.claude/*
!.claude/CLAUDE.md
**/.claude/*
!**/.claude/CLAUDE.md
# --- Logs ---
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# --- Docker ---
# If you mount volumes locally
.docker/
postgres_data/
redis_data/
# --- Additional Safety Nets ---
# These provide defense-in-depth, even though subdirectory
# .gitignore files may already cover these patterns
tmp/
temp/
# Additional IDE files
*.sublime-*
.vscode-test/
# ==============================================================================
# PROJECT-SPECIFIC IGNORES
# ==============================================================================
# --- Go Backend (go-b2b-starter/) ---
# Go Environment Files
go-b2b-starter/.env
go-b2b-starter/.env.*
go-b2b-starter/app.env
# Binaries and Build Artifacts
go-b2b-starter/bin/
go-b2b-starter/dist/
go-b2b-starter/*.exe
go-b2b-starter/*.exe~
go-b2b-starter/*.dll
go-b2b-starter/*.so
go-b2b-starter/*.dylib
go-b2b-starter/*.test
go-b2b-starter/main
go-b2b-starter/src/main/main
go-b2b-starter/src/bin/main
# Go Temporary Files
go-b2b-starter/tmp/
go-b2b-starter/temp/
# Go Test Coverage
go-b2b-starter/coverage.out
go-b2b-starter/coverage.html
go-b2b-starter/coverage.txt
go-b2b-starter/coverage/
# Go Vendor
go-b2b-starter/vendor/
# --- Next.js Frontend (next_b2b_starter/) ---
# Next.js Environment Files
next_b2b_starter/.env.local
next_b2b_starter/.env.production
next_b2b_starter/.env.development
next_b2b_starter/.env
# Dependencies
next_b2b_starter/node_modules/
# Next.js Build Output
next_b2b_starter/.next/
next_b2b_starter/out/
next_b2b_starter/build/
# TypeScript Build Info
next_b2b_starter/*.tsbuildinfo
next_b2b_starter/.turbo/
================================================
FILE: CLAUDE.md
================================================
# CLAUDE.md
Guidance for Claude Code when working with this monorepo.
## Monorepo Structure
Production SaaS Starter - Enterprise-grade B2B SaaS boilerplate with Next.js 16 frontend and Go backend.
```
production-saas-starter/
├── go-b2b-starter/ # Go backend (API, auth, billing, AI/RAG)
├── next_b2b_starter/ # Next.js frontend (React 19, TypeScript)
├── setup.sh # One-line setup script
├── DEVELOPMENT.md # Development workflow guide
└── README.md # Project overview
```
## Quick Navigation
**Working on Backend?**
- See: `go-b2b-starter/.claude/CLAUDE.md`
- Key commands: `make server`, `make dev`, `make sqlc`, `make test`
- Tech: Go, Gin, PostgreSQL, SQLC, Stytch, Polar.sh
**Working on Frontend?**
- See: `next_b2b_starter/.claude/CLAUDE.md`
- Key commands: `pnpm dev`, `pnpm build`, `pnpm lint`
- Tech: Next.js 16, React 19, TypeScript, Tailwind, shadcn/ui, TanStack Query
## Getting Started
```bash
# One-line setup
chmod +x setup.sh && ./setup.sh
# Or manual start:
# Backend
cd go-b2b-starter
make run-deps # Start PostgreSQL
make migrateup # Apply migrations
make dev # Run with hot reload
# Frontend
cd next_b2b_starter
pnpm install
pnpm dev # Start Next.js dev server
```
## Architecture Overview
| Component | Technology | Purpose |
|-----------|------------|---------|
| **Authentication** | Stytch B2B | Magic links, RBAC, multi-tenant |
| **Billing** | Polar.sh | Subscriptions, webhooks, usage metering |
| **Database** | PostgreSQL + SQLC | Type-safe queries, pgvector |
| **Backend** | Go + Gin | Clean Architecture, DI (uber-go/dig) |
| **Frontend** | Next.js 16 + React 19 | Server Actions, TanStack Query |
| **Styling** | Tailwind + shadcn/ui | Consistent design system |
## Key Patterns
### Backend (Go)
- **Clean Architecture**: domain -> app -> infra layers
- **Repository Pattern**: Domain interfaces implemented by SQLC-backed repos
- **Event Bus**: Loose coupling between modules
- **RBAC Middleware**: Permission-based route protection
### Frontend (Next.js)
- **Server Actions**: For mutations with auth/permission guards
- **TanStack Query**: Server state management with caching
- **Repository Pattern**: API client abstractions
- **Type Safety**: Strict TypeScript throughout
## Documentation
- `DEVELOPMENT.md` - Development workflow and setup
- `SETUP.md` - Initial project configuration
- `go-b2b-starter/docs/` - Backend documentation
- `next_b2b_starter/docs/` - Frontend documentation
================================================
FILE: Caddyfile
================================================
# Caddyfile - Production reverse proxy configuration
#
# Routes traffic between Next.js frontend and Go backend:
# - Next.js internal API routes stay in frontend container
# - Go backend API routes go to backend container
# - Everything else (pages, assets) goes to frontend
#
# Usage:
# Set DOMAIN environment variable or it defaults to localhost
# For production: DOMAIN=yourdomain.com docker compose up
{$DOMAIN:localhost} {
# =========================================================================
# Next.js internal API routes (must go to frontend)
# These are handled by Next.js API routes, not the Go backend
# =========================================================================
# Auth session management (handled by Next.js)
handle /api/auth/session/* {
reverse_proxy frontend:3000
}
# Billing webhook (handled by Next.js for Polar.sh)
handle /api/billing/webhook {
reverse_proxy frontend:3000
}
# Next.js health check
handle /api/health {
reverse_proxy frontend:3000
}
# =========================================================================
# Go Backend API routes
# All other /api/* routes go to the Go backend
# =========================================================================
handle /api/* {
reverse_proxy backend:8080
}
# Backend health check (optional, for container orchestration)
handle /health {
reverse_proxy backend:8080
}
# =========================================================================
# Frontend - Everything else (pages, assets, etc.)
# =========================================================================
handle {
reverse_proxy frontend:3000
}
}
================================================
FILE: DEVELOPMENT.md
================================================
# 🛠️ Local Development Setup
Complete guide to running the Production SaaS Starter Kit locally.
---
## 📋 Prerequisites
Install these tools before starting:
| Tool | Version | Purpose |
|------|---------|---------|
| **Docker Desktop** | Latest | Runs PostgreSQL + Redis containers |
| **Go** | 1.25+ | Backend server |
| **Node.js** | 20+ | Frontend build |
| **pnpm** | 9+ | Frontend package manager |
> **Note:** You do NOT need to install PostgreSQL or Redis directly — Docker handles them.
---
### 🐳 Install Docker Desktop
Docker runs PostgreSQL and Redis in containers so you don't need to install them directly.
**macOS:**
```bash
# Option 1: Homebrew
brew install --cask docker
# Option 2: Direct download
# https://www.docker.com/products/docker-desktop/
```
**Windows:**
1. Download from https://www.docker.com/products/docker-desktop/
2. Run installer
3. Enable WSL 2 when prompted
**Linux (Ubuntu/Debian):**
```bash
# Add Docker's official GPG key
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Add your user to docker group (logout/login required)
sudo usermod -aG docker $USER
```
After installing, **open Docker Desktop** and wait for it to start before proceeding.
---
### 🐹 Install Go
The backend requires Go 1.25 or higher.
**macOS:**
```bash
# Option 1: Homebrew (recommended)
brew install go
# Option 2: Direct download
# https://go.dev/dl/
```
**Windows:**
1. Download from https://go.dev/dl/
2. Run the MSI installer
3. Restart terminal after install
**Linux:**
```bash
# Download latest (check https://go.dev/dl/ for current version)
wget https://go.dev/dl/go1.25.0.linux-amd64.tar.gz
# Remove old version and extract new
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.25.0.linux-amd64.tar.gz
# Add to PATH (add to ~/.bashrc or ~/.zshrc)
export PATH=$PATH:/usr/local/go/bin
```
---
### 📦 Install Node.js
The frontend requires Node.js 20 or higher. We recommend using **nvm** (Node Version Manager) to manage Node versions.
**macOS/Linux — Install nvm:**
```bash
# Install nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
# Restart terminal, then install Node 20
nvm install 20
nvm use 20
nvm alias default 20
```
**Windows — Install nvm-windows:**
1. Download from https://github.com/coreybutler/nvm-windows/releases
2. Run the installer
3. Open new terminal:
```bash
nvm install 20
nvm use 20
```
**Alternative — Direct install (without nvm):**
```bash
# macOS
brew install node@20
# Or download from https://nodejs.org/
```
---
### 📦 Install pnpm
pnpm is our package manager for the frontend (faster than npm, saves disk space).
```bash
# After Node is installed
npm install -g pnpm
```
Or use Corepack (built into Node 16.13+):
```bash
corepack enable
corepack prepare pnpm@latest --activate
```
---
### ✅ Verify Installation
Run these commands to confirm everything is installed correctly:
```bash
docker --version # Docker version 24+
go version # go1.25+
node --version # v20+
pnpm --version # 9+
```
All four should return version numbers. If any command fails, revisit the install steps above.
---
## 📁 Project Structure
```
production-saas-starter/
├── go-b2b-starter/ # Go backend
├── next_b2b_starter/ # Next.js frontend
├── deps/ # Docker Compose files
└── setup.sh # Automated setup script
```
---
## 🚀 First-Time Setup
### 1. Clone the Repository
```bash
git clone <repo-url>
cd production-saas-starter
```
### 2. Start Backend Services
```bash
cd go-b2b-starter
# Start PostgreSQL + Redis containers
make run-deps
# Wait for containers to be healthy, then run migrations
make migrateup
```
### 3. Configure Frontend Environment
```bash
cd next_b2b_starter
# Copy environment template
cp .env.example .env.local
# Edit .env.local and fill in:
# - STYTCH_PROJECT_ID
# - STYTCH_SECRET
# - NEXT_PUBLIC_STYTCH_PUBLIC_TOKEN
# - POLAR_ACCESS_TOKEN (if using billing)
```
### 4. Install Frontend Dependencies
```bash
pnpm install
```
### 5. Start Development Servers
**Terminal 1 — Backend:**
```bash
cd go-b2b-starter
make dev
```
**Terminal 2 — Frontend:**
```bash
cd next_b2b_starter
pnpm dev
```
### 6. Access the App
| Service | URL |
|---------|-----|
| Frontend | http://localhost:3000 |
| Backend API | http://localhost:8080 |
| API Docs (Swagger) | http://localhost:8080/swagger/index.html |
---
## 📅 Daily Workflow
### Starting Your Day
```bash
# Terminal 1: Start database containers (if not running)
cd go-b2b-starter
make run-deps
# Terminal 2: Start backend with hot reload
cd go-b2b-starter
make dev
# Terminal 3: Start frontend
cd next_b2b_starter
pnpm dev
```
### Ending Your Day
```bash
# Stop the Go server: Ctrl+C in Terminal 2
# Stop the Next.js server: Ctrl+C in Terminal 3
# Optional: Stop database containers (data persists)
cd go-b2b-starter
make stop-deps
```
---
## 📋 Commands Cheat Sheet
### Backend (Go)
Run from `go-b2b-starter/`:
| Command | Description |
|---------|-------------|
| `make run-deps` | Start PostgreSQL + Redis containers |
| `make stop-deps` | Stop and remove containers |
| `make dev` | Start server with hot reload (Air) |
| `make server` | Start server without hot reload |
| `make migrateup` | Apply database migrations |
| `make migratedown` | Rollback migrations |
| `make create-migration MIGRATION_NAME=add_users` | Create new migration |
| `make sqlc` | Generate Go code from SQL queries |
| `make test` | Run tests |
| `make swagger` | Regenerate Swagger docs |
| `make build` | Build production binary |
### Frontend (Next.js)
Run from `next_b2b_starter/`:
| Command | Description |
|---------|-------------|
| `pnpm dev` | Start development server |
| `pnpm build` | Build for production |
| `pnpm start` | Start production server |
| `pnpm lint` | Run ESLint |
---
## 🔌 Service Ports
| Service | Port | Notes |
|---------|------|-------|
| Next.js Frontend | 3000 | Turbopack hot reload |
| Go Backend | 8080 | Air hot reload |
| PostgreSQL | 5432 | pgvector enabled |
| Redis | 6379 | For caching/sessions |
---
## 🗄️ Database Access
### Connect via psql
```bash
psql -h localhost -p 5432 -U user -d mydatabase
# Password: password
```
### Connect via GUI (TablePlus, DBeaver, etc.)
| Field | Value |
|-------|-------|
| Host | localhost |
| Port | 5432 |
| User | user |
| Password | password |
| Database | mydatabase |
### Database Credentials
Defined in `go-b2b-starter/deps/docker-compose.yml`:
```yaml
POSTGRES_DB: mydatabase
POSTGRES_USER: user
POSTGRES_PASSWORD: password
```
---
## 🔐 Environment Variables
### Backend
The backend uses Docker environment variables defined in `deps/docker-compose.yml`. No `.env` file needed for local dev.
### Frontend
Required variables in `.env.local`:
```bash
# App URLs
APP_BASE_URL=http://localhost:3000
NEXT_PUBLIC_APP_BASE_URL=http://localhost:3000
# Stytch B2B Auth (required)
STYTCH_PROJECT_ID=project-test-xxx
STYTCH_SECRET=secret-test-xxx
STYTCH_PROJECT_ENV=test
NEXT_PUBLIC_STYTCH_PROJECT_ENV=test
NEXT_PUBLIC_STYTCH_PUBLIC_TOKEN=public-token-test-xxx
# Polar Billing (optional for dev)
POLAR_ACCESS_TOKEN=
POLAR_WEBHOOK_SECRET=
```
Get Stytch credentials from: https://stytch.com/dashboard
---
## 🔧 Troubleshooting
### Docker containers won't start
```bash
# Check if Docker is running
docker info
# Check container status
docker ps -a
# View container logs
docker compose -f deps/docker-compose.yml logs postgres
docker compose -f deps/docker-compose.yml logs redis
# Nuclear option: remove everything and start fresh
make stop-deps
docker volume rm deps_postgres_data deps_redis_data
make run-deps
```
### Port already in use
```bash
# Find what's using the port
lsof -i :5432 # PostgreSQL
lsof -i :8080 # Backend
lsof -i :3000 # Frontend
# Kill the process
kill -9 <PID>
```
### Migration errors
```bash
# Check migration status
docker compose -f deps/docker-compose.yml run --rm cli migrate -path ./internal/db/postgres/sqlc/migrations -database "postgresql://user:password@postgres:5432/mydatabase?sslmode=disable" version
# Force to specific version if stuck
docker compose -f deps/docker-compose.yml run --rm cli migrate -path ./internal/db/postgres/sqlc/migrations -database "postgresql://user:password@postgres:5432/mydatabase?sslmode=disable" force <VERSION>
```
### SQLC generation fails
```bash
# Make sure containers are running
make run-deps
# Check sqlc.yaml configuration
cat internal/db/postgres/sqlc/sqlc.yaml
# Run sqlc with verbose output
docker compose -f deps/docker-compose.yml run --rm -w /workspace/internal/db/postgres/sqlc cli sqlc generate
```
### Hot reload not working (Backend)
Air watches for file changes. If it's not working:
```bash
# Check Air is installed in container
docker compose -f deps/docker-compose.yml run --rm cli which air
# Restart with fresh build
make stop-deps
make run-deps
make dev
```
### Hot reload not working (Frontend)
```bash
# Clear Next.js cache
rm -rf .next
# Restart
pnpm dev
```
### Can't connect to backend from frontend
1. Check backend is running: http://localhost:8080/health
2. Check CORS settings in backend
3. Verify API URL in frontend matches backend port
---
## 💡 Tips
### VS Code Extensions
Recommended for this project:
- **Go** — Go language support
- **ESLint** — JavaScript/TypeScript linting
- **Tailwind CSS IntelliSense** — Tailwind autocomplete
- **Docker** — Docker file support
- **PostgreSQL** — SQL syntax highlighting
### Multiple Terminals
Use a terminal multiplexer or VS Code's integrated terminals:
```
┌─────────────────────────────────────────┐
│ Terminal 1: make run-deps (background) │
├─────────────────────────────────────────┤
│ Terminal 2: make dev (backend) │
├─────────────────────────────────────────┤
│ Terminal 3: pnpm dev (frontend) │
└─────────────────────────────────────────┘
```
### Fast Iteration Cycle
1. Make code changes
2. Save file (hot reload triggers)
3. Test in browser
4. Repeat
No manual restart needed thanks to Air (Go) and Turbopack (Next.js).
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2025 Mohammed Salim
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# ⭐ Production SaaS Starter Kit
The Enterprise-Grade SaaS boilerplate for serious founders. Built with **Next.js 16** and **Go 1.25**.
[](https://goreportcard.com/report/github.com/moasq/production-saas-starter)
[](https://opensource.org/licenses/MIT)

## 🛠️ Built With
### Frontend Stack
- **[Next.js 16](https://nextjs.org)** (v16.0.10)
Modern React framework with App Router and API routes.
- **[React 19](https://react.dev)** (v19.2.3)
Latest React with improved performance and concurrent features.
- **[TypeScript](https://www.typescriptlang.org)** (v5.7.3)
Type-safe JavaScript for enhanced developer experience.
- **[Tailwind CSS](https://tailwindcss.com)** (v3.4.17)
Utility-first CSS framework for rapid UI development.
- **[shadcn/ui](https://ui.shadcn.com)** + **Radix UI**
Accessible component library with 29+ pre-built components.
- **[TanStack Query](https://tanstack.com/query)** (v5.90.5)
Powerful data fetching and state management.
- **[Zustand](https://zustand-demo.pmnd.rs)** (v5.0.8)
Lightweight state management for UI state.
- **[react-hook-form](https://react-hook-form.com)** + **[Zod](https://zod.dev)**
Type-safe forms with schema validation.
- **[Stytch](https://stytch.com)**
Enterprise authentication with magic links, OAuth, and SSO.
- **[Polar.sh](https://polar.sh)**
Billing integration and subscription management.
- **[Recharts](https://recharts.org)**
Composable charting library for data visualization.
### Backend Stack
- **[Go 1.25](https://go.dev)**
High-performance, concurrent backend with excellent tooling.
- **[Gin](https://gin-gonic.com)**
Fast HTTP web framework with middleware support.
- **[PostgreSQL](https://www.postgresql.org)** with **[pgvector](https://github.com/pgvector/pgvector)**
Reliable relational database with vector similarity search.
- **[SQLC](https://sqlc.dev)**
Type-safe SQL compiler for Go (no ORM).
- **[Stytch B2B](https://stytch.com)**
Enterprise authentication, SSO, and RBAC.
- **[Polar.sh](https://polar.sh)**
Merchant of Record for subscriptions, invoicing, and global tax compliance.
- **[OpenAI API](https://openai.com)**
LLM integration with RAG pipeline and vector embeddings.
- **[Mistral AI](https://mistral.ai)**
OCR service for document data extraction.
- **[Cloudflare R2](https://www.cloudflare.com/products/r2/)**
Object storage for file management.
- **[Docker](https://www.docker.com)** + **Docker Compose**
Containerization for consistent environments.
## 🥇 Features
- **Authentication**: Sign in with Magic Link, Google OAuth, and Enterprise SSO.
- **Multi-Tenancy**: Built-in Organization support with strict data isolation.
- **Roles & Permissions**: Granular RBAC system with 3 roles (Member, Manager, Admin) and 7 permission types.
- **Billing & Subscriptions**: Complete integration with Polar.sh for SaaS pricing models.
- **AI & RAG**: Ready-to-use vector embeddings pipeline for AI features.
- **OCR Service**: Extract structured data from valid documents instantly.
- **Team Management**: Invite members, manage roles, and update settings.
- **Responsive Design**: Mobile-first UI built with Tailwind CSS and shadcn/ui.
- **Type Safety**: End-to-end type safety from database (SQLC) to frontend (TypeScript).
## ➡️ Coming Soon
- **Audit Logs**: Complete audit logging system for tracking user activities.
- **Webhooks UI**: Customer-facing webhook configuration.
- **Advanced Analytics**: Built-in charts and usage tracking.
## ✨ Getting Started
Please follow these simple steps to get a local copy up and running.
### Prerequisites
- **Docker** & **Docker Compose**
- **Go 1.25+**
- **Node.js 20+** & **pnpm**
### The One-Line Setup
Run this command to configure your keys and start the infrastructure:
```bash
chmod +x setup.sh && ./setup.sh
```
**Manual Start:**
1. **Backend:** `cd go-b2b-starter && make dev`
2. **Frontend:** `cd next_b2b_starter && pnpm dev`
3. **Visit:** [http://localhost:3000](http://localhost:3000)
> [!IMPORTANT]
> See **[SETUP.md](./SETUP.md)** for quick setup or **[DEVELOPMENT.md](./DEVELOPMENT.md)** for comprehensive guidance including multi-platform prerequisites, troubleshooting, and daily workflow tips.
## 🛡️ License
[MIT License](./LICENSE)
## 👯 Consulting & Services
Although this kit is self-service, I help ambitious founders move faster.
**I can help you with:**
1. **Managed Config:** I sets up your AWS/GCP production environment so you never touch DevOps.
2. **Custom Features:** Need SAML SSO or complex RAG flows? I'll build them directly into your repo.
3. **Code Audits:** Migrating from Node/Python? I'll review your architecture for scale.
**[m.salim@apflowhq.com](mailto:m.salim@apflowhq.com)** • [**@foundmod**](https://x.com/foundmod)
================================================
FILE: SECURITY.md
================================================
# Security Policy
## Supported Versions
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
| ------- | ------------------ |
| 1.0.x | :white_check_mark: |
| < 1.0 | :x: |
## Reporting a Vulnerability
We take the security of this starter kit seriously. If you find a vulnerability, please **DO NOT** open a public issue.
================================================
FILE: SETUP.md
================================================
# 🛠️ Setup Guide
> **Looking for detailed setup?** See **[DEVELOPMENT.md](./DEVELOPMENT.md)** for comprehensive guidance including multi-platform prerequisites, troubleshooting, database access, and daily workflow tips.
This document covers the manual steps to verify your environment if `setup.sh` is not sufficient.
## 1. Environment Variables
The kit comes with example files. You need to copy them to the "live" filenames.
### Backend (`go-b2b-starter`)
```bash
cp go-b2b-starter/example.env go-b2b-starter/app.env
```
Open `app.env` and fill in the keys:
* `DB_SOURCE`: Your Postgres connection string.
* `STYTCH_PROJECT_ID`: From Stytch Dashboard.
* `POLAR_ACCESS_TOKEN`: From Polar.sh.
### Frontend (`next_b2b_starter`)
```bash
cp next_b2b_starter/.env.example next_b2b_starter/.env.local
```
Update `.env.local` with your public API keys.
## 2. Docker Dependencies
If you prefer running dependencies manually (without `setup.sh`):
```bash
cd go-b2b-starter
docker compose -f deps/docker-compose.yml up -d postgres redis
```
## 3. Database Migrations
Once Docker is running, you must apply the schema:
```bash
cd go-b2b-starter
make migrateup
```
## 4. Troubleshooting
If the backend fails to start, verify that Redis is reachable on port `6379`.
================================================
FILE: docker-compose.production.yml
================================================
# Production Docker Compose
# Copy to docker-compose.yml and configure with your .env file
#
# Required environment variables in .env:
# - POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB
# - STYTCH_PROJECT_ID, STYTCH_SECRET, STYTCH_PROJECT_ENV
# - NEXT_PUBLIC_STYTCH_PUBLIC_TOKEN, NEXT_PUBLIC_STYTCH_PROJECT_ID
# - NEXT_PUBLIC_APP_BASE_URL
# - POLAR_ACCESS_TOKEN (if using billing)
services:
# =============================================================================
# Reverse Proxy - Routes traffic between frontend and backend
# =============================================================================
caddy:
image: caddy:2-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
environment:
- DOMAIN=${DOMAIN:-localhost}
depends_on:
- frontend
- backend
restart: unless-stopped
# =============================================================================
# Frontend - Next.js application
# =============================================================================
frontend:
build:
context: ./next_b2b_starter
dockerfile: Dockerfile
args:
- NEXT_PUBLIC_APP_BASE_URL=${NEXT_PUBLIC_APP_BASE_URL}
- NEXT_PUBLIC_API_BASE_URL=${NEXT_PUBLIC_API_BASE_URL:-/api}
- NEXT_PUBLIC_STYTCH_PUBLIC_TOKEN=${NEXT_PUBLIC_STYTCH_PUBLIC_TOKEN}
- NEXT_PUBLIC_STYTCH_PROJECT_ID=${NEXT_PUBLIC_STYTCH_PROJECT_ID}
- NEXT_PUBLIC_STYTCH_PROJECT_ENV=${NEXT_PUBLIC_STYTCH_PROJECT_ENV:-test}
- NEXT_PUBLIC_POLAR_API_SANDBOX_ACCESS_TOKEN=${NEXT_PUBLIC_POLAR_API_SANDBOX_ACCESS_TOKEN:-}
- NEXT_PUBLIC_POLAR_API_PRODUCTION_ACCESS_TOKEN=${NEXT_PUBLIC_POLAR_API_PRODUCTION_ACCESS_TOKEN:-}
environment:
# Runtime environment variables for Server Actions
- API_BASE_URL_INTERNAL=http://backend:8080/api
- STYTCH_PROJECT_ID=${STYTCH_PROJECT_ID}
- STYTCH_SECRET=${STYTCH_SECRET}
- STYTCH_PROJECT_ENV=${STYTCH_PROJECT_ENV:-test}
expose:
- "3000"
depends_on:
- backend
restart: unless-stopped
# =============================================================================
# Backend - Go API server
# =============================================================================
backend:
build:
context: ./go-b2b-starter
dockerfile: Dockerfile
environment:
- POSTGRES_HOST=postgres
- POSTGRES_PORT=5432
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
- REDIS_HOST=redis
- REDIS_PORT=6379
- STYTCH_PROJECT_ID=${STYTCH_PROJECT_ID}
- STYTCH_SECRET=${STYTCH_SECRET}
- STYTCH_PROJECT_ENV=${STYTCH_PROJECT_ENV:-test}
- POLAR_ACCESS_TOKEN=${POLAR_ACCESS_TOKEN:-}
expose:
- "8080"
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
restart: unless-stopped
# =============================================================================
# Database - PostgreSQL with pgvector
# =============================================================================
postgres:
image: pgvector/pgvector:pg17
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
# =============================================================================
# Cache - Redis
# =============================================================================
redis:
image: redis:alpine
volumes:
- redis_data:/data
restart: unless-stopped
volumes:
postgres_data:
redis_data:
caddy_data:
caddy_config:
================================================
FILE: go-b2b-starter/.air.toml
================================================
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"
[build]
args_bin = []
bin = "./tmp/main"
cmd = "go build -o ./tmp/main ./cmd/api/main.go"
delay = 1000
exclude_dir = ["tmp", "vendor", "testdata", "frontend-starter", "next_b2b_starter", "deps", "src"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false
[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"
[log]
main_only = false
time = false
[misc]
clean_on_exit = true
[screen]
clear_on_rebuild = false
keep_scroll = true
================================================
FILE: go-b2b-starter/.claude/CLAUDE.md
================================================
# CLAUDE.md
AI instructions for working with this Go B2B SaaS Starter Kit codebase.
## Project Overview
Go B2B SaaS Starter Kit - Invoice-to-pay lifecycle automation with AI-powered data extraction, duplicate detection, and payment optimization via Polar.sh integration.
**Architecture**: Modular monolith following Clean Architecture with clear module boundaries.
**Layers**:
- `internal/modules/*/` - Feature modules (domain/app/infra layers per module)
- `internal/platform/` - Cross-cutting concerns (logger, server, etc.)
- `internal/db/` - Database layer (SQLC adapters, DI registration)
- `internal/bootstrap/` - Application initialization
- `pkg/` - Shared utility packages (httperr, response)
- `cmd/api/` - Application entry point
**Core Patterns**:
- Clean Architecture (domain → app → infra)
- Dependency Injection (uber-go/dig)
- Repository Pattern (domain interfaces → store adapters)
- Adapter Pattern (limit SQLC exposure)
## Commands
```bash
# Development
make server # Run dev server
make build # Build binary
make deps # Update Go dependencies
# Database
make run-deps # Start PostgreSQL in Docker
make migrateup # Apply migrations
make migratedown # Rollback migrations
make sqlc # Generate Go code from SQL
# Testing
make test # Run tests with coverage
# Docker
make run-stack # Start full stack
make restart-app # Restart app container
```
## Database Layer (internal/db/)
**Structure**:
```
internal/db/
├── adapters/ # Legacy adapter interfaces (being phased out)
├── postgres/
│ ├── sqlc/
│ │ ├── migrations/ # SQL migration files
│ │ ├── query/ # SQL queries with SQLC annotations
│ │ └── gen/ # Generated code (DO NOT EDIT)
│ ├── adapter_impl/ # Legacy adapter implementations
│ └── postgres.go # DB connection and pooling
└── inject.go # DI registration for all domain repositories
```
**Key Principle**: Domain interfaces (defined in `internal/modules/*/domain/`) are implemented by repositories in `internal/modules/*/infra/repositories/`. The `internal/db/inject.go` registers these implementations in the DI container.
**SQLC Workflow**:
```
internal/db/postgres/sqlc/
├── migrations/ # SQL migration files
├── query/ # SQL queries with SQLC annotations
└── gen/ # Generated code (DO NOT EDIT)
```
### Adding Database Operations
**1. Define domain interface** in your module (`internal/modules/{module}/domain/repository.go`):
```go
package domain
type UserRepository interface {
GetByID(ctx context.Context, orgID, userID int32) (*User, error)
Create(ctx context.Context, user *User) (*User, error)
Update(ctx context.Context, user *User) (*User, error)
Delete(ctx context.Context, orgID, userID int32) error
}
```
**2. Write SQL query** (`internal/db/postgres/sqlc/query/{domain}.sql`):
```sql
-- name: GetUserByID :one
SELECT * FROM users WHERE organization_id = $1 AND id = $2;
-- name: CreateUser :one
INSERT INTO users (organization_id, email, full_name)
VALUES ($1, $2, $3)
RETURNING *;
```
**3. Generate SQLC code**:
```bash
make sqlc
```
**4. Implement repository** (`internal/modules/{module}/infra/repositories/{domain}_repository.go`):
```go
package repositories
import (
"github.com/moasq/go-b2b-starter/internal/modules/{module}/domain"
sqlc "github.com/moasq/go-b2b-starter/internal/db/postgres/sqlc/gen"
)
type userRepository struct {
store sqlc.Store
}
func NewUserRepository(store sqlc.Store) domain.UserRepository {
return &userRepository{store: store}
}
func (r *userRepository) GetByID(ctx context.Context, orgID, userID int32) (*domain.User, error) {
dbUser, err := r.store.GetUserByID(ctx, sqlc.GetUserByIDParams{
OrganizationID: orgID,
ID: userID,
})
if err != nil {
return nil, err
}
// Map SQLC type to domain type
return &domain.User{
ID: dbUser.ID,
OrganizationID: dbUser.OrganizationID,
Email: dbUser.Email,
FullName: dbUser.FullName,
}, nil
}
```
**5. Register in DI** (`internal/db/inject.go`):
```go
import (
userDomain "github.com/moasq/go-b2b-starter/internal/modules/users/domain"
userRepos "github.com/moasq/go-b2b-starter/internal/modules/users/infra/repositories"
)
// In registerDomainStores function:
if err := container.Provide(func(sqlcStore sqlc.Store) userDomain.UserRepository {
return userRepos.NewUserRepository(sqlcStore)
}); err != nil {
return fmt.Errorf("failed to provide user repository: %w", err)
}
```
**Why This Architecture**:
- Domain defines interfaces (Dependency Inversion Principle)
- Infra implements these interfaces using SQLC
- SQLC types never leak out of the infra layer
- Easy to mock for testing (depend on interface, not implementation)
- Clear separation of concerns
**Error Handling** (`core/errors.go`):
- `ErrNoRows`, `ErrTxClosed`, `ErrPoolClosed`, `ErrInvalidConnection`, `ErrTimeout`
- Helpers: `IsNoRowsError()`, `IsConstraintError()`, `IsTimeoutError()`
## Authentication (internal/modules/auth/)
**Provider-agnostic auth with Stytch integration**. Type-safe middleware for JWT verification, RBAC, and multi-tenant org context.
**Core Types**:
- `Identity` - User info from auth provider (email, roles, permissions)
- `RequestContext` - Resolved database IDs (OrganizationID, AccountID)
- `Permission` - Format `"resource:action"` (e.g., `"invoice:create"`)
**Middleware Setup**:
```go
authMiddleware := auth.NewMiddleware(authProvider, orgResolver, accResolver, nil)
// Apply middleware
router.Use(authMiddleware.RequireAuth()) // Verify JWT
router.Use(authMiddleware.RequireOrganization()) // Resolve org/account IDs
```
**Route Protection**:
```go
// Permission-based
router.POST("/invoices",
auth.RequirePermissionFunc("invoice", "create"),
handler.CreateInvoice)
// Role-based
router.DELETE("/orgs/:id",
authMiddleware.RequireRole(auth.RoleAdmin),
handler.DeleteOrg)
```
**Handler Context Access**:
```go
func (h *Handler) MyHandler(c *gin.Context) {
reqCtx := auth.GetRequestContext(c)
orgID := reqCtx.OrganizationID // int32
accountID := reqCtx.AccountID // int32
email := reqCtx.Identity.Email // string
// Or use convenience functions
orgID := auth.GetOrganizationID(c) // Safe: returns 0 if not set
accountID := auth.GetAccountID(c) // Safe: returns 0 if not set
}
```
**Common Permissions** (`permissions.go`):
```go
auth.PermInvoiceCreate // "invoice:create"
auth.PermInvoiceView // "invoice:view"
auth.PermInvoiceDelete // "invoice:delete"
auth.PermOrgView // "org:view"
auth.PermOrgManage // "org:manage"
```
**Configuration** (environment variables):
```env
STYTCH_PROJECT_ID=project-test-xxx-xxx # Required
STYTCH_SECRET=secret-test-xxx # Required
STYTCH_ENV=test # Optional: "test" or "live"
```
**See**: `internal/modules/auth/README.md` for detailed usage patterns and examples.
## File Manager (internal/modules/files/)
**Dual architecture**: Cloudflare R2 (object storage) + PostgreSQL (searchable metadata).
**Components**:
- `FileRepository` - Combined operations (upload, download, delete, search)
- `R2Repository` - R2 object storage operations
- `FileMetadataRepository` - Database metadata operations
- `FileService` - Business logic with validation
**Upload with Entity Linking**:
```go
req := &domain.FileUploadRequest{
Filename: "invoice_001.pdf",
ContentType: "application/pdf",
Context: file_manager.ContextInvoice,
}
file := &domain.FileAsset{
EntityType: "invoice",
EntityID: invoiceID,
}
uploadedFile, err := fileService.UploadFile(ctx, req, fileReader)
```
**Search Operations**:
```go
files, err := fileRepo.GetByEntity(ctx, "invoice", invoiceID)
documents, err := fileRepo.GetByCategory(ctx, file_manager.CategoryDocument, 10, 0)
receipts, err := fileRepo.GetByContext(ctx, file_manager.ContextReceipt, 20, 0)
```
**Atomic Transactions**:
1. Save metadata to DB (get ID)
2. Upload file to R2 (using DB ID in key)
3. Update metadata with storage path
4. Automatic rollback on failure
## Go Coding Standards
### Core Rules
**Use `any` instead of `interface{}`** (Go 1.18+):
```go
// ✅ Good
func ProcessData(data any) error
type Request struct { Metadata map[string]any }
// ❌ Bad
func ProcessData(data interface{}) error
```
**Error Wrapping**:
```go
// ✅ Good
if err := repo.Create(ctx, invoice); err != nil {
return fmt.Errorf("failed to create invoice %d: %w", invoice.ID, err)
}
```
**Context First**:
```go
// ✅ Good
func (s *service) ProcessInvoice(ctx context.Context, invoiceID int32) error
```
**Naming**:
- Packages: lowercase, single word (`invoice`, not `invoice_mgmt`)
- Interfaces: noun/adjective + "er" (`Repository`, `Handler`)
- Structs: PascalCase (`InvoiceService`, `PaymentRequest`)
- Methods: PascalCase verbs (`CreateInvoice`, `ValidateData`)
### Struct Organization
```go
type Invoice struct {
// Identifiers first
ID int32 `json:"id" db:"id"`
InvoiceNumber string `json:"invoice_number"`
// Core business data
Amount decimal.Decimal `json:"amount"`
DueDate time.Time `json:"due_date"`
// References
VendorID int32 `json:"vendor_id"`
// Timestamps last
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
```
### Dependency Injection
```go
// ✅ Constructor returns interface
func NewInvoiceService(
repo domain.InvoiceRepository,
logger logger.Logger,
) domain.InvoiceService {
return &invoiceService{repo: repo, logger: logger}
}
// ✅ Register in DI
container.Provide(NewInvoiceService)
```
### Event-Driven Patterns
```go
// ✅ Events are past tense, include all data
type InvoiceCreatedEvent struct {
BaseEvent
InvoiceID int32 `json:"invoice_id"`
Amount decimal.Decimal `json:"amount"`
CreatedAt time.Time `json:"created_at"`
}
```
### Testing
```go
// ✅ Table-driven tests
func TestInvoiceValidation(t *testing.T) {
tests := []struct {
name string
invoice *Invoice
wantErr bool
}{
{"valid", &Invoice{Amount: decimal.NewFromInt(100)}, false},
{"negative", &Invoice{Amount: decimal.NewFromInt(-100)}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.invoice.Validate()
if (err != nil) != tt.wantErr {
t.Errorf("got error = %v, want %v", err, tt.wantErr)
}
})
}
}
```
## API Development Pattern
**ALWAYS follow this pattern** for consistency and Clean Architecture compliance.
### Implementation Steps
**1. Database Layer** (if new data needed):
- Add SQLC queries: `internal/db/postgres/sqlc/query/{domain}.sql`
- Run `make sqlc`
- Define repository interface in `internal/modules/{module}/domain/repository.go`
- Implement repository in `internal/modules/{module}/infra/repositories/{domain}_repository.go`
- Register in DI: `internal/db/inject.go`
**2. Domain Layer** (`internal/modules/{module}/domain/`):
- Create entities with business types
- Define repository interfaces
- Add validation methods
**3. Infrastructure** (`internal/modules/{module}/infra/repositories/`):
- Implement repository interfaces using SQLC
- Map SQLC types ↔ domain types (never expose SQLC outside infra)
- Handle transactions
**4. Application** (`internal/modules/{module}/app/services/`):
- Define request/response DTOs
- Add service interface
- Implement business logic
**5. API Layer** (`internal/modules/{module}/`):
- Add handler with validation (`handler.go`)
- Add Swagger annotations (see Swagger Best Practices below)
- Register routes (`routes.go`)
- Wire dependencies in module initialization
### Required Handler Pattern
```go
func (h *Handler) OperationName(c *gin.Context) {
// 1. Extract path params
var entityID int32
if _, err := fmt.Sscanf(c.Param("id"), "%d", &entityID); err != nil {
c.JSON(400, httperr.NewHTTPError(400, "invalid_id", "Invalid ID"))
return
}
// 2. Get auth context
reqCtx := auth.GetRequestContext(c)
if reqCtx == nil {
c.JSON(401, httperr.NewHTTPError(401, "unauthorized", "Auth required"))
return
}
// 3. Bind request (if needed)
var req models.RequestDto
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, httperr.NewHTTPError(400, "invalid_request", err.Error()))
return
}
// 4. Call service
response, err := h.service.Operation(c.Request.Context(), reqCtx.OrganizationID, req)
if err != nil {
c.JSON(500, httperr.NewHTTPError(500, "operation_failed", err.Error()))
return
}
// 5. Return response
c.JSON(200, response)
}
```
### Swagger Best Practices
**CRITICAL**: Always use local type references in swagger annotations. Never use full package paths.
**✅ Correct**:
```go
// @Success 200 {object} domain.User "User details"
// @Success 201 {object} services.CreateUserResponse "Created user"
// @Failure 400 {object} httperr.HTTPError "Bad request"
// @Param request body services.CreateUserRequest true "User data"
```
**❌ Wrong**:
```go
// @Success 200 {object} github_com_moasq_go-b2b-starter_internal_modules_users_domain.User
// @Failure 400 {object} errors.HTTPError // Wrong package name
```
**Common Patterns**:
```go
// Handler in internal/modules/users/handler.go
import (
"github.com/moasq/go-b2b-starter/internal/modules/users/domain"
"github.com/moasq/go-b2b-starter/internal/modules/users/app/services"
"github.com/moasq/go-b2b-starter/pkg/httperr"
)
// @Summary Create user
// @Description Creates a new user in the organization
// @Tags users
// @Accept json
// @Produce json
// @Param request body services.CreateUserRequest true "User data"
// @Success 201 {object} domain.User "Created user"
// @Failure 400 {object} httperr.HTTPError "Invalid request"
// @Failure 500 {object} httperr.HTTPError "Internal error"
// @Router /api/users [post]
func (h *Handler) CreateUser(c *gin.Context) {
// Implementation
}
```
**Docker Compose Best Practices**:
When using docker-compose for CLI tools, use `${PWD}` for volume mounts:
```yaml
cli:
volumes:
- ${PWD}:/workspace # ✅ Correct - uses current directory
# - ../:/workspace # ❌ Wrong - relative paths don't work consistently
working_dir: /workspace
```
### Required Service Pattern
```go
func (s *service) Operation(ctx context.Context, orgID int32, req *Request) (*Response, error) {
// 1. Validate
if err := req.Validate(); err != nil {
return nil, err
}
// 2. Execute business logic
result, err := s.repo.Operation(ctx, orgID, req)
if err != nil {
return nil, fmt.Errorf("operation failed: %w", err)
}
// 3. Return
return result, nil
}
```
### Required Middleware Pattern
```go
// In routes.go
apiGroup := router.Group("/{domain}")
apiGroup.Use(
authMiddleware.RequireAuth(),
authMiddleware.RequireOrganization(),
)
{
apiGroup.POST("/path",
auth.RequirePermissionFunc("{resource}", "{action}"),
h.HandlerMethod)
}
```
### Mandatory Requirements
- **Context**: First parameter in all I/O operations
- **Error Wrapping**: `fmt.Errorf("context: %w", err)`
- **Validation**: At both entity and service levels
- **Logging**: Structured logging for operations
- **Middleware**: Auth, org context, permissions
- **Swagger**: Complete API documentation
- **Transactions**: Atomic operations where needed
### Testing Requirements
- Unit tests with mocked dependencies
- Integration tests with database
- Validation tests for all error scenarios
- Permission tests for access control
## Dependency Management
**Rule**: Use interface abstractions when dependencies aren't ready.
```go
// ✅ Good - Depend on interface
type OCRService interface {
ExtractData(ctx context.Context, fileID int32) (map[string]any, error)
}
// ✅ Good - Event-driven integration
func NewInvoiceService(eventBus eventbus.EventBus) InvoiceService {
// Publish events; other modules subscribe when ready
}
// ❌ Bad - Don't inject concrete types that don't exist
func NewInvoiceService(ocrService *OCRServiceImpl) InvoiceService {
// Fails if OCRServiceImpl doesn't exist
}
```
## Project Structure
```
go-b2b-starter/
├── cmd/api/ # Application entry point
├── internal/
│ ├── bootstrap/ # App initialization and wiring
│ ├── db/ # Database layer (SQLC, DI registration)
│ │ ├── postgres/sqlc/ # SQLC queries and generated code
│ │ ├── adapters/ # Legacy adapters (being phased out)
│ │ └── inject.go # Repository DI registration
│ ├── modules/ # Feature modules
│ │ ├── {module}/
│ │ │ ├── domain/ # Entities, interfaces, validation
│ │ │ ├── app/services/ # Business logic (use cases)
│ │ │ ├── infra/ # Repository implementations
│ │ │ ├── handler.go # HTTP handlers
│ │ │ ├── routes.go # Route definitions
│ │ │ └── module.go # Module DI setup
│ │ ├── auth/ # Authentication & RBAC
│ │ ├── billing/ # Polar.sh subscriptions
│ │ ├── organizations/ # Multi-tenant org management
│ │ ├── documents/ # PDF document management
│ │ ├── cognitive/ # RAG and embeddings
│ │ ├── files/ # File storage (R2 + metadata)
│ │ └── paywall/ # Subscription access gating
│ └── platform/ # Cross-cutting concerns
│ ├── logger/ # Structured logging
│ ├── server/ # HTTP server
│ ├── eventbus/ # Event pub-sub
│ ├── llm/ # LLM client
│ ├── ocr/ # OCR service
│ ├── redis/ # Redis client
│ └── stytch/ # Stytch B2B client
└── pkg/ # Public shared utilities
├── httperr/ # HTTP error responses
├── pagination/ # Pagination helpers
├── response/ # Standard API responses
└── slugify/ # Slug generation utilities
```
## Billing & Paywall (internal/modules/billing/)
**Polar.sh integration** with hybrid sync for subscriptions.
**Sync Strategy**:
1. **Webhooks** (primary) - Real-time updates from Polar.sh
2. **Active Verification** - Poll after checkout redirect
3. **Lazy Guarding** - Verify with API if local data suggests expired
**Paywall Middleware**:
```go
// Require active subscription
premiumGroup := router.Group("/premium")
premiumGroup.Use(
resolver.Get("auth"),
resolver.Get("org_context"),
resolver.Get("paywall"), // RequireActiveSubscription
)
// Optional subscription info
publicGroup.Use(resolver.Get("paywall_optional"))
```
**Quota Management**:
```go
// Check and consume quota
status, err := billingService.ConsumeInvoiceQuota(ctx, orgID)
if err == domain.ErrInsufficientQuota {
// Handle quota exhausted
}
```
## Event Bus (internal/platform/eventbus/)
**In-memory event bus** for loose coupling between modules.
**Define Event**:
```go
type DocumentUploadedEvent struct {
eventbus.BaseEvent
DocumentID int32 `json:"document_id"`
OrganizationID int32 `json:"organization_id"`
}
func NewDocumentUploadedEvent(docID, orgID int32) *DocumentUploadedEvent {
return &DocumentUploadedEvent{
BaseEvent: eventbus.NewBaseEvent("document.uploaded"),
DocumentID: docID,
OrganizationID: orgID,
}
}
```
**Publish**:
```go
event := NewDocumentUploadedEvent(doc.ID, orgID)
eventBus.Publish(ctx, event) // Fire-and-forget
```
**Subscribe**:
```go
eventBus.Subscribe("document.uploaded", func(ctx context.Context, event eventbus.Event) error {
docEvent := event.(*DocumentUploadedEvent)
return embeddingService.GenerateForDocument(ctx, docEvent.DocumentID)
})
```
## Module Initialization Order
**File**: `internal/bootstrap/bootstrap.go`
Order matters due to dependencies:
```go
// Phase 1: Infrastructure (no dependencies)
logger.Inject(container)
server.Inject(container)
db.Inject(container) // Registers all domain repositories
// Phase 2: Platform Services
redis.Inject(container)
llm.Inject(container)
ocr.Inject(container)
polar.Inject(container)
eventbus.Inject(container)
// Phase 3: Module Dependencies (order critical!)
files.SetupDependencies(container) // File storage
auth.SetupDependencies(container) // Auth, RBAC, resolvers
organizations.RegisterDependencies(container)
billing.Configure(container)
cognitive.RegisterDependencies(container)
documents.RegisterDependencies(container)
// Phase 4: Event Subscriptions
cognitive.SetupEventSubscriptions(container)
// Phase 5: HTTP Server Setup
server.SetupMiddleware(container)
```
## Named Middlewares
Access middleware by name in routes:
```go
func (r *Routes) Routes(router *gin.RouterGroup, resolver server.MiddlewareResolver) {
group := router.Group("/api")
group.Use(
resolver.Get("auth"), // RequireAuth
resolver.Get("org_context"), // RequireOrganization
resolver.Get("paywall"), // RequireActiveSubscription
resolver.Get("paywall_optional"), // OptionalSubscriptionStatus
resolver.Get("subscription"), // Deprecated alias
)
}
```
## Configuration
Environment-based configuration using `app.env` and `example.env`. Docker Compose for local dependencies.
## Documentation
Comprehensive documentation available in `docs/`:
- `docs/README.md` - Overview and quick start
- `docs/architecture.md` - Clean Architecture patterns
- `docs/database.md` - SQLC workflow and migrations
- `docs/authentication.md` - Auth, RBAC, Stytch integration
- `docs/billing.md` - Polar.sh and paywall
- `docs/file-manager.md` - R2 file storage
- `docs/event-bus.md` - Event-driven patterns
- `docs/api-development.md` - Step-by-step API guide
- `docs/modules/` - Module-specific documentation
================================================
FILE: go-b2b-starter/.dockerignore
================================================
# Environment and configuration files
app.env
.env
.air.toml
example.env
# Version control
.git
.gitignore
.gitlab-ci.yml
# IDE and editor files
.idea
.vscode
.claude
# Project files
Makefile
README.md
# Directories
docs/
deps/
deployment/
scripts/
tmp/
bin/
storage/
.scannerwork/
coverage/
/src/pkg/db/postgres/seed
/src/pkg/db/postgres/sqlc/migrations
/src/pkg/db/postgres/sqlc/query
/src/pkg/db/postgres/sqlc.yml
# Build artifacts
*.log
*.out
*.env
*.sql
# Docker files
Dockerfile
docker-compose.yml
================================================
FILE: go-b2b-starter/.gitignore
================================================
/api
================================================
FILE: go-b2b-starter/.gitlab-ci.yml
================================================
stages:
- test
- build
run-tests:
stage: test
image: golang:1.22.4
script:
- mkdir -p coverage
- bash scripts/run_tests_with_coverage.sh
artifacts:
paths:
- coverage/
reports:
coverage_report:
coverage_format: cobertura
path: coverage/coverage.xml
coverage: '/total:\s+\(statements\)\s+(\d+\.\d+)%/'
build-image:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest
- docker push $CI_REGISTRY_IMAGE:latest
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: on_success
================================================
FILE: go-b2b-starter/Dockerfile
================================================
# Builder stage
FROM golang:1.25-alpine3.20 AS builder
WORKDIR /app
# Install build dependencies
RUN apk add --no-cache git
# Copy go mod and sum files first for better caching
COPY go.mod go.sum ./
RUN go mod download
# Copy the source code
COPY . .
# Build the application with additional flags for production
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o /main ./cmd/api/main.go
# Final stage - using Alpine for smaller image with necessary system files
FROM alpine:3.20
# Install necessary packages and clean up
RUN apk add --no-cache ca-certificates tzdata && \
rm -rf /var/cache/apk/*
# Create non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
# Copy only the binary from builder
COPY --from=builder /main /app/main
# Set proper permissions
RUN chown -R appuser:appgroup /app && \
chmod +x /app/main
# Use non-root user
USER appuser
# Image metadata
LABEL org.opencontainers.image.title="B2B SaaS Starter Backend" \
org.opencontainers.image.description="Go backend for B2B SaaS Starter" \
org.opencontainers.image.vendor="B2B SaaS Starter" \
org.opencontainers.image.version="1.0.0" \
org.opencontainers.image.source="https://github.com/yourusername/b2b-saas-starter"
# Expose the port your app runs on
EXPOSE 8080
# Command to run the application
ENTRYPOINT ["/app/main"]
================================================
FILE: go-b2b-starter/Makefile
================================================
COMPOSE_FILE := deps/docker-compose.yml
MIGRATION_PATH ?= schema/migration
POSTGRES_HOST ?= localhost
POSTGRES_PORT ?= 5432
POSTGRES_DB ?= mydatabase
POSTGRES_USER ?= user
POSTGRES_PASSWORD ?= password
CONTAINER_NAME ?= deps-postgis-1
MIGRATION_NAME ?= init_schema
MIGRATION_DIR ?= ./internal/db/postgres/sqlc/migrations
SQLC_DIR ?= internal/db/postgres/sqlc
# Start the necessary docker containers
run-deps:
docker compose -f $(COMPOSE_FILE) up --build -d
# Stop and remove docker containers
stop-deps:
docker compose -f $(COMPOSE_FILE) down -v
# Create a new database migration file
create-migration:
@docker compose -f $(COMPOSE_FILE) run --rm cli migrate create -ext sql -dir $(MIGRATION_DIR) -seq $(MIGRATION_NAME)
@echo "Migration created in $(MIGRATION_DIR) with name $(MIGRATION_NAME)"
# Apply all up migrations
# Apply all up migrations
migrateup:
@docker compose -f $(COMPOSE_FILE) run --rm cli migrate -path $(MIGRATION_DIR) -database "postgresql://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@postgres:$(POSTGRES_PORT)/$(POSTGRES_DB)?sslmode=disable" -verbose up
# Apply all down migrations
migratedown:
@docker compose -f $(COMPOSE_FILE) run --rm cli migrate -path $(MIGRATION_DIR) -database "postgresql://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@postgres:$(POSTGRES_PORT)/$(POSTGRES_DB)?sslmode=disable" -verbose down
sqlc:
@docker compose -f $(COMPOSE_FILE) run --rm -w /workspace/$(SQLC_DIR) cli sqlc generate
# Create a new module
create-module:
bash scripts/create_module.sh $(type) $(name)
if [ "$(db)" = "postgres" ]; then bash scripts/setup_db.sh $(type) $(name); fi
# Run the server
server:
go run ./cmd/api/main.go
# build the app
build:
go build -o bin/api ./cmd/api/main.go
# install dependencies
deps:
go mod tidy
# swagger
swagger:
@docker compose -f $(COMPOSE_FILE) run --rm cli swag init -g cmd/api/main.go -d . --parseDependency --parseInternal -o internal/docs/gen
# Run the server with Air (Live Reload)
dev:
@docker compose -f $(COMPOSE_FILE) run --rm -T --service-ports cli air
reload-profile:
@source ~/.bashrc
test:
@bash scripts/run_tests_with_coverage.sh
# Clear RBAC and JWKS caches from Redis
clear-rbac-cache:
@echo "Clearing RBAC and JWKS Redis caches..."
@redis-cli DEL "stytch:rbac:policy" || echo " ✗ Failed to clear stytch:rbac:policy (may not exist)"
@redis-cli DEL "stytch:jwks:cache" || echo " ✗ Failed to clear stytch:jwks:cache (may not exist)"
@echo "✓ Cache clearing attempted (caches will auto-expire if not manually cleared)"
.PHONY: \
build \
clear-rbac-cache \
create-migration \
create-module \
create-seed-country \
deps \
generate-seed-file \
generate-changed-seed-file \
generate-migrations-file \
generate-down-migrations-file \
migratedown \
migrateup \
push-to-do \
reload-profile \
run-deps \
seed-db \
server \
sonar-scanner \
sqlc \
swagger \
test
================================================
FILE: go-b2b-starter/README.md
================================================
# Go B2B Starter Backend
Professional Modular Monolith backend for B2B SaaS using idiomatic Go project layout.
## ⚡️ Quick Start
```bash
# 1. Start dependencies (Postgres, Redis)
cd deps && docker-compose up -d postgres redis
# 2. Copy environment config
cp example.env app.env
# 3. Run migrations
make migrateup
# 4. Start server with live reload
make dev
```
## 🏗 Project Layout (Go Standard 2026)
```
go-b2b-starter/
├── cmd/
│ └── api/ # Application entry point
│ └── main.go
│
├── internal/ # Private application code
│ ├── bootstrap/ # App initialization & DI wiring
│ ├── api/ # API route registration
│ │
│ ├── auth/ # Authentication & RBAC
│ ├── billing/ # Subscription & billing
│ ├── organizations/ # Multi-tenant org management
│ ├── documents/ # PDF document handling
│ ├── cognitive/ # AI/RAG chat features
│ │
│ ├── db/ # Database connections & SQLC
│ ├── server/ # HTTP server & middleware
│ ├── redis/ # Redis client
│ └── stytch/ # Stytch B2B auth adapter
│
├── pkg/ # Public reusable packages
│ ├── httperr/ # HTTP error types
│ ├── pagination/ # Pagination helpers
│ ├── response/ # API response helpers
│ └── slugify/ # String utilities
│
├── deps/ # Docker Compose for dependencies
├── docs/ # Documentation
└── go.mod # Single module (consolidated)
```
## 📚 Documentation
- **[Architecture Guide](./docs/01-architecture.md)** - Understand the layers
- **[Adding a Feature](./docs/02-adding-a-module.md)** - How to create new features
- **[API & Auth](./docs/03-api-and-auth.md)** - Security and Request flow
## 🛠 Key Commands
| Command | Description |
|---------|-------------|
| `make dev` | Start server with Air (Live Reload) |
| `make server` | Run server directly |
| `make build` | Build binary to `bin/api` |
| `make migrateup` | Apply DB migrations |
| `make sqlc` | Generate type-safe DB code |
| `make swagger` | Generate Swagger docs |
## 🔧 Module Structure
Each feature module in `internal/` follows **Clean Architecture**:
```
internal/billing/
├── cmd/ # Module initialization (DI)
│ └── init.go
├── app/ # Application layer (use cases)
│ └── services/
├── domain/ # Core business logic & interfaces
├── infra/ # External integrations
│ └── repositories/
├── handler.go # HTTP handlers
├── routes.go # Route registration
└── provider.go # Dependency injection
```
## 🚀 API Endpoints
The server exposes these API groups:
- `/api/auth/*` - Authentication & member management
- `/api/organizations/*` - Organization CRUD
- `/api/accounts/*` - Account management
- `/api/rbac/*` - Role & permission discovery
- `/api/subscriptions/*` - Billing status
- `/api/example_documents/*` - PDF upload/management
- `/api/example_cognitive/*` - AI chat sessions
- `/swagger/*` - API documentation
- `/health` - Health check
================================================
FILE: go-b2b-starter/cmd/api/main.go
================================================
// Package main provides the entry point for the B2B SaaS Starter
//
// @title B2B SaaS Starter API
// @version 1.0
// @description This is the API server for B2B SaaS Starter.
// @termsOfService http://swagger.io/terms/
//
// @contact.name API Support
// @contact.url http://www.swagger.io/support
// @contact.email support@swagger.io
//
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
//
// @host localhost:8080
// @BasePath /api
//
// @securityDefinitions.basic BasicAuth
//
// @externalDocs.description OpenAPI
// @externalDocs.url https://swagger.io/resources/open-api/
package main
import "github.com/moasq/go-b2b-starter/internal/bootstrap"
func main() {
bootstrap.Execute()
}
================================================
FILE: go-b2b-starter/deps/Dockerfile
================================================
FROM golang:1.25.5-alpine
WORKDIR /workspace
# Install system dependencies
RUN apk add --no-cache git make bash curl
# Install Go tools
RUN go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest && \
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest && \
go install github.com/swaggo/swag/cmd/swag@latest && \
go install github.com/air-verse/air@latest
CMD ["bash"]
================================================
FILE: go-b2b-starter/deps/docker-compose.yml
================================================
services:
postgres:
image: pgvector/pgvector:pg17
environment:
POSTGRES_DB: mydatabase
POSTGRES_USER: user
POSTGRES_PASSWORD: password
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d mydatabase"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:alpine
platform: linux/arm64
ports:
- "6379:6379"
volumes:
- redis_data:/data
cli:
build:
context: .
dockerfile: Dockerfile
image: go-b2b-starter-cli
volumes:
- ${PWD}:/workspace
working_dir: /workspace
environment:
- POSTGRES_HOST=postgres
- POSTGRES_PORT=5432
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
- POSTGRES_DB=mydatabase
- REDIS_HOST=redis
- REDIS_PORT=6379
ports:
- "8080:8080"
depends_on:
postgres:
condition: service_healthy
volumes:
postgres_data:
redis_data:
================================================
FILE: go-b2b-starter/docs/README.md
================================================
# Go B2B SaaS Starter Kit
A production-ready Go backend for B2B SaaS applications with multi-tenant architecture, authentication, billing, and file management.
## Quick Start
```bash
make run-deps # Start PostgreSQL & Redis
make migrateup # Run migrations
make dev # Start dev server with hot reload
```
## Documentation
### Core Systems
- **[Architecture](./architecture.md)** - Clean Architecture, dependency injection, module patterns
- **[Database](./database.md)** - SQLC workflow, migrations, store adapters
- **[Authentication](./authentication.md)** - Stytch integration, RBAC, middleware
- **[Billing](./billing.md)** - Polar.sh integration, subscriptions, paywall
### Infrastructure
- **[File Manager](./file-manager.md)** - R2 storage and file operations
- **[Event Bus](./event-bus.md)** - Event-driven architecture patterns
- **[API Development](./api-development.md)** - Guide to building new endpoints
## Project Structure
The codebase follows Clean Architecture with three main layers:
**API Layer** (`internal/`) - HTTP handlers and routes
**Application Layer** (`internal/`) - Business logic organized by modules
**Shared Layer** (`internal/`) - Reusable infrastructure packages
Each application module contains:
- `domain/` - Entities, interfaces, business rules
- `app/` - Services (use cases)
- `infra/` - Repository implementations
- `module.go` - Dependency injection setup
## Common Commands
```bash
# Development
make dev # Run dev server with hot reload (Air)
make server # Run server without hot reload
make build # Build production binary
# Dependencies
make run-deps # Start PostgreSQL & Redis in Docker
make stop-deps # Stop and remove Docker containers
# Database
make migrateup # Apply all migrations
make migratedown # Rollback migrations
make sqlc # Generate code from SQL
make create-migration # Create new migration file
# Code Generation
make swagger # Generate Swagger docs
# Testing
make test # Run tests with coverage
# Utilities
make clear-rbac-cache # Clear RBAC and JWKS caches from Redis
```
## Tech Stack
- **Language**: Go 1.25+
- **HTTP**: Gin framework
- **Database**: PostgreSQL with SQLC
- **Auth**: Stytch B2B
- **Payments**: Polar.sh
- **Storage**: Cloudflare R2
- **DI**: uber-go/dig
## Environment Setup
Copy `example.env` to `app.env` and configure:
```env
# Database
DATABASE_HOST=localhost
DATABASE_NAME=b2b_starter
# Authentication
STYTCH_PROJECT_ID=your-project-id
STYTCH_SECRET=your-secret
# Billing
POLAR_ACCESS_TOKEN=your-token
POLAR_WEBHOOK_SECRET=your-secret
# File Storage
R2_ACCOUNT_ID=your-account
R2_ACCESS_KEY_ID=your-key
R2_SECRET_ACCESS_KEY=your-secret
R2_BUCKET_NAME=files
```
See `example.env` for all configuration options.
## Getting Started
1. **Understand the architecture**: Read [Architecture](./architecture.md)
2. **Set up the database**: Follow [Database](./database.md)
3. **Configure authentication**: See [Authentication](./authentication.md)
4. **Build your first API**: Follow [API Development](./api-development.md)
================================================
FILE: go-b2b-starter/docs/adding-a-module.md
================================================
# Adding a New Module
This guide shows how to create a new feature module following Clean Architecture and the idiomatic Go project layout.
## Modules vs Platform Decision
Before creating a new module, determine whether it should be a **feature module** or a **platform component**.
### Create a Module (`internal/modules/`) when:
- Implementing a business domain feature
- Has domain entities with business rules
- Exposes API endpoints
- Contains use cases and workflows
- **Examples**: billing, documents, organizations, invoices, products
### Create a Platform Component (`internal/platform/`) when:
- Infrastructure or cross-cutting concern
- Used by multiple modules
- No business logic (pure infrastructure)
- Provides technical capability
- **Examples**: logger, eventbus, redis, http server
### Decision Tree
```
Is it a business domain feature?
├─ Yes → Create in internal/modules/{name}/
└─ No → Is it used by multiple modules?
├─ Yes → Create in internal/platform/{name}/
└─ No → Should it be part of an existing module?
```
## Module Location
All feature modules live in `internal/modules/` which enforces Go's import boundary:
```
internal/
├── modules/ # Feature modules (business domains)
│ ├── auth/ # Authentication & RBAC
│ ├── billing/ # Subscription & billing
│ ├── organizations/ # Multi-tenant organizations
│ ├── documents/ # Document management
│ ├── cognitive/ # AI/RAG features
│ ├── files/ # File storage
│ ├── paywall/ # Subscription middleware
│ └── products/ # ← Your new module here
│
├── platform/ # Cross-cutting infrastructure
│ ├── server/ # HTTP server
│ ├── eventbus/ # Event pub/sub
│ ├── logger/ # Structured logging
│ ├── redis/ # Redis client
│ └── ...
│
├── db/ # Database layer
└── bootstrap/ # App initialization
```
## Module Structure
Each module follows **Clean Architecture** with these layers:
```
internal/modules/products/
├── cmd/ # Module initialization (DI wiring)
│ └── init.go
│
├── app/ # Application Layer (Use Cases)
│ └── services/
│ └── product_service.go
│
├── domain/ # Domain Layer (Core Business Logic)
│ ├── entity.go # Data structures
│ └── repository.go # Interface definitions
│
├── infra/ # Infrastructure Layer (External)
│ └── repositories/
│ └── product_repository.go
│
├── handler.go # HTTP handlers (Delivery Layer)
├── routes.go # Route registration
└── module.go # Dependency injection setup
```
## Step-by-Step Guide
### 1. Define the Entity (`domain/entity.go`)
Start with your core business objects:
```go
package domain
import "time"
type Product struct {
ID int32 `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Price float64 `json:"price"`
OrganizationID int32 `json:"organization_id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// Validate validates the product data
func (p *Product) Validate() error {
if p.Name == "" {
return ErrInvalidProductName
}
if p.Price < 0 {
return ErrInvalidPrice
}
return nil
}
```
### 2. Define the Repository Interface (`domain/repository.go`)
Define what operations your module needs:
```go
package domain
import "context"
type ProductRepository interface {
Create(ctx context.Context, p *Product) (*Product, error)
GetByID(ctx context.Context, orgID, id int32) (*Product, error)
ListByOrganization(ctx context.Context, orgID int32, limit, offset int32) ([]*Product, error)
Update(ctx context.Context, p *Product) error
Delete(ctx context.Context, orgID, id int32) error
}
```
**Key Points:**
- Interface uses **domain types**, not database types
- Defined in the domain layer (where it's used)
- Independent of implementation details
### 3. Implement the Repository (`infra/repositories/product_repository.go`)
Implement the interface using SQLC:
```go
package repositories
import (
"context"
"fmt"
"github.com/moasq/go-b2b-starter/internal/modules/products/domain"
sqlc "github.com/moasq/go-b2b-starter/internal/db/postgres/sqlc/gen"
)
type productRepository struct {
store sqlc.Store
}
func NewProductRepository(store sqlc.Store) domain.ProductRepository {
return &productRepository{store: store}
}
func (r *productRepository) Create(ctx context.Context, p *domain.Product) (*domain.Product, error) {
dbProduct, err := r.store.CreateProduct(ctx, sqlc.CreateProductParams{
Name: p.Name,
Description: p.Description,
Price: p.Price,
OrganizationID: p.OrganizationID,
})
if err != nil {
return nil, fmt.Errorf("failed to create product: %w", err)
}
// Map SQLC type to domain type
return &domain.Product{
ID: dbProduct.ID,
Name: dbProduct.Name,
Description: dbProduct.Description,
Price: dbProduct.Price,
OrganizationID: dbProduct.OrganizationID,
CreatedAt: dbProduct.CreatedAt,
UpdatedAt: dbProduct.UpdatedAt,
}, nil
}
func (r *productRepository) GetByID(ctx context.Context, orgID, id int32) (*domain.Product, error) {
dbProduct, err := r.store.GetProductByID(ctx, sqlc.GetProductByIDParams{
OrganizationID: orgID,
ID: id,
})
if err != nil {
return nil, fmt.Errorf("failed to get product: %w", err)
}
return &domain.Product{
ID: dbProduct.ID,
Name: dbProduct.Name,
Description: dbProduct.Description,
Price: dbProduct.Price,
OrganizationID: dbProduct.OrganizationID,
CreatedAt: dbProduct.CreatedAt,
UpdatedAt: dbProduct.UpdatedAt,
}, nil
}
// ... implement other methods
```
### 4. Create the Service (`app/services/product_service.go`)
Business logic lives here:
```go
package services
import (
"context"
"fmt"
"github.com/moasq/go-b2b-starter/internal/modules/products/domain"
)
type ProductService interface {
Create(ctx context.Context, orgID int32, req *CreateProductRequest) (*domain.Product, error)
GetByID(ctx context.Context, orgID, id int32) (*domain.Product, error)
ListByOrganization(ctx context.Context, orgID int32, limit, offset int32) ([]*domain.Product, error)
}
type productService struct {
repo domain.ProductRepository
}
func NewProductService(repo domain.ProductRepository) ProductService {
return &productService{repo: repo}
}
type CreateProductRequest struct {
Name string `json:"name" binding:"required"`
Description string `json:"description"`
Price float64 `json:"price" binding:"required,min=0"`
}
func (s *productService) Create(ctx context.Context, orgID int32, req *CreateProductRequest) (*domain.Product, error) {
product := &domain.Product{
Name: req.Name,
Description: req.Description,
Price: req.Price,
OrganizationID: orgID,
}
// Validate
if err := product.Validate(); err != nil {
return nil, err
}
// Create
created, err := s.repo.Create(ctx, product)
if err != nil {
return nil, fmt.Errorf("failed to create product: %w", err)
}
return created, nil
}
```
### 5. Create the Handler (`handler.go`)
HTTP request handling:
```go
package products
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"github.com/moasq/go-b2b-starter/internal/modules/auth"
"github.com/moasq/go-b2b-starter/internal/modules/products/app/services"
"github.com/moasq/go-b2b-starter/pkg/httperr"
)
type Handler struct {
service services.ProductService
}
func NewHandler(service services.ProductService) *Handler {
return &Handler{service: service}
}
// @Summary Create product
// @Description Creates a new product in the organization
// @Tags products
// @Accept json
// @Produce json
// @Param request body services.CreateProductRequest true "Product data"
// @Success 201 {object} domain.Product "Created product"
// @Failure 400 {object} httperr.HTTPError "Invalid request"
// @Failure 500 {object} httperr.HTTPError "Internal error"
// @Router /api/products [post]
func (h *Handler) Create(c *gin.Context) {
reqCtx := auth.GetRequestContext(c)
if reqCtx == nil {
c.JSON(http.StatusUnauthorized, httperr.NewHTTPError(
http.StatusUnauthorized,
"unauthorized",
"Authentication required",
))
return
}
var req services.CreateProductRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, httperr.NewHTTPError(
http.StatusBadRequest,
"invalid_request",
err.Error(),
))
return
}
product, err := h.service.Create(c.Request.Context(), reqCtx.OrganizationID, &req)
if err != nil {
c.JSON(http.StatusInternalServerError, httperr.NewHTTPError(
http.StatusInternalServerError,
"creation_failed",
err.Error(),
))
return
}
c.JSON(http.StatusCreated, product)
}
// @Summary Get product
// @Description Gets a product by ID
// @Tags products
// @Produce json
// @Param id path int true "Product ID"
// @Success 200 {object} domain.Product "Product details"
// @Failure 400 {object} httperr.HTTPError "Invalid ID"
// @Failure 404 {object} httperr.HTTPError "Product not found"
// @Router /api/products/{id} [get]
func (h *Handler) GetByID(c *gin.Context) {
reqCtx := auth.GetRequestContext(c)
if reqCtx == nil {
c.JSON(http.StatusUnauthorized, httperr.NewHTTPError(
http.StatusUnauthorized,
"unauthorized",
"Authentication required",
))
return
}
var productID int32
if _, err := fmt.Sscanf(c.Param("id"), "%d", &productID); err != nil {
c.JSON(http.StatusBadRequest, httperr.NewHTTPError(
http.StatusBadRequest,
"invalid_id",
"Product ID must be a number",
))
return
}
product, err := h.service.GetByID(c.Request.Context(), reqCtx.OrganizationID, productID)
if err != nil {
c.JSON(http.StatusNotFound, httperr.NewHTTPError(
http.StatusNotFound,
"not_found",
err.Error(),
))
return
}
c.JSON(http.StatusOK, product)
}
```
### 6. Define Routes (`routes.go`)
Register your endpoints:
```go
package products
import (
"github.com/gin-gonic/gin"
"github.com/moasq/go-b2b-starter/internal/modules/auth"
"github.com/moasq/go-b2b-starter/internal/platform/server/domain"
)
type Routes struct {
handler *Handler
}
func NewRoutes(handler *Handler) *Routes {
return &Routes{handler: handler}
}
func (r *Routes) Routes(router *gin.RouterGroup, resolver domain.MiddlewareResolver) {
products := router.Group("/products")
products.Use(
resolver.Get("auth"), // RequireAuth
resolver.Get("org_context"), // RequireOrganization
)
{
products.POST("", r.handler.Create)
products.GET("/:id", r.handler.GetByID)
products.GET("", r.handler.List)
products.PUT("/:id", r.handler.Update)
products.DELETE("/:id", r.handler.Delete)
}
}
```
### 7. Wire Dependencies (`cmd/init.go`)
Set up dependency injection:
```go
package cmd
import (
"fmt"
"go.uber.org/dig"
"github.com/moasq/go-b2b-starter/internal/modules/products"
"github.com/moasq/go-b2b-starter/internal/modules/products/app/services"
"github.com/moasq/go-b2b-starter/internal/modules/products/domain"
"github.com/moasq/go-b2b-starter/internal/modules/products/infra/repositories"
sqlc "github.com/moasq/go-b2b-starter/internal/db/postgres/sqlc/gen"
)
func RegisterDependencies(container *dig.Container) error {
// Repository - registered in internal/db/inject.go
// (See step 8 below)
// Service
if err := container.Provide(services.NewProductService); err != nil {
return fmt.Errorf("failed to provide product service: %w", err)
}
// Handler
if err := container.Provide(products.NewHandler); err != nil {
return fmt.Errorf("failed to provide product handler: %w", err)
}
// Routes
if err := container.Provide(products.NewRoutes); err != nil {
return fmt.Errorf("failed to provide product routes: %w", err)
}
return nil
}
```
### 8. Register Repository in Database Layer
**IMPORTANT**: Repositories are registered in `internal/db/inject.go`, not in the module's `cmd/init.go`.
Add to `internal/db/inject.go`:
```go
import (
productDomain "github.com/moasq/go-b2b-starter/internal/modules/products/domain"
productRepos "github.com/moasq/go-b2b-starter/internal/modules/products/infra/repositories"
)
// In registerDomainStores function:
if err := container.Provide(func(sqlcStore sqlc.Store) productDomain.ProductRepository {
return productRepos.NewProductRepository(sqlcStore)
}); err != nil {
return fmt.Errorf("failed to provide product repository: %w", err)
}
```
### 9. Register in Bootstrap
Add your module to `internal/bootstrap/init_mods.go`:
```go
import productsCmd "github.com/moasq/go-b2b-starter/internal/modules/products/cmd"
func InitMods(container *dig.Container) error {
// ... existing modules ...
// Products module
if err := productsCmd.RegisterDependencies(container); err != nil {
return fmt.Errorf("failed to register products dependencies: %w", err)
}
return nil
}
```
### 10. Register Routes in API
Routes are auto-registered via DI. Ensure your module's Routes struct is provided in step 7.
The `internal/api/provider.go` will automatically discover and register all route groups.
## Database Setup
### 1. Create Migration
Create a migration for your new table:
```bash
cd internal/db/postgres/sqlc/migrations
# Create files manually with next sequence number
```
**Up migration** (`000015_create_products.up.sql`):
```sql
CREATE TABLE app.products (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
price DECIMAL(10, 2) NOT NULL,
organization_id INTEGER NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT fk_organization
FOREIGN KEY (organization_id)
REFERENCES app.organizations(id)
ON DELETE CASCADE
);
CREATE INDEX idx_products_organization_id ON app.products(organization_id);
CREATE INDEX idx_products_name ON app.products(name);
```
**Down migration** (`000015_create_products.down.sql`):
```sql
DROP TABLE IF EXISTS app.products;
```
### 2. Create SQLC Queries
Create `internal/db/postgres/sqlc/query/products.sql`:
```sql
-- name: CreateProduct :one
INSERT INTO products (name, description, price, organization_id)
VALUES ($1, $2, $3, $4)
RETURNING *;
-- name: GetProductByID :one
SELECT * FROM products
WHERE organization_id = $1 AND id = $2;
-- name: ListProductsByOrganization :many
SELECT * FROM products
WHERE organization_id = $1
ORDER BY created_at DESC
LIMIT $2 OFFSET $3;
-- name: UpdateProduct :one
UPDATE products
SET name = $2, description = $3, price = $4, updated_at = NOW()
WHERE organization_id = $1 AND id = $5
RETURNING *;
-- name: DeleteProduct :exec
DELETE FROM products
WHERE organization_id = $1 AND id = $2;
```
### 3. Run Migrations and Generate Code
```bash
make migrateup # Apply migrations
make sqlc # Generate type-safe Go code
```
## Testing
### Unit Test Example
```go
package services_test
import (
"context"
"testing"
"github.com/moasq/go-b2b-starter/internal/modules/products/domain"
"github.com/moasq/go-b2b-starter/internal/modules/products/app/services"
)
type mockProductRepository struct {
createFunc func(ctx context.Context, p *domain.Product) (*domain.Product, error)
}
func (m *mockProductRepository) Create(ctx context.Context, p *domain.Product) (*domain.Product, error) {
return m.createFunc(ctx, p)
}
func TestProductService_Create(t *testing.T) {
mockRepo := &mockProductRepository{
createFunc: func(ctx context.Context, p *domain.Product) (*domain.Product, error) {
p.ID = 1
return p, nil
},
}
service := services.NewProductService(mockRepo)
req := &services.CreateProductRequest{
Name: "Test Product",
Price: 99.99,
}
product, err := service.Create(context.Background(), 1, req)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if product.ID != 1 {
t.Errorf("expected product ID 1, got %d", product.ID)
}
}
```
## Best Practices
1. **Domain Layer is Pure**: No external dependencies in `domain/`
2. **Interfaces in Domain**: Repository interfaces defined where they're used
3. **Services Return Domain Types**: Not database types
4. **Handlers Are Thin**: Validation, auth, delegate to service
5. **Context First**: Always pass `context.Context` as first parameter
6. **Use `httperr.HTTPError`**: For consistent API error responses
7. **Register Repositories Centrally**: In `internal/db/inject.go`, not module init
8. **Map Database Types**: Convert SQLC types to domain types in repositories
## Common Pitfalls
### Import Cycles
```go
// ❌ Bad - Creates import cycle
// internal/modules/products/domain/entity.go
import "github.com/moasq/go-b2b-starter/internal/modules/products/app/services"
// ✅ Good - Domain has no dependencies
// internal/modules/products/domain/entity.go
package domain
```
### Wrong Repository Registration
```go
// ❌ Bad - Registering repository in module init
// internal/modules/products/cmd/init.go
container.Provide(repositories.NewProductRepository)
// ✅ Good - Register in database layer
// internal/db/inject.go
container.Provide(func(sqlcStore sqlc.Store) productDomain.ProductRepository {
return productRepos.NewProductRepository(sqlcStore)
})
```
### Exposing SQLC Types
```go
// ❌ Bad - Service returns SQLC types
func (s *service) GetProduct(ctx context.Context, id int32) (*sqlc.Product, error)
// ✅ Good - Service returns domain types
func (s *service) GetProduct(ctx context.Context, id int32) (*domain.Product, error)
```
## File Checklist
After creating a new module, you should have:
- [ ] `domain/entity.go` - Domain entities
- [ ] `domain/repository.go` - Repository interfaces
- [ ] `infra/repositories/{entity}_repository.go` - Repository implementation
- [ ] `app/services/{entity}_service.go` - Service interface and implementation
- [ ] `handler.go` - HTTP handlers with Swagger docs
- [ ] `routes.go` - Route registration
- [ ] `cmd/init.go` - DI setup for service, handler, routes
- [ ] SQL queries in `internal/db/postgres/sqlc/query/{entity}.sql`
- [ ] Repository registration in `internal/db/inject.go`
- [ ] Module registration in `internal/bootstrap/init_mods.go`
- [ ] Database migrations in `internal/db/postgres/sqlc/migrations/`
## Next Steps
- **Architecture Details**: See [Architecture Guide](./architecture.md)
- **Database Operations**: See [Database Guide](./database.md)
- **API Development**: See [API Development Guide](./api-development.md)
================================================
FILE: go-b2b-starter/docs/api-development.md
================================================
# API Development Guide
Step-by-step guide to building new API endpoints following Clean Architecture patterns.
## Overview
Building an API endpoint involves these layers:
1. **Domain** - Entity and repository interface
2. **Infrastructure** - Repository implementation
3. **Application** - Service with business logic
4. **API** - HTTP handler and routes
## Step 1: Database Layer
### Create Migration
Add migration files in `internal/db/postgres/sqlc/migrations/`:
```sql
-- 000015_create_resources.up.sql
CREATE TABLE app.resources (
id SERIAL PRIMARY KEY,
organization_id INT NOT NULL,
name VARCHAR(255) NOT NULL,
status VARCHAR(50) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_resources_org ON app.resources(organization_id);
```
### Write SQL Queries
In `internal/db/postgres/sqlc/query/resources.sql`:
```sql
-- name: GetResourceByID :one
SELECT * FROM app.resources WHERE id = $1;
-- name: CreateResource :one
INSERT INTO app.resources (organization_id, name, status)
VALUES ($1, $2, $3)
RETURNING *;
-- name: ListResources :many
SELECT * FROM app.resources
WHERE organization_id = $1
ORDER BY created_at DESC;
```
### Generate Code
```bash
make sqlc
```
### Create Store Interface
In `internal/db/adapters/resource_store.go`:
```go
type ResourceStore interface {
GetResourceByID(ctx context.Context, id int32) (sqlc.Resource, error)
CreateResource(ctx context.Context, arg sqlc.CreateResourceParams) (sqlc.Resource, error)
ListResources(ctx context.Context, orgID int32) ([]sqlc.Resource, error)
}
```
### Implement Adapter
In `internal/db/postgres/adapter_impl/resource_store.go`:
```go
type resourceStore struct {
store sqlc.Store
}
func NewResourceStore(store sqlc.Store) adapters.ResourceStore {
return &resourceStore{store: store}
}
func (s *resourceStore) GetResourceByID(ctx context.Context, id int32) (sqlc.Resource, error) {
return s.store.GetResourceByID(ctx, id)
}
```
### Register in DI
In `internal/db/inject.go`:
```go
container.Provide(func(sqlcStore sqlc.Store) adapters.ResourceStore {
return adapter_impl.NewResourceStore(sqlcStore)
})
```
## Step 2: Domain Layer
### Create Entity
In `internal/resources/domain/entity.go`:
```go
type Resource struct {
ID int32
OrganizationID int32
Name string
Status string
CreatedAt time.Time
UpdatedAt time.Time
}
func (r *Resource) Validate() error {
if r.Name == "" {
return ErrResourceNameRequired
}
return nil
}
```
### Define Repository Interface
In `internal/resources/domain/repository.go`:
```go
type ResourceRepository interface {
Create(ctx context.Context, resource *Resource) (*Resource, error)
GetByID(ctx context.Context, id int32) (*Resource, error)
List(ctx context.Context, orgID int32) ([]*Resource, error)
}
```
## Step 3: Infrastructure Layer
### Implement Repository
In `internal/resources/infra/repositories/resource_repository.go`:
```go
type resourceRepository struct {
store adapters.ResourceStore
}
func NewResourceRepository(store adapters.ResourceStore) domain.ResourceRepository {
return &resourceRepository{store: store}
}
func (r *resourceRepository) Create(ctx context.Context, resource *domain.Resource) (*domain.Resource, error) {
params := sqlc.CreateResourceParams{
OrganizationID: resource.OrganizationID,
Name: resource.Name,
Status: resource.Status,
}
dbResource, err := r.store.CreateResource(ctx, params)
if err != nil {
return nil, fmt.Errorf("failed to create resource: %w", err)
}
return toDomainResource(dbResource), nil
}
```
## Step 4: Application Layer
### Define Service Interface
In `internal/resources/app/services/resource_service_interface.go`:
```go
type ResourceService interface {
CreateResource(ctx context.Context, orgID int32, req *CreateResourceRequest) (*domain.Resource, error)
GetResource(ctx context.Context, id int32) (*domain.Resource, error)
ListResources(ctx context.Context, orgID int32) ([]*domain.Resource, error)
}
```
### Implement Service
In `internal/resources/app/services/resource_service.go`:
```go
type resourceService struct {
repo domain.ResourceRepository
}
func NewResourceService(repo domain.ResourceRepository) ResourceService {
return &resourceService{repo: repo}
}
func (s *resourceService) CreateResource(
ctx context.Context,
orgID int32,
req *CreateResourceRequest,
) (*domain.Resource, error) {
// Validate request
if err := req.Validate(); err != nil {
return nil, err
}
// Create entity
resource := &domain.Resource{
OrganizationID: orgID,
Name: req.Name,
Status: "active",
}
// Persist
return s.repo.Create(ctx, resource)
}
```
## Step 5: API Layer
### Create Handler
In `internal/resources/handler.go`:
```go
type Handler struct {
service services.ResourceService
}
func NewHandler(service services.ResourceService) *Handler {
return &Handler{service: service}
}
func (h *Handler) CreateResource(c *gin.Context) {
// Get auth context
reqCtx := auth.GetRequestContext(c)
if reqCtx == nil {
c.JSON(401, gin.H{"error": "unauthorized"})
return
}
// Parse request
var req services.CreateResourceRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": "invalid request"})
return
}
// Call service
resource, err := h.service.CreateResource(c.Request.Context(), reqCtx.OrganizationID, &req)
if err != nil {
c.JSON(500, gin.H{"error": "failed to create resource"})
return
}
c.JSON(201, resource)
}
```
### Register Routes
In `internal/resources/routes.go`:
```go
type Routes struct {
handler *Handler
authMiddleware *auth.Middleware
}
func NewRoutes(handler *Handler, authMiddleware *auth.Middleware) *Routes {
return &Routes{handler: handler, authMiddleware: authMiddleware}
}
func (r *Routes) Register(router *gin.Engine) {
apiGroup := router.Group("/api/resources")
apiGroup.Use(r.authMiddleware.RequireAuth())
apiGroup.Use(r.authMiddleware.RequireOrganization())
{
apiGroup.POST("",
auth.RequirePermissionFunc("resource", "create"),
r.handler.CreateResource)
apiGroup.GET("/:id", r.handler.GetResource)
apiGroup.GET("", r.handler.ListResources)
}
}
```
## Step 6: Module Registration
### Create Module
In `internal/resources/module.go`:
```go
type Module struct {
container *dig.Container
}
func NewModule(container *dig.Container) *Module {
return &Module{container: container}
}
func (m *Module) RegisterDependencies() error {
// Repository
if err := m.container.Provide(func(store adapters.ResourceStore) domain.ResourceRepository {
return repositories.NewResourceRepository(store)
}); err != nil {
return err
}
// Service
if err := m.container.Provide(func(repo domain.ResourceRepository) services.ResourceService {
return services.NewResourceService(repo)
}); err != nil {
return err
}
return nil
}
```
### Initialize Module
In `internal/resources/cmd/init.go`:
```go
func Init(container *dig.Container) error {
module := NewModule(container)
return module.RegisterDependencies()
}
```
### Register API
In `internal/resources/provider.go`:
```go
func RegisterDependencies(container *dig.Container) error {
// Register handler
if err := container.Provide(func(service services.ResourceService) *Handler {
return NewHandler(service)
}); err != nil {
return err
}
// Register routes
if err := container.Provide(func(
handler *Handler,
authMiddleware *auth.Middleware,
) *Routes {
return NewRoutes(handler, authMiddleware)
}); err != nil {
return err
}
return nil
}
```
## Quick Reference
### File Structure
```
internal/resources/
├── domain/
│ ├── entity.go
│ ├── repository.go
│ └── errors.go
├── app/services/
│ ├── resource_service_interface.go
│ └── resource_service.go
├── infra/repositories/
│ └── resource_repository.go
├── cmd/init.go
└── module.go
internal/resources/
├── handler.go
├── routes.go
└── provider.go
```
### Common Response Codes
- `200` - Success
- `201` - Created
- `400` - Bad Request
- `401` - Unauthorized
- `403` - Forbidden
- `404` - Not Found
- `500` - Internal Server Error
## Next Steps
- **Add tests**: Unit tests for service, integration tests for repository
- **Add Swagger docs**: Document API with Swagger annotations
- **Add validation**: Request/response validation
- **Add events**: Publish domain events for cross-module communication
================================================
FILE: go-b2b-starter/docs/architecture.md
================================================
# Backend Architecture
The backend is a **Modular Monolith** using **idiomatic Go project layout** with Clear separation between business features and infrastructure.
## High-Level Structure
```
go-b2b-starter/
├── cmd/ # Application entry points
│ └── api/
│ └── main.go # Main entry point
│
├── internal/ # Private application code (import boundary)
│ ├── modules/ # Feature modules (business domains)
│ ├── platform/ # Cross-cutting infrastructure
│ ├── db/ # Database layer (SQLC, DI registration)
│ ├── bootstrap/ # Application initialization
│ └── api/ # API route registration
│
├── pkg/ # Public reusable packages
│ ├── httperr/ # HTTP error types
│ ├── pagination/ # Pagination helpers
│ └── response/ # API response utilities
│
└── go.mod # Single consolidated module
```
## Architectural Layers
### Feature Modules (`internal/modules/`)
Business domain modules following **Clean Architecture**. Each module represents a distinct business capability:
```
internal/modules/
├── auth/ # Authentication & RBAC
├── billing/ # Polar.sh subscriptions & quota management
├── organizations/ # Multi-tenant organization management
├── documents/ # PDF document processing
├── cognitive/ # RAG (Retrieval-Augmented Generation) & embeddings
├── files/ # File storage (R2 + metadata)
└── paywall/ # Subscription middleware
```
**Characteristics of Feature Modules:**
- Business domain logic
- Domain entities with business rules
- API endpoints
- Use cases and workflows
- Follow Clean Architecture layers (domain → app → infra)
### Platform Services (`internal/platform/`)
Cross-cutting infrastructure components used by multiple modules:
```
internal/platform/
├── server/ # HTTP server & middleware
├── eventbus/ # Event pub/sub system
├── logger/ # Structured logging
├── redis/ # Redis cache client
├── stytch/ # Stytch auth provider client
├── polar/ # Polar.sh billing provider client
├── llm/ # LLM integration (OpenAI)
└── ocr/ # OCR service (Mistral)
```
**Characteristics of Platform Components:**
- Infrastructure concerns
- Used by multiple modules
- No business logic
- Provide technical capabilities
### Database Layer (`internal/db/`)
Centralized database layer using SQLC:
```
internal/db/
├── postgres/
│ ├── sqlc/
│ │ ├── migrations/ # SQL migration files
│ │ ├── query/ # SQL queries with SQLC annotations
│ │ └── gen/ # Generated Go code
│ └── postgres.go # DB connection and pooling
├── inject.go # DI registration for all repositories
└── core/
└── errors.go # Database error types
```
**Key Responsibilities:**
- SQLC code generation
- Repository DI registration
- Database connection management
- Transaction support
## Module Structure (Clean Architecture)
Each feature module in `internal/modules/` follows **Clean Architecture**:
```mermaid
graph TD
A[Handler] --> B[Service]
B --> C[Repository Interface]
C --> D[Repository Implementation]
D --> E[SQLC Store]
E --> F[PostgreSQL]
```
### Layer Details
```
internal/modules/billing/
├── cmd/ # Module initialization (DI wiring)
│ └── init.go
│
├── app/ # Application Layer (Use Cases)
│ └── services/
│ └── billing_service.go
│
├── domain/ # Domain Layer (Core Business Logic)
│ ├── entity.go # Data structures
│ ├── repository.go # Interface definitions
│ ├── errors.go # Domain errors
│ └── events/ # Domain events
│
├── infra/ # Infrastructure Layer (External)
│ ├── repositories/ # Repository implementations
│ │ └── subscription_repository.go
│ └── polar/ # Polar.sh adapter
│ └── polar_adapter.go
│
├── handler.go # HTTP handlers (Delivery Layer)
├── routes.go # Route registration
└── module.go # Dependency injection setup
```
## Key Principles
### 1. `internal/` Boundary
Code in `internal/` cannot be imported by external packages. This enforces encapsulation and prevents unintended dependencies.
### 2. Dependency Rule (Clean Architecture)
```mermaid
graph LR
A[Domain] --> B[Application]
B --> C[Infrastructure]
C --> D[Delivery/Handler]
```
**Direction of dependencies:**
- Domain → Nothing (pure business logic)
- Application → Domain (uses domain interfaces)
- Infrastructure → Domain (implements domain interfaces)
- Handlers → Application (calls services)
**Key Point**: Inner layers never depend on outer layers. Infrastructure implements interfaces defined in domain.
### 3. Feature-Based Organization
Modules are organized by **business feature** (billing, auth, organizations), not by technical layer (controllers, services, models).
This promotes:
- High cohesion within features
- Low coupling between features
- Easy to understand and navigate
- Clear ownership and boundaries
### 4. Single `go.mod`
One module for the entire project eliminates workspace complexity and simplifies dependency management.
## Request Flow
```mermaid
sequenceDiagram
participant Client
participant Middleware
participant Handler
participant Service
participant Repository
participant Database
Client->>Middleware: HTTP Request
Middleware->>Middleware: Auth & Validation
Middleware->>Handler: Authenticated Request
Handler->>Handler: Parse & Validate
Handler->>Service: Call Use Case
Service->>Service: Business Logic
Service->>Repository: Get/Save Data (Interface)
Repository->>Database: SQL Query (SQLC)
Database-->>Repository: Result
Repository-->>Service: Domain Entity
Service-->>Handler: DTO Response
Handler-->>Client: JSON Response
```
### Flow Breakdown
1. **Client Request**: HTTP request arrives at server
2. **Middleware**: Auth, logging, rate limiting, CORS
3. **Handler**: Parse request, extract context (org ID, user ID)
4. **Service**: Execute business logic, orchestrate operations
5. **Repository**: Data access using domain interfaces
6. **Database**: SQLC-generated type-safe queries
## Initialization Flow
```mermaid
graph TD
A[cmd/api/main.go] --> B[bootstrap.Execute]
B --> C[InitMods]
C --> D[Infrastructure Layer]
C --> E[Platform Services]
C --> F[Feature Modules]
C --> G[API Routes]
D --> D1[Logger]
D --> D2[Server]
D --> D3[Database]
E --> E1[Redis]
E --> E2[EventBus]
E --> E3[Stytch]
E --> E4[Polar]
F --> F1[Auth Module]
F --> F2[Billing Module]
F --> F3[Organizations Module]
F --> F4[Documents Module]
G --> G1[Register Routes]
G --> G2[Setup Middleware]
```
### Initialization Order (Critical)
```
cmd/api/main.go
└── bootstrap.Execute()
├── 1. Infrastructure (no dependencies)
│ ├── logger.Inject()
│ ├── server.Inject()
│ └── db.Inject() # Registers all domain repositories
│
├── 2. Platform Services
│ ├── redis.Inject()
│ ├── llm.Inject()
│ ├── ocr.Inject()
│ ├── polar.Inject()
│ └── eventbus.Inject()
│
├── 3. Feature Modules (order matters!)
│ ├── files.SetupDependencies()
│ ├── auth.SetupDependencies()
│ ├── organizations.RegisterDependencies()
│ ├── billing.Configure()
│ ├── cognitive.RegisterDependencies()
│ └── documents.RegisterDependencies()
│
├── 4. Event Subscriptions
│ └── cognitive.SetupEventSubscriptions()
│
└── 5. HTTP Server Setup
├── server.SetupMiddleware()
└── api.RegisterRoutes()
```
**Why Order Matters:**
- `db.Inject()` must run early (registers all repositories)
- `auth` must be before modules that need auth middleware
- `files` must be before `documents` (documents depend on files)
- Event subscriptions must be after all modules are loaded
## Dependency Injection
The project uses **uber-go/dig** for dependency injection:
```go
// 1. Define interface in domain
package domain
type ProductRepository interface {
Create(ctx context.Context, p *Product) (*Product, error)
}
// 2. Implement in infrastructure
package repositories
func NewProductRepository(store sqlc.Store) domain.ProductRepository {
return &productRepository{store: store}
}
// 3. Register in DI (internal/db/inject.go)
container.Provide(func(sqlcStore sqlc.Store) productDomain.ProductRepository {
return productRepos.NewProductRepository(sqlcStore)
})
// 4. Inject into service
package services
func NewProductService(repo domain.ProductRepository) ProductService {
return &productService{repo: repo}
}
```
**Benefits:**
- Automatic dependency resolution
- Easy testing (inject mocks)
- Clear dependency graph
- Compile-time safety
## Modules vs Platform Decision
```mermaid
graph TD
A{Is it a business domain feature?}
A -->|Yes| B[Create in internal/modules/]
A -->|No| C{Used by multiple modules?}
C -->|Yes| D[Create in internal/platform/]
C -->|No| E{Part of existing module?}
E -->|Yes| F[Add to that module]
E -->|No| D
```
### Examples
| Component | Location | Reason |
|-----------|----------|--------|
| Product Catalog | `modules/products/` | Business domain feature |
| Invoice Processing | `modules/invoices/` | Business domain feature |
| Subscription Management | `modules/billing/` | Business domain feature |
| Event Bus | `platform/eventbus/` | Used by all modules |
| Logging | `platform/logger/` | Cross-cutting infrastructure |
| Stytch Client | `platform/stytch/` | Auth provider client |
| Auth Module | `modules/auth/` | Business auth logic using Stytch |
## Communication Between Modules
Modules communicate through:
### 1. Event Bus (Loosely Coupled)
```go
// Module A publishes event
eventBus.Publish(ctx, events.NewDocumentUploadedEvent(docID, orgID))
// Module B subscribes
eventBus.Subscribe("document.uploaded", func(ctx context.Context, event Event) error {
docEvent := event.(*DocumentUploadedEvent)
return embeddingService.GenerateForDocument(ctx, docEvent.DocumentID)
})
```
**Use When:**
- Asynchronous operations
- One-to-many communication
- Loose coupling desired
### 2. Direct Service Injection (Tightly Coupled)
```go
// Service A uses Service B
func NewInvoiceService(
repo domain.InvoiceRepository,
billingService billing.BillingService, // Direct dependency
) InvoiceService {
return &invoiceService{
repo: repo,
billing: billingService,
}
}
```
**Use When:**
- Synchronous operations
- One-to-one communication
- Strong dependency relationship
### 3. Shared Platform Components
```go
// Multiple modules use platform logger
func NewDocumentService(
repo domain.DocumentRepository,
logger logger.Logger, // Platform component
) DocumentService {
return &documentService{repo: repo, logger: logger}
}
```
## Multi-Tenancy
Every module supports multi-tenancy through **Organization ID**:
```go
// Organization context in middleware
type RequestContext struct {
OrganizationID int32 // From JWT token
AccountID int32 // User account ID
Identity *Identity
}
// Used in handlers
reqCtx := auth.GetRequestContext(c)
products, err := service.ListByOrganization(ctx, reqCtx.OrganizationID)
// Enforced in repository
SELECT * FROM products WHERE organization_id = $1 AND id = $2
```
**Benefits:**
- Data isolation per organization
- Single database for all tenants
- Efficient resource usage
- Simplified deployment
## File Structure Summary
| Layer | Path | Purpose |
|-------|------|---------|
| Entry point | `cmd/api/main.go` | Application startup |
| Feature modules | `internal/modules/*/` | Business domains |
| Platform services | `internal/platform/*/` | Infrastructure |
| Database layer | `internal/db/` | SQLC, migrations, DI |
| Bootstrap | `internal/bootstrap/` | Initialization |
| API routes | `internal/api/` | Route registration |
| Shared utilities | `pkg/*/` | Public packages |
## Next Steps
- **Adding a Module**: See [Adding a Module Guide](./adding-a-module.md)
- **Database Operations**: See [Database Guide](./database.md)
- **API Development**: See [API Development Guide](./api-development.md)
- **Authentication**: See [Authentication Guide](./authentication.md)
- **Event Bus**: See [Event Bus Guide](./event-bus.md)
================================================
FILE: go-b2b-starter/docs/authentication.md
================================================
# Authentication Guide
The authentication system uses Stytch B2B for identity management with JWT verification, RBAC, and multi-tenant organization context.
## Architecture
**Provider**: Stytch B2B handles user authentication and sessions
**Middleware**: Verifies JWTs and resolves organization/account context
**RBAC**: Role-based access control with permissions
**Resolvers**: Bridge auth provider IDs to database IDs
## JWT Verification
The system uses a two-tier verification strategy:
**1. Fast Path** - Verify JWT locally using cached public keys
**2. API Fallback** - Call Stytch API if local verification fails
This approach balances security with performance.
### Configuration
```env
STYTCH_PROJECT_ID=project-test-xxx
STYTCH_SECRET=secret-test-xxx
STYTCH_ENV=test # or "live"
```
## Middleware
Three middleware functions protect routes:
### RequireAuth
Verifies JWT and extracts identity.
```go
router.Use(authMiddleware.RequireAuth())
```
**What it does:**
- Verifies JWT from `Authorization: Bearer {token}` header
- Extracts user identity (email, roles, permissions)
- Stores `auth.Identity` in request context
- Returns 401 if auth fails
### RequireOrganization
Resolves organization and account IDs from auth provider.
```go
router.Use(authMiddleware.RequireOrganization())
```
**What it does:**
- Gets organization ID from Stytch → resolves to database ID
- Gets user email → resolves to account ID
- Stores `auth.RequestContext` with IDs
- Returns 401 if resolution fails
**Note:** Always use after `RequireAuth()`.
### RequirePermission
Checks user has specific permission.
```go
router.POST("/resources",
auth.RequirePermissionFunc("resource", "create"),
handler.CreateResource)
```
**What it does:**
- Checks if user has permission (e.g., `"resource:create"`)
- Returns 403 if permission missing
**Note:** Use after `RequireOrganization()`.
## Using Context in Handlers
Access authentication info from request context:
```go
func (h *Handler) MyHandler(c *gin.Context) {
// Get full context
reqCtx := auth.GetRequestContext(c)
orgID := reqCtx.OrganizationID // int32
accountID := reqCtx.AccountID // int32
email := reqCtx.Identity.Email // string
// Or use convenience functions
orgID := auth.GetOrganizationID(c)
accountID := auth.GetAccountID(c)
}
```
## RBAC System
### Roles
Defined in `internal/auth/roles.go`:
- `RoleAdmin` - Full system access
- `RoleManager` - Organization management
- `RoleMember` - Standard user access
### Permissions
Format: `"{resource}:{action}"`
**Common permissions:**
- `resource:view` - Read access
- `resource:create` - Create new items
- `resource:update` - Modify existing items
- `resource:delete` - Delete items
- `org:manage` - Organization administration
Defined in `internal/auth/permissions.go`.
### Permission Checks
```go
// In middleware (route-level)
router.POST("/resources",
auth.RequirePermissionFunc("resource", "create"),
handler.CreateResource)
// In code (programmatic)
if !auth.HasPermission(identity, "resource:delete") {
return errors.New("permission denied")
}
```
## Resolver Pattern
Resolvers convert auth provider IDs to database IDs.
### Why Needed?
- Stytch uses string UUIDs for organizations
- Database uses int32 for primary keys
- Auth package can't depend on domain modules (circular dependency)
### How It Works
**1. Auth package defines interfaces:**
```go
type OrganizationResolver interface {
ResolveByProviderID(ctx context.Context, providerID string) (int32, error)
}
```
**2. Domain modules implement via adapters:**
```go
type orgResolverAdapter struct {
repo domain.OrganizationRepository
}
func (a *orgResolverAdapter) ResolveByProviderID(ctx context.Context, id string) (int32, error) {
org, err := a.repo.GetByStytchID(ctx, id)
if err != nil {
return 0, err
}
return org.ID, nil
}
```
**3. Wired in initialization:**
Resolvers registered in `internal/bootstrap/init_mods.go` after organization module loads.
## Route Protection Patterns
### Public Route (No Auth)
```go
router.GET("/health", handler.Health)
```
### Authenticated Route
```go
apiGroup := router.Group("/api")
apiGroup.Use(authMiddleware.RequireAuth())
apiGroup.Use(authMiddleware.RequireOrganization())
{
apiGroup.GET("/profile", handler.GetProfile)
}
```
### Permission-Protected Route
```go
apiGroup.POST("/resources",
auth.RequirePermissionFunc("resource", "create"),
handler.CreateResource)
apiGroup.DELETE("/resources/:id",
auth.RequirePermissionFunc("resource", "delete"),
handler.DeleteResource)
```
### Role-Protected Route
```go
adminGroup := router.Group("/admin")
adminGroup.Use(authMiddleware.RequireRole(auth.RoleAdmin))
{
adminGroup.GET("/users", handler.ListUsers)
}
```
## Adding New Permissions
**1. Define permission constant** in `internal/auth/permissions.go`:
```go
const PermResourceView = Permission("resource:view")
const PermResourceCreate = Permission("resource:create")
```
**2. Assign to roles** in `internal/auth/rbac.go`:
```go
{
RoleMember: {
PermResourceView,
// ... other permissions
},
RoleManager: {
PermResourceView,
PermResourceCreate,
// ... other permissions
},
}
```
**3. Protect routes**:
```go
router.POST("/resources",
auth.RequirePermissionFunc("resource", "create"),
handler.CreateResource)
```
## Common Patterns
### Check Organization Ownership
```go
func (h *Handler) GetResource(c *gin.Context) {
orgID := auth.GetOrganizationID(c)
resourceID := parseID(c.Param("id"))
resource, err := h.service.GetResource(c.Request.Context(), resourceID)
if err != nil {
c.JSON(500, gin.H{"error": "failed to get resource"})
return
}
// Verify resource belongs to user's organization
if resource.OrganizationID != orgID {
c.JSON(403, gin.H{"error": "access denied"})
return
}
c.JSON(200, resource)
}
```
### Optional Authentication
```go
func (h *Handler) PublicResource(c *gin.Context) {
// Try to get org ID (may be 0 if not authenticated)
orgID := auth.GetOrganizationID(c)
if orgID != 0 {
// User is authenticated, show personalized data
} else {
// User is not authenticated, show public data
}
}
```
## File Locations
| Component | Path |
|-----------|------|
| Auth provider interface | `internal/auth/auth.go` |
| Middleware | `internal/auth/middleware.go` |
| Context helpers | `internal/auth/context.go` |
| RBAC definitions | `internal/auth/rbac.go` |
| Roles | `internal/auth/roles.go` |
| Permissions | `internal/auth/permissions.go` |
| Resolvers | `internal/auth/resolvers.go` |
| Stytch adapter | `internal/auth/adapters/stytch/` |
## Next Steps
- **Database operations**: See [Database Guide](./database.md)
- **Building APIs**: See [API Development Guide](./api-development.md)
- **Stytch documentation**: https://stytch.com/docs/b2b
================================================
FILE: go-b2b-starter/docs/billing.md
================================================
# Billing Guide
The billing system integrates with Polar.sh for subscription management, usage-based billing, and payment processing with a hybrid sync strategy.
## Architecture
**Polar.sh**: Payment provider for subscriptions and metering
**Hybrid Sync**: Webhooks + on-demand fetching
**Paywall Middleware**: Protects routes based on subscription status
**Quota Tracking**: Usage-based billing with meters
## Core Concepts
### Subscriptions
Managed in Polar.sh, synced to local database.
**Subscription states:**
- `active` - Valid subscription
- `incomplete` - Payment pending
- `cancelled` - Subscription cancelled
- `unpaid` - Payment failed
### Quota Tracking
Track usage for metered billing.
**How it works:**
1. User performs action (API call, file upload, etc.)
2. System increments local quota counter
3. Periodically sync usage to Polar meters
4. Polar charges based on usage
### Billing Status
Represents organization's billing state:
- **Subscription**: Active subscription details
- **Quota Usage**: Current usage vs limits
- **Payment Status**: Last payment result
- **Metering**: Usage meters for billing
## Hybrid Sync Strategy
Combines webhooks with on-demand fetching for reliability.
### Webhook Path (Real-time)
```
Polar Event → Webhook → Update Database
```
**Handles:**
- Subscription created/updated/cancelled
- Payment succeeded/failed
- Customer created/updated
### Lazy Guarding (On-demand)
```
API Request → Check Subscription → Fetch if stale → Update Database
```
**When used:**
- Webhook delivery failed
- Data drift detected
- Initial subscription fetch
**Benefits:**
- Self-healing system
- No critical webhook dependency
- Always up-to-date data
## Paywall Middleware
Protects routes based on subscription requirements.
### Basic Usage
```go
router.POST("/premium-feature",
paywallMiddleware.RequireActiveSubscription(),
handler.PremiumFeature)
```
### Quota-Based Protection
```go
router.POST("/api-call",
paywallMiddleware.RequireQuota("api_calls", 1),
handler.APICall)
```
**What it does:**
1. Checks organization has active subscription
2. Verifies quota available
3. Increments usage counter
4. Returns 402 (Payment Required) if quota exceeded
### Feature-Based Protection
```go
router.POST("/advanced-feature",
paywallMiddleware.RequireFeature("advanced_analytics"),
handler.AdvancedFeature)
```
Checks if subscription plan includes specific feature.
## Webhook Processing
Polar sends webhooks for billing events.
### Webhook Handler
Located in `internal/billing/polar_handler.go`.
**Events handled:**
- `subscription.created`
- `subscription.updated`
- `subscription.canceled`
- `checkout.created`
- `checkout.updated`
### Verification
Webhooks are verified using Polar webhook secret:
```env
POLAR_WEBHOOK_SECRET=whsec_xxx
```
Invalid signatures are rejected.
## Usage Tracking
Track resource usage for billing.
### Recording Usage
```go
func (s *service) ProcessAction(ctx context.Context, orgID int32) error {
// Perform action
result, err := s.doAction(ctx)
if err != nil {
return err
}
// Record usage
err = s.billingService.IncrementQuota(ctx, orgID, "actions", 1)
if err != nil {
// Log error but don't fail the operation
log.Error("failed to record usage", zap.Error(err))
}
return nil
}
```
### Meter Ingestion
Usage synced to Polar periodically:
1. Accumulate usage locally
2. Batch send to Polar meters API
3. Polar charges based on metered usage
Configured in `internal/billing/app/services/metering_service.go`.
## Configuration
```env
# Polar.sh
POLAR_ACCESS_TOKEN=polar_xxx
POLAR_WEBHOOK_SECRET=whsec_xxx
POLAR_ORGANIZATION_ID=org_xxx
```
## Common Patterns
### Check Subscription Status
```go
func (h *Handler) GetFeature(c *gin.Context) {
orgID := auth.GetOrganizationID(c)
status, err := h.billingService.GetBillingStatus(ctx, orgID)
if err != nil {
c.JSON(500, gin.H{"error": "failed to get billing status"})
return
}
if status.Subscription == nil || !status.Subscription.IsActive() {
c.JSON(402, gin.H{"error": "active subscription required"})
return
}
// Proceed with feature
}
```
### Track Usage
```go
func (s *service) ProcessFile(ctx context.Context, orgID int32, file *File) error {
// Process file
err := s.processor.Process(file)
if err != nil {
return err
}
// Record usage
s.billingService.IncrementQuota(ctx, orgID, "files_processed", 1)
return nil
}
```
### Handle Payment Failures
```go
func (h *WebhookHandler) HandlePaymentFailed(ctx context.Context, event *Event) error {
// Update subscription status
err := h.billingService.UpdateSubscriptionStatus(ctx, event.SubscriptionID, "unpaid")
if err != nil {
return err
}
// Notify organization
h.notificationService.SendPaymentFailure(ctx, event.OrganizationID)
return nil
}
```
## File Locations
| Component | Path |
|-----------|------|
| Billing domain | `internal/billing/domain/` |
| Billing service | `internal/billing/app/services/` |
| Polar adapter | `internal/billing/infra/adapters/polar/` |
| Paywall middleware | `internal/paywall/` |
| Polar client | `internal/polar/` |
| Webhook handlers | `internal/billing/` |
## Next Steps
- **API protection**: Use paywall middleware in routes
- **Usage tracking**: Implement quota consumption
- **Polar documentation**: https://docs.polar.sh/
================================================
FILE: go-b2b-starter/docs/database.md
================================================
# Database Guide
The database layer uses PostgreSQL with SQLC for type-safe SQL operations. Domain modules define repository interfaces in their `domain/` layer, which are implemented by repositories in the `infra/` layer using SQLC.
## Architecture
The database layer follows the **Repository Pattern**:
**1. Domain Interfaces** (`internal/modules/{module}/domain/repository.go`) - Repository contracts defined by the domain
**2. Repository Implementations** (`internal/modules/{module}/infra/repositories/`) - Implement interfaces using SQLC
**3. SQLC Generated Code** (`internal/db/postgres/sqlc/gen/`) - Auto-generated type-safe queries
**4. DI Registration** (`internal/db/inject.go`) - Wire repositories to domain interfaces
### Why This Pattern?
- **Dependency Inversion** - Domain defines what it needs, infrastructure provides it
- **SQLC Isolation** - SQLC types never leak out of the `infra/` layer
- **Easy Testing** - Mock domain interfaces, not SQLC
- **Clean Boundaries** - Domain stays pure, no database knowledge
- **Type Safety** - SQLC generates type-safe Go code from SQL
### Legacy Note
> **Note**: Earlier versions used an `adapters/` and `adapter_impl/` pattern. This has been phased out in favor of the simpler repository pattern where domain interfaces are implemented directly by repository classes.
## SQLC Workflow
### 1. Write SQL Query
Create queries in `internal/db/postgres/sqlc/query/{domain}.sql`:
```sql
-- name: GetDocumentByID :one
SELECT * FROM documents
WHERE organization_id = $1 AND id = $2;
-- name: CreateDocument :one
INSERT INTO documents (organization_id, title, file_path, status)
VALUES ($1, $2, $3, $4)
RETURNING *;
-- name: ListDocuments :many
SELECT * FROM documents
WHERE organization_id = $1
ORDER BY created_at DESC
LIMIT $2 OFFSET $3;
```
**SQLC Annotations:**
- `:one` - Returns single row
- `:many` - Returns slice of rows
- `:exec` - Returns error only (no data)
### 2. Generate Code
```bash
make sqlc
```
Generates Go code in `internal/db/postgres/sqlc/gen/`.
**Never edit generated files** - they are regenerated on every run.
### 3. Define Repository Interface in Domain
Define interface in `internal/modules/documents/domain/repository.go`:
```go
package domain
import "context"
type DocumentRepository interface {
GetByID(ctx context.Context, orgID, docID int32) (*Document, error)
Create(ctx context.Context, doc *Document) (*Document, error)
List(ctx context.Context, orgID int32, limit, offset int32) ([]*Document, error)
Update(ctx context.Context, doc *Document) error
Delete(ctx context.Context, orgID, docID int32) error
}
```
**Key Points:**
- Interface uses **domain types** (`*Document`), not SQLC types
- Defined where it's used (in the domain layer)
- Independent of implementation details
### 4. Implement Repository
Create repository in `internal/modules/documents/infra/repositories/document_repository.go`:
```go
package repositories
import (
"context"
"fmt"
"github.com/moasq/go-b2b-starter/internal/modules/documents/domain"
sqlc "github.com/moasq/go-b2b-starter/internal/db/postgres/sqlc/gen"
)
type documentRepository struct {
store sqlc.Store
}
func NewDocumentRepository(store sqlc.Store) domain.DocumentRepository {
return &documentRepository{store: store}
}
func (r *documentRepository) GetByID(ctx context.Context, orgID, docID int32) (*domain.Document, error) {
// Call SQLC-generated method
dbDoc, err := r.store.GetDocumentByID(ctx, sqlc.GetDocumentByIDParams{
OrganizationID: orgID,
ID: docID,
})
if err != nil {
return nil, fmt.Errorf("failed to get document: %w", err)
}
// Map SQLC type to domain type
return &domain.Document{
ID: dbDoc.ID,
OrganizationID: dbDoc.OrganizationID,
Title: dbDoc.Title,
FilePath: dbDoc.FilePath,
Status: dbDoc.Status,
CreatedAt: dbDoc.CreatedAt,
UpdatedAt: dbDoc.UpdatedAt,
}, nil
}
func (r *documentRepository) Create(ctx context.Context, doc *domain.Document) (*domain.Document, error) {
dbDoc, err := r.store.CreateDocument(ctx, sqlc.CreateDocumentParams{
OrganizationID: doc.OrganizationID,
Title: doc.Title,
FilePath: doc.FilePath,
Status: doc.Status,
})
if err != nil {
return nil, fmt.Errorf("failed to create document: %w", err)
}
// Map back to domain
return &domain.Document{
ID: dbDoc.ID,
OrganizationID: dbDoc.OrganizationID,
Title: dbDoc.Title,
FilePath: dbDoc.FilePath,
Status: dbDoc.Status,
CreatedAt: dbDoc.CreatedAt,
UpdatedAt: dbDoc.UpdatedAt,
}, nil
}
```
**Why Map Types?**
- SQLC types (`sqlc.Document`) are generated and may change
- Domain types (`domain.Document`) are stable and business-focused
- Mapping keeps SQLC isolated in the infrastructure layer
### 5. Register in DI
Add to `internal/db/inject.go`:
```go
import (
documentDomain "github.com/moasq/go-b2b-starter/internal/modules/documents/domain"
documentRepos "github.com/moasq/go-b2b-starter/internal/modules/documents/infra/repositories"
)
// In registerDomainStores function:
if err := container.Provide(func(sqlcStore sqlc.Store) documentDomain.DocumentRepository {
return documentRepos.NewDocumentRepository(sqlcStore)
}); err != nil {
return fmt.Errorf("failed to provide document repository: %w", err)
}
```
**Why Centralize DI?**
- All repository registrations in one place
- Easy to see all database dependencies
- Consistent pattern across modules
## Database Migrations
### File Structure
Migrations live in `internal/db/postgres/sqlc/migrations/`:
```
000001_create_schema.up.sql
000001_create_schema.down.sql
000002_add_indexes.up.sql
000002_add_indexes.down.sql
```
### Naming Convention
Format: `{6-digit-number}_{description}.{up|down}.sql`
- `.up.sql` - Apply the migration
- `.down.sql` - Rollback the migration
### Example Migration
**Up migration** (`000005_create_documents.up.sql`):
```sql
CREATE SCHEMA IF NOT EXISTS app;
CREATE TABLE app.documents (
id SERIAL PRIMARY KEY,
organization_id INTEGER NOT NULL,
title VARCHAR(255) NOT NULL,
file_path VARCHAR(512) NOT NULL,
status VARCHAR(50) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT fk_organization
FOREIGN KEY (organization_id)
REFERENCES app.organizations(id)
ON DELETE CASCADE
);
CREATE INDEX idx_documents_org_id ON app.documents(organization_id);
CREATE INDEX idx_documents_status ON app.documents(status);
```
**Down migration** (`000005_create_documents.down.sql`):
```sql
DROP TABLE IF EXISTS app.documents;
```
### Running Migrations
```bash
make migrateup # Apply all pending migrations
make migratedown # Rollback last migration
```
## Type Conversions
PostgreSQL types need conversion to Go types.
### Nullable Fields
SQLC uses `pgtype` for nullable fields:
```go
// Convert pgtype.Text to string
str := postgres.StringFromPgText(dbRecord.NullableField)
// Convert string to pgtype.Text
pgText := postgres.ToPgText(str)
// Convert pgtype.Int4 to int32
num := postgres.Int32FromPgInt4(dbRecord.NullableInt)
```
Helper functions in `internal/db/postgres/types_transform.go`.
### JSONB Fields
```go
// Convert map to JSONB
jsonbData := postgres.ToJSONB(map[string]any{"key": "value"})
// Convert JSONB to map
data := postgres.JSONBToMap(dbRecord.Metadata)
```
## Error Handling
The database layer provides specific error types in `internal/db/core/errors.go`:
**Common Errors:**
- `ErrNoRows` - Query returned no results
- `ErrTxClosed` - Transaction already committed/rolled back
- `ErrTimeout` - Operation exceeded timeout
- `ErrPoolClosed` - Connection pool is closed
**Helper Functions:**
```go
if core.IsNoRowsError(err) {
return domain.ErrDocumentNotFound
}
if core.IsConstraintError(err, "unique_title") {
return domain.ErrDocumentAlreadyExists
}
if core.IsTimeoutError(err) {
return domain.ErrDatabaseTimeout
}
```
## Transactions
Use transactions for multi-step operations that must be atomic.
### Basic Transaction
```go
func (r *repository) CreateWithRelation(ctx context.Context, doc *domain.Document) error {
return r.db.WithTx(ctx, func(tx core.Transaction) error {
// Step 1: Create document
created, err := tx.CreateDocument(ctx, params)
if err != nil {
return err
}
// Step 2: Create embeddings
_, err = tx.CreateEmbedding(ctx, embeddingParams)
if err != nil {
return err // Transaction auto-rolls back on error
}
return nil // Transaction commits on success
})
}
```
### Transaction Options
```go
// Read-only transaction
err := r.db.WithTxOptions(ctx, &sql.TxOptions{ReadOnly: true}, func(tx core.Transaction) error {
// Read operations only
})
// Custom isolation level
err := r.db.WithTxOptions(ctx, &sql.TxOptions{
Isolation: sql.LevelSerializable,
}, func(tx core.Transaction) error {
// Operations
})
```
## Best Practices
### Always Use Context
```go
// ✅ Good
func (r *repository) GetDocument(ctx context.Context, id int32) (*Document, error)
// ❌ Bad
func (r *repository) GetDocument(id int32) (*Document, error)
```
### Handle Errors Appropriately
```go
// ✅ Convert database errors to domain errors
doc, err := r.store.GetDocumentByID(ctx, params)
if err != nil {
if core.IsNoRowsError(err) {
return nil, domain.ErrDocumentNotFound
}
return nil, fmt.Errorf("failed to get document: %w", err)
}
```
### Use Prepared Statements
SQLC automatically creates prepared statements. Never concatenate SQL strings.
```go
// ✅ Good (SQLC handles this)
SELECT * FROM documents WHERE title = $1
// ❌ Bad (SQL injection risk)
query := fmt.Sprintf("SELECT * FROM documents WHERE title = '%s'", title)
```
### Indexes for Performance
Add indexes for commonly queried fields:
```sql
-- Foreign keys
CREATE INDEX idx_documents_org_id ON documents(organization_id);
-- Status fields
CREATE INDEX idx_documents_status ON documents(status);
-- Timestamps for sorting
CREATE INDEX idx_documents_created_at ON documents(created_at DESC);
-- Composite indexes for multi-column queries
CREATE INDEX idx_documents_org_status ON documents(organization_id, status);
```
### Map SQLC Types to Domain Types
Always convert SQLC types to domain types in the repository layer:
```go
// ✅ Good - Repository returns domain types
func (r *repository) GetDocument(ctx context.Context, id int32) (*domain.Document, error) {
dbDoc, err := r.store.GetDocumentByID(ctx, id)
if err != nil {
return nil, err
}
// Map SQLC type to domain type
return &domain.Document{
ID: dbDoc.ID,
Title: dbDoc.Title,
// ... other fields
}, nil
}
// ❌ Bad - Service receives SQLC types
func (s *service) GetDocument(ctx context.Context, id int32) (*sqlc.Document, error)
```
## Complete Example: Adding a New Entity
Let's add a `Comment` entity to the documents module:
### 1. Write Migration
`internal/db/postgres/sqlc/migrations/000010_create_comments.up.sql`:
```sql
CREATE TABLE app.comments (
id SERIAL PRIMARY KEY,
document_id INTEGER NOT NULL,
author_id INTEGER NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT fk_document
FOREIGN KEY (document_id)
REFERENCES app.documents(id)
ON DELETE CASCADE
);
CREATE INDEX idx_comments_document_id ON app.comments(document_id);
```
### 2. Write SQLC Queries
`internal/db/postgres/sqlc/query/comments.sql`:
```sql
-- name: CreateComment :one
INSERT INTO comments (document_id, author_id, content)
VALUES ($1, $2, $3)
RETURNING *;
-- name: ListCommentsByDocument :many
SELECT * FROM comments
WHERE document_id = $1
ORDER BY created_at ASC;
```
### 3. Generate SQLC Code
```bash
make migrateup
make sqlc
```
### 4. Define Domain Interface
`internal/modules/documents/domain/repository.go`:
```go
type CommentRepository interface {
Create(ctx context.Context, comment *Comment) (*Comment, error)
ListByDocument(ctx context.Context, docID int32) ([]*Comment, error)
}
```
### 5. Implement Repository
`internal/modules/documents/infra/repositories/comment_repository.go`:
```go
package repositories
import (
"context"
"github.com/moasq/go-b2b-starter/internal/modules/documents/domain"
sqlc "github.com/moasq/go-b2b-starter/internal/db/postgres/sqlc/gen"
)
type commentRepository struct {
store sqlc.Store
}
func NewCommentRepository(store sqlc.Store) domain.CommentRepository {
return &commentRepository{store: store}
}
func (r *commentRepository) Create(ctx context.Context, comment *domain.Comment) (*domain.Comment, error) {
dbComment, err := r.store.CreateComment(ctx, sqlc.CreateCommentParams{
DocumentID: comment.DocumentID,
AuthorID: comment.AuthorID,
Content: comment.Content,
})
if err != nil {
return nil, err
}
return &domain.Comment{
ID: dbComment.ID,
DocumentID: dbComment.DocumentID,
AuthorID: dbComment.AuthorID,
Content: dbComment.Content,
CreatedAt: dbComment.CreatedAt,
}, nil
}
```
### 6. Register in DI
`internal/db/inject.go`:
```go
if err := container.Provide(func(sqlcStore sqlc.Store) documentDomain.CommentRepository {
return documentRepos.NewCommentRepository(sqlcStore)
}); err != nil {
return fmt.Errorf("failed to provide comment repository: %w", err)
}
```
## File Locations
| Component | Path |
|-----------|------|
| Domain interfaces | `internal/modules/{module}/domain/repository.go` |
| Repository implementations | `internal/modules/{module}/infra/repositories/` |
| SQL queries | `internal/db/postgres/sqlc/query/` |
| Migrations | `internal/db/postgres/sqlc/migrations/` |
| Generated code | `internal/db/postgres/sqlc/gen/` |
| Type helpers | `internal/db/postgres/types_transform.go` |
| Error types | `internal/db/core/errors.go` |
| DI registration | `internal/db/inject.go` |
## Next Steps
- **Using repositories in services**: See [Architecture Guide](./architecture.md)
- **Building APIs**: See [API Development Guide](./api-development.md)
- **Adding a new module**: See [Adding a Module Guide](./02-adding-a-module.md)
- **SQLC documentation**: https://docs.sqlc.dev/
================================================
FILE: go-b2b-starter/docs/event-bus.md
================================================
# Event Bus Guide
The event bus enables event-driven architecture for loose coupling between modules using an in-memory publish-subscribe pattern.
## Architecture
**In-memory event bus** - Simple, fast, synchronous
**Publisher-subscriber pattern** - Decouple event producers from consumers
**Type-safe events** - Events are Go structs implementing Event interface
## Core Concepts
### Events
Events represent things that have happened in the system.
**Naming**: Past tense (ResourceCreated, ResourceUpdated, ResourceDeleted)
```go
type ResourceCreatedEvent struct {
BaseEvent
ResourceID int32 `json:"resource_id"`
Name string `json:"name"`
CreatedBy int32 `json:"created_by"`
CreatedAt time.Time `json:"created_at"`
}
```
### Event Interface
All events implement the Event interface:
```go
type Event interface {
EventName() string
EventID() string
OccurredAt() time.Time
}
```
### BaseEvent
Provides common event fields:
```go
type BaseEvent struct {
ID string `json:"id"`
Name string `json:"name"`
Timestamp time.Time `json:"timestamp"`
}
```
## Publishing Events
Emit events when something happens:
```go
func (s *service) CreateResource(ctx context.Context, req *Request) (*Resource, error) {
// Create resource
resource, err := s.repo.Create(ctx, req)
if err != nil {
return nil, err
}
// Publish event
event := &ResourceCreatedEvent{
ResourceID: resource.ID,
Name: resource.Name,
CreatedBy: req.UserID,
CreatedAt: resource.CreatedAt,
}
s.eventBus.Publish(ctx, event)
return resource, nil
}
```
**Note**: Publish is fire-and-forget. Failures don't block the operation.
## Subscribing to Events
Listen for events and react:
```go
func (l *ResourceListener) Init(eventBus eventbus.EventBus) {
// Subscribe to events
eventBus.Subscribe("resource.created", l.HandleResourceCreated)
eventBus.Subscribe("resource.updated", l.HandleResourceUpdated)
}
func (l *ResourceListener) HandleResourceCreated(ctx context.Context, event eventbus.Event) error {
resourceEvent := event.(*ResourceCreatedEvent)
// React to event
log.Info("Resource created", zap.Int32("id", resourceEvent.ResourceID))
// Trigger other actions
return l.notificationService.NotifyResourceCreated(ctx, resourceEvent.ResourceID)
}
```
## Event Flow
```
Service → Publish Event → Event Bus → Notify Subscribers → Execute Handlers
```
**Synchronous**: Subscribers execute in the same request context
**Ordered**: Subscribers execute in registration order
**Error handling**: Subscriber errors are logged but don't fail the operation
## Common Patterns
### Cross-Module Communication
Module A publishes events, Module B subscribes:
```go
// Module A (Resources)
func (s *resourceService) Delete(ctx context.Context, id int32) error {
err := s.repo.Delete(ctx, id)
if err != nil {
return err
}
s.eventBus.Publish(ctx, &ResourceDeletedEvent{ResourceID: id})
return nil
}
// Module B (Analytics)
func (l *analyticsListener) HandleResourceDeleted(ctx context.Context, event eventbus.Event) error {
evt := event.(*ResourceDeletedEvent)
return l.analyticsService.RecordDeletion(ctx, evt.ResourceID)
}
```
### Audit Logging
Subscribe to all events for audit trail:
```go
func (l *auditListener) Init(eventBus eventbus.EventBus) {
eventBus.Subscribe("*.created", l.HandleCreated)
eventBus.Subscribe("*.updated", l.HandleUpdated)
eventBus.Subscribe("*.deleted", l.HandleDeleted)
}
func (l *auditListener) HandleCreated(ctx context.Context, event eventbus.Event) error {
return l.auditService.Log(ctx, "created", event)
}
```
### Async Processing
Trigger background jobs from events:
```go
func (l *processingListener) HandleFileUploaded(ctx context.Context, event eventbus.Event) error {
evt := event.(*FileUploadedEvent)
// Queue async job
return l.jobQueue.Enqueue(ctx, &ProcessFileJob{
FileID: evt.FileID,
})
}
```
## Registration
Register listeners during module initialization:
```go
// internal/resources/cmd/init.go
func Init(container *dig.Container) error {
return container.Invoke(func(
eventBus eventbus.EventBus,
listener *listeners.ResourceListener,
) {
listener.Init(eventBus)
})
}
```
## File Locations
| Component | Path |
|-----------|------|
| Event bus interface | `internal/eventbus/eventbus.go` |
| Event interface | `internal/eventbus/event.go` |
| Base event | `internal/eventbus/base_event.go` |
| Implementation | `internal/eventbus/memory_eventbus.go` |
| Domain events | `internal/*/domain/events/` |
| Event listeners | `internal/*/domain/listeners/` |
## Next Steps
- **Define events**: Create event structs in `domain/events/`
- **Implement listeners**: Handle events in `domain/listeners/`
- **Publish events**: Emit events in service layer
================================================
FILE: go-b2b-starter/docs/file-manager.md
================================================
# File Manager Guide
The file manager provides file storage using Cloudflare R2 (object storage) with PostgreSQL for searchable metadata.
## Architecture
**Dual-layer design:**
**R2 Storage** - Stores actual file content
**PostgreSQL** - Stores searchable metadata
This separation enables fast querying while leveraging object storage scalability.
## Components
**FileRepository**: Combined operations (upload, download, delete, search)
**R2Repository**: R2 object storage operations
**FileMetadataRepository**: Database metadata operations
**FileService**: Business logic with validation
## File Upload
### Basic Upload
```go
req := &domain.FileUploadRequest{
Filename: "document.pdf",
ContentType: "application/pdf",
Context: file_manager.ContextDocument,
}
file, err := fileService.UploadFile(ctx, req, fileReader)
```
### Upload with Entity Linking
Link files to domain entities (like resources, users, etc.):
```go
req := &domain.FileUploadRequest{
Filename: "profile.jpg",
ContentType: "image/jpeg",
Context: file_manager.ContextProfile,
}
file := &domain.FileAsset{
EntityType: "user",
EntityID: userID,
}
uploadedFile, err := fileService.UploadFile(ctx, req, fileReader)
```
### Upload Flow
1. Validate file (size, type, magic bytes)
2. Save metadata to database (get ID)
3. Upload content to R2 (using database ID in key)
4. Update metadata with storage path
5. Rollback on failure (atomic operation)
## File Download
### Get Presigned URL
Generate temporary download link:
```go
url, err := fileService.GetPresignedURL(ctx, fileID, 15*time.Minute)
```
Returns a time-limited URL for direct download from R2.
### Download File Content
```go
content, err := fileService.DownloadFile(ctx, fileID)
```
Returns `io.ReadCloser` with file content.
## File Search
### By Entity
Get all files for a specific entity:
```go
files, err := fileRepo.GetByEntity(ctx, "resource", resourceID)
```
### By Category
Find files by category:
```go
documents, err := fileRepo.GetByCategory(ctx, file_manager.CategoryDocument, 10, 0)
```
### By Context
Search by context type:
```go
profiles, err := fileRepo.GetByContext(ctx, file_manager.ContextProfile, 20, 0)
```
## File Validation
Automatic validation on upload:
**Magic byte verification** - Validates file type matches content
**Size limits** - Configurable max file size
**Content type** - Ensures valid MIME type
Configure in `FileService` initialization.
## Contexts and Categories
### Predefined Contexts
- `ContextDocument` - General documents
- `ContextProfile` - Profile images
- `ContextAttachment` - Email/message attachments
- `ContextThumbnail` - Image thumbnails
### Categories
- `CategoryDocument` - PDFs, docs
- `CategoryImage` - Images
- `CategoryVideo` - Videos
- `CategoryArchive` - ZIP, TAR files
Defined in `internal/files/domain/constants.go`.
## Configuration
```env
# Cloudflare R2
R2_ACCOUNT_ID=your-account-id
R2_ACCESS_KEY_ID=your-access-key
R2_SECRET_ACCESS_KEY=your-secret-key
R2_BUCKET_NAME=files
R2_REGION=auto # Usually "auto" for R2
```
## Common Patterns
### Upload User Avatar
```go
func (s *service) UpdateAvatar(ctx context.Context, userID int32, avatar io.Reader) error {
req := &domain.FileUploadRequest{
Filename: fmt.Sprintf("avatar_%d.jpg", userID),
ContentType: "image/jpeg",
Context: file_manager.ContextProfile,
}
file, err := s.fileService.UploadFile(ctx, req, avatar)
if err != nil {
return err
}
// Link to user
return s.userRepo.UpdateAvatar(ctx, userID, file.ID)
}
```
### Get Entity Files
```go
func (h *Handler) GetResourceFiles(c *gin.Context) {
resourceID := parseID(c.Param("id"))
files, err := h.fileRepo.GetByEntity(c.Request.Context(), "resource", resourceID)
if err != nil {
c.JSON(500, gin.H{"error": "failed to get files"})
return
}
c.JSON(200, files)
}
```
### Delete File
```go
func (s *service) DeleteResource(ctx context.Context, resourceID int32) error {
// Get associated files
files, err := s.fileRepo.GetByEntity(ctx, "resource", resourceID)
if err != nil {
return err
}
// Delete files
for _, file := range files {
err = s.fileService.DeleteFile(ctx, file.ID)
if err != nil {
return err
}
}
// Delete resource
return s.resourceRepo.Delete(ctx, resourceID)
}
```
## File Locations
| Component | Path |
|-----------|------|
| Domain entities | `internal/files/domain/` |
| File service | `internal/files/internal/app/` |
| R2 repository | `internal/files/internal/infra/r2/` |
| Metadata repository | `internal/files/internal/infra/metadata/` |
| Constants | `internal/files/domain/constants.go` |
## Next Steps
- **Upload files**: Integrate file upload in your features
- **Link entities**: Associate files with domain objects
- **R2 documentation**: https://developers.cloudflare.com/r2/
================================================
FILE: go-b2b-starter/example.env
================================================
# Go B2B SaaS Starter Kit - Environment Configuration Template
# Copy this file to app.env and fill in your actual values
# Environment
ENV=DEV
ALLOW_SELF_APPROVAL=true
# Server
SERVER_ADDRESS=:8080
RATE_LIMIT_PER_SECOND=100
MAX_REQUEST_SIZE=10485760
# Security Settings
TLS_CERT_PATH=/path/to/cert.pem
TLS_KEY_PATH=/path/to/key.pem
TRUSTED_PROXIES=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:3001
# Redis Configuration
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
# Postgres Configuration
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DB=mydatabase
POSTGRES_USER=user
POSTGRES_PASSWORD=password
DB_SSL_MODE=disable
MIGRATION_URL=src/pkg/db/postgres/sqlc/migrations
SEED_URL=src/pkg/db/postgres/seed
# Auth Configuration
ACCESS_TOKEN_DURATION=3h
REFRESH_TOKEN_DURATION=72h
TOKEN_SYMMETRIC_KEY=REPLACE_WITH_YOUR_32_CHAR_SECRET_KEY
SESSION_ENCRYPTION_KEY=REPLACE_WITH_YOUR_32_CHAR_SESSION_KEY
PASSWORD_HASH_COST=12
MAX_LOGIN_ATTEMPTS=5
LOCKOUT_DURATION=15m
JWT_ISSUER=go-b2b-starter
# === Stytch B2B configuration ===
STYTCH_PROJECT_ID=project-test-REPLACE_WITH_YOUR_STYTCH_PROJECT_ID
STYTCH_SECRET=secret-test-REPLACE_WITH_YOUR_STYTCH_SECRET
STYTCH_ENV=test
STYTCH_SESSION_DURATION_MINUTES=1440
STYTCH_INVITE_REDIRECT_URL=http://localhost:3000/authenticate
STYTCH_LOGIN_REDIRECT_URL=http://localhost:3000/authenticate
STYTCH_OWNER_ROLE_SLUG=owner
STYTCH_DISABLE_SESSION_VERIFICATION=false
# Cloudflare R2 Configuration
R2_ACCOUNT_ID=REPLACE_WITH_YOUR_R2_ACCOUNT_ID
R2_ACCESS_KEY_ID=REPLACE_WITH_YOUR_R2_ACCESS_KEY
R2_SECRET_ACCESS_KEY=REPLACE_WITH_YOUR_R2_SECRET_KEY
R2_BUCKET=uploads
R2_REGION=auto
S3_API=https://REPLACE_WITH_YOUR_R2_ACCOUNT_ID.r2.cloudflarestorage.com
# OpenAI Configuration
OPENAI_API_KEY=sk-proj-REPLACE_WITH_YOUR_OPENAI_API_KEY
OPENAI_MODEL=gpt-4o-mini
OPENAI_MAX_TOKENS=500
OPENAI_TEMPERATURE=0.0
LLM_TIMEOUT_SEC=30
LLM_MAX_RETRIES=1
LLM_FALLBACK_ENABLED=true
# Mistral Configuration
MISTRAL_API_KEY=REPLACE_WITH_YOUR_MISTRAL_API_KEY
OCR_DEBUG_MODE=true
# Polar Configuration
POLAR_ACCESS_TOKEN=polar_oat_REPLACE_WITH_YOUR_POLAR_ACCESS_TOKEN
POLAR_BASE_URL=https://sandbox-api.polar.sh
POLAR_DEBUG=true
WEBHOOK_SECRET=polar_whs_REPLACE_WITH_YOUR_WEBHOOK_SECRET
NEXT_PUBLIC_POLAR_PRODUCT_ID=REPLACE_WITH_YOUR_PRODUCT_ID
NEXT_PUBLIC_POLAR_BUSINESS_PRODUCT_ID=REPLACE_WITH_YOUR_BUSINESS_PRODUCT_ID
================================================
FILE: go-b2b-starter/go.mod
================================================
module github.com/moasq/go-b2b-starter
go 1.25
require (
github.com/KyleBanks/depth v1.2.1
github.com/MicahParks/keyfunc/v2 v2.0.1
github.com/aws/aws-sdk-go-v2 v1.24.0
github.com/aws/aws-sdk-go-v2/config v1.26.1
github.com/aws/aws-sdk-go-v2/credentials v1.16.12
github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5
github.com/aws/smithy-go v1.19.0
github.com/gabriel-vasile/mimetype v1.4.10
github.com/gin-contrib/cors v1.7.2
github.com/gin-gonic/gin v1.10.1
github.com/go-openapi/jsonpointer v0.19.5
github.com/go-openapi/jsonreference v0.20.0
github.com/go-openapi/spec v0.20.6
github.com/go-openapi/swag v0.19.15
github.com/go-playground/validator/v10 v10.23.0
github.com/golang-jwt/jwt/v5 v5.3.0
github.com/golang-migrate/migrate/v4 v4.17.1
github.com/google/uuid v1.6.0
github.com/jackc/pgx/v5 v5.7.2
github.com/joho/godotenv v1.5.1
github.com/pgvector/pgvector-go v0.3.0
github.com/prometheus/client_golang v1.20.5
github.com/redis/go-redis/v9 v9.7.0
github.com/rs/zerolog v1.33.0
github.com/shopspring/decimal v1.4.0
github.com/spf13/viper v1.19.0
github.com/stytchauth/stytch-go/v16 v16.40.0
github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.0
github.com/swaggo/swag v1.16.3
github.com/twpayne/go-geom v1.6.1
go.uber.org/dig v1.19.0
go.uber.org/zap v1.27.0
golang.org/x/time v0.8.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
)
require (
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bytedance/sonic v1.12.5 // indirect
github.com/bytedance/sonic/loader v0.2.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.12.0 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect
golang.org/x/net v0.37.0 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
golang.org/x/tools v0.31.0 // indirect
google.golang.org/protobuf v1.35.2 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
================================================
FILE: go-b2b-starter/go.sum
================================================
entgo.io/ent v0.14.3 h1:wokAV/kIlH9TeklJWGGS7AYJdVckr0DloWjIcO9iIIQ=
entgo.io/ent v0.14.3/go.mod h1:aDPE/OziPEu8+OWbzy4UlvWmD2/kbRuWfK2A40hcxJM=
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/MicahParks/keyfunc/v2 v2.0.1 h1:6FrNNvG/20gEKkjxV+5anrkq0VOF666G2zUn8lk8dgk=
github.com/MicahParks/keyfunc/v2 v2.0.1/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k=
github.com/alecthomas/assert/v2 v2.10.0 h1:jjRCHsj6hBJhkmhznrCzoNpbA3zqy0fYiUcYZP/GkPY=
github.com/alecthomas/assert/v2 v2.10.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/aws/aws-sdk-go-v2 v1.24.0 h1:890+mqQ+hTpNuw0gGP6/4akolQkSToDJgHfQE7AwGuk=
github.com/aws/aws-sdk-go-v2 v1.24.0/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 h1:OCs21ST2LrepDfD3lwlQiOqIGp6JiEUqG84GzTDoyJs=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4/go.mod h1:usURWEKSNNAcAZuzRn/9ZYPT8aZQkR7xcCtunK/LkJo=
github.com/aws/aws-sdk-go-v2/config v1.26.1 h1:z6DqMxclFGL3Zfo+4Q0rLnAZ6yVkzCRxhRMsiRQnD1o=
github.com/aws/aws-sdk-go-v2/config v1.26.1/go.mod h1:ZB+CuKHRbb5v5F0oJtGdhFTelmrxd4iWO1lf0rQwSAg=
github.com/aws/aws-sdk-go-v2/credentials v1.16.12 h1:v/WgB8NxprNvr5inKIiVVrXPuuTegM+K8nncFkr1usU=
github.com/aws/aws-sdk-go-v2/credentials v1.16.12/go.mod h1:X21k0FjEJe+/pauud82HYiQbEr9jRKY3kXEIQ4hXeTQ=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 h1:w98BT5w+ao1/r5sUuiH6JkVzjowOKeOJRHERyy1vh58=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10/go.mod h1:K2WGI7vUvkIv1HoNbfBA1bvIZ+9kL3YVmWxeKuLQsiw=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 h1:v+HbZaCGmOwnTTVS86Fleq0vPzOd7tnJGbFhP0stNLs=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9/go.mod h1:Xjqy+Nyj7VDLBtCMkQYOw1QYfAEZCVLrfI0ezve8wd4=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 h1:N94sVhRACtXyVcjXxrwK1SKFIJrA9pOJ5yu2eSHnmls=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9/go.mod h1:hqamLz7g1/4EJP+GH5NBhcUMLjW+gKLQabgyz6/7WAU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 h1:ugD6qzjYtB7zM5PN/ZIeaAIyefPaD82G8+SJopgvUpw=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9/go.mod h1:YD0aYBWCrPENpHolhKw2XDlTIWae2GKXT1T4o6N6hiM=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9 h1:/90OR2XbSYfXucBMJ4U14wrjlfleq/0SB6dZDPncgmo=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9/go.mod h1:dN/Of9/fNZet7UrQQ6kTDo/VSwKPIq94vjlU16bRARc=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 h1:Nf2sHxjMJR8CSImIVCONRi4g0Su3J+TSTbS7G0pUeMU=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9/go.mod h1:idky4TER38YIjr2cADF1/ugFMKvZV7p//pVeV5LZbF0=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9 h1:iEAeF6YC3l4FzlJPP9H3Ko1TXpdjdqWffxXjp8SY6uk=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9/go.mod h1:kjsXoK23q9Z/tLBrckZLLyvjhZoS+AGrzqzUfEClvMM=
github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5 h1:Keso8lIOS+IzI2MkPZyK6G0LYcK3My2LQ+T5bxghEAY=
github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5/go.mod h1:vADO6Jn+Rq4nDtfwNjhgR84qkZwiC6FqCaXdw/kYwjA=
github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 h1:ldSFWz9tEHAwHNmjx2Cvy1MjP5/L9kNoR0skc6wyOOM=
github.com/aws/aws-sdk-go-v2/service/sso v1.18.5/go.mod h1:CaFfXLYL376jgbP7VKC96uFcU8Rlavak0UlAwk1Dlhc=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 h1:2k9KmFawS63euAkY4/ixVNsYYwrwnd5fIvgEKkfZFNM=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5/go.mod h1:W+nd4wWDVkSUIox9bacmkBP5NMFQeTJ/xqNabpzSR38=
github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 h1:5UYvv8JUvllZsRnfrcMQ+hJ9jNICmcgKPAO1CER25Wg=
github.com/aws/aws-sdk-go-v2/service/sts v1.26.5/go.mod h1:XX5gh4CB7wAs4KhcF46G6C8a2i7eupU19dcAAE+EydU=
github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM=
github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bytedance/sonic v1.12.5 h1:hoZxY8uW+mT+OpkcUWw4k0fDINtOcVavEsGfzwzFU/w=
github.com/bytedance/sonic v1.12.5/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E=
github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gin-contrib/cors v1.7.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQw=
github.com/gin-contrib/cors v1.7.2/go.mod h1:SUJVARKgQ40dmrzgXEVxj2m7Ig1v1qIboQkPDTQ9t2E=
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
github.com/go-openapi/spec v0.20.6 h1:ich1RQ3WDbfoeTqTAb+5EIxNmpKVJZWBNah9RAT0jIQ=
github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-pg/pg/v10 v10.11.0 h1:CMKJqLgTrfpE/aOVeLdybezR2om071Vh38OLZjsyMI0=
github.com/go-pg/pg/v10 v10.11.0/go.mod h1:4BpHRoxE61y4Onpof3x1a2SQvi9c+q1dJnrNdMjsroA=
github.com/go-pg/zerochecker v0.2.0 h1:pp7f72c3DobMWOb2ErtZsnrPaSvHd2W4o9//8HtF4mU=
github.com/go-pg/zerochecker v0.2.0/go.mod h1:NJZ4wKL0NmTtz0GKCoJ8kym6Xn/EQzXRl2OnAe7MmDo=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o=
github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang-migrate/migrate/v4 v4.17.1 h1:4zQ6iqL6t6AiItphxJctQb3cFqWiSpMnX7wLTPnnYO4=
github.com/golang-migrate/migrate/v4 v4.17.1/go.mod h1:m8hinFyWBn0SA4QKHuKh175Pm9wjmxj3S2Mia7dbXzM=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI=
github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pgvector/pgvector-go v0.3.0 h1:Ij+Yt78R//uYqs3Zk35evZFvr+G0blW0OUN+Q2D1RWc=
github.com/pgvector/pgvector-go v0.3.0/go.mod h1:duFy+PXWfW7QQd5ibqutBO4GxLsUZ9RVXhFZGIBsWSA=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/stytchauth/stytch-go/v16 v16.40.0 h1:xT9QyPtWi4j6rJPhkROfGCDzDeVBqvS2KQge1dv8rfs=
github.com/stytchauth/stytch-go/v16 v16.40.0/go.mod h1:b2Dj63HNogYxAwJz7l9S7aJ8k3xyFYrMOtkzdTme+tk=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/twpayne/go-geom v1.6.1 h1:iLE+Opv0Ihm/ABIcvQFGIiFBXd76oBIar9drAwHFhR4=
github.com/twpayne/go-geom v1.6.1/go.mod h1:Kr+Nly6BswFsKM5sd31YaoWS5PeDDH2NftJTK7Gd028=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/uptrace/bun v1.1.12 h1:sOjDVHxNTuM6dNGaba0wUuz7KvDE1BmNu9Gqs2gJSXQ=
github.com/uptrace/bun v1.1.12/go.mod h1:NPG6JGULBeQ9IU6yHp7YGELRa5Agmd7ATZdz4tGZ6z0=
github.com/uptrace/bun/dialect/pgdialect v1.1.12 h1:m/CM1UfOkoBTglGO5CUTKnIKKOApOYxkcP2qn0F9tJk=
github.com/uptrace/bun/dialect/pgdialect v1.1.12/go.mod h1:Ij6WIxQILxLlL2frUBxUBOZJtLElD2QQNDcu/PWDHTc=
github.com/uptrace/bun/driver/pgdriver v1.1.12 h1:3rRWB1GK0psTJrHwxzNfEij2MLibggiLdTqjTtfHc1w=
github.com/uptrace/bun/driver/pgdriver v1.1.12/go.mod h1:ssYUP+qwSEgeDDS1xm2XBip9el1y9Mi5mTAvLoiADLM=
github.com/vmihailenco/bufpool v0.1.11 h1:gOq2WmBrq0i2yW5QJ16ykccQ4wH9UyEsgLm6czKAd94=
github.com/vmihailenco/bufpool v0.1.11/go.mod h1:AFf/MOy3l2CFTKbxwt0mp2MwnqjNEs5H/UxrkA5jxTQ=
github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc=
github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/dig v1.19.0 h1:BACLhebsYdpQ7IROQ1AGPjrXcP5dF80U3gKoFzbaq/4=
go.uber.org/dig v1.19.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg=
golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/postgres v1.5.4 h1:Iyrp9Meh3GmbSuyIAGyjkN+n9K+GHX9b9MqsTL4EJCo=
gorm.io/driver/postgres v1.5.4/go.mod h1:Bgo89+h0CRcdA33Y6frlaHHVuTdOf87pmyzwW9C/BH0=
gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
mellium.im/sasl v0.3.1 h1:wE0LW6g7U83vhvxjC1IY8DnXM+EU095yeo8XClvCdfo=
mellium.im/sasl v0.3.1/go.mod h1:xm59PUYpZHhgQ9ZqoJ5QaCqzWMi8IeS49dhp6plPCzw=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
================================================
FILE: go-b2b-starter/internal/api/provider.go
================================================
package api
import (
"go.uber.org/dig"
"github.com/moasq/go-b2b-starter/internal/modules/auth"
"github.com/moasq/go-b2b-starter/internal/modules/billing"
"github.com/moasq/go-b2b-starter/internal/modules/cognitive"
"github.com/moasq/go-b2b-starter/internal/modules/documents"
"github.com/moasq/go-b2b-starter/internal/modules/organizations"
server "github.com/moasq/go-b2b-starter/internal/platform/server/domain"
)
// moduleRoutes holds handlers for all API modules
// 1. OrganizationRoutes - Handles organization, account, and member management routes (includes /auth routes)
// 2. RbacRoutes - Handles RBAC role and permission routes
// 3. BillingHandler - Handles billing status and subscription routes (uses billing module)
// 4. DocumentsRoutes - Handles PDF document upload and management routes
// 5. CognitiveRoutes - Handles AI/RAG chat and document search routes
type moduleRoutes struct {
OrganizationRoutes *organizations.Routes
RbacRoutes *auth.Routes
SubscriptionHandler *billing.Handler
DocumentsRoutes *documents.Routes
CognitiveRoutes *cognitive.Routes
}
// Init sets up all module dependencies and registers API routes
func Init(container *dig.Container) error {
if err := setupDependencies(container); err != nil {
return err
}
if err := registerAPI(container); err != nil {
return err
}
return nil
}
// registerAPI registers all module handlers and routes
func registerAPI(container *dig.Container) error {
if err := container.Provide(func(
organizationRoutes *organizations.Routes,
rbacRoutes *auth.Routes,
subscriptionHandler *billing.Handler,
documentsRoutes *documents.Routes,
cognitiveRoutes *cognitive.Routes,
) *moduleRoutes {
return &moduleRoutes{
OrganizationRoutes: organizationRoutes,
RbacRoutes: rbacRoutes,
SubscriptionHandler: subscriptionHandler,
DocumentsRoutes: documentsRoutes,
CognitiveRoutes: cognitiveRoutes,
}
}); err != nil {
return err
}
return container.Invoke(func(
srv server.Server,
modules *moduleRoutes,
) {
// Register each module's routes
srv.RegisterRoutes(modules.OrganizationRoutes.Routes, server.ApiPrefix)
srv.RegisterRoutes(modules.RbacRoutes.Routes, server.ApiPrefix)
srv.RegisterRoutes(modules.SubscriptionHandler.Routes, server.ApiPrefix)
srv.RegisterRoutes(modules.DocumentsRoutes.Routes, server.ApiPrefix)
srv.RegisterRoutes(modules.CognitiveRoutes.Routes, server.ApiPrefix)
})
}
// setupDependencies initializes all module dependencies
func setupDependencies(container *dig.Container) error {
if err := organizations.NewProvider(container).RegisterDependencies(); err != nil {
return err
}
// Initialize RBAC API (role and permission discovery)
if err := auth.NewProvider(container).RegisterDependencies(); err != nil {
return err
}
// Initialize billing API (subscription and billing status)
if err := billing.RegisterHandlers(container); err != nil {
return err
}
// Initialize documents API (PDF upload and management)
if err := documents.NewProvider(container).RegisterDependencies(); err != nil {
return err
}
// Initialize cognitive API (AI/RAG chat and document search)
if err := cognitive.NewProvider(container).RegisterDependencies(); err != nil {
return err
}
return nil
}
================================================
FILE: go-b2b-starter/internal/bootstrap/init_mods.go
================================================
package bootstrap
import (
"context"
"go.uber.org/dig"
"github.com/moasq/go-b2b-starter/internal/api"
"github.com/moasq/go-b2b-starter/internal/modules/auth"
authCmd "github.com/moasq/go-b2b-starter/internal/modules/auth/cmd"
billing "github.com/moasq/go-b2b-starter/internal/modules/billing/cmd"
cognitive "github.com/moasq/go-b2b-starter/internal/modules/cognitive/cmd"
db "github.com/moasq/go-b2b-starter/internal/db/cmd"
docs "github.com/moasq/go-b2b-starter/internal/docs/cmd"
documents "github.com/moasq/go-b2b-starter/internal/modules/documents/cmd"
eventbus "github.com/moasq/go-b2b-starter/internal/platform/eventbus/cmd"
files "github.com/moasq/go-b2b-starter/internal/modules/files/cmd"
llm "github.com/moasq/go-b2b-starter/internal/platform/llm/cmd"
logger "github.com/moasq/go-b2b-starter/internal/platform/logger/cmd"
ocr "github.com/moasq/go-b2b-starter/internal/platform/ocr/cmd"
orgDomain "github.com/moasq/go-b2b-starter/internal/modules/organizations/domain"
organizations "github.com/moasq/go-b2b-starter/internal/modules/organizations/cmd"
paywall "github.com/moasq/go-b2b-starter/internal/modules/paywall/cmd"
polar "github.com/moasq/go-b2b-starter/internal/platform/polar/cmd"
redisCmd "github.com/moasq/go-b2b-starter/internal/platform/redis/cmd"
server "github.com/moasq/go-b2b-starter/internal/platform/server/cmd"
stytchCmd "github.com/moasq/go-b2b-starter/internal/platform/stytch/cmd"
)
// orgLookupAdapter adapts orgDomain.OrganizationRepository to auth.OrganizationLookup
type orgLookupAdapter struct {
repo orgDomain.OrganizationRepository
}
func (a *orgLookupAdapter) GetByStytchID(ctx context.Context, stytchOrgID string) (auth.OrganizationEntity, error) {
return a.repo.GetByStytchID(ctx, stytchOrgID)
}
// accLookupAdapter adapts orgDomain.AccountRepository to auth.AccountLookup
type accLookupAdapter struct {
repo orgDomain.AccountRepository
}
func (a *accLookupAdapter) GetByEmail(ctx context.Context, orgID int32, email string) (auth.AccountEntity, error) {
return a.repo.GetByEmail(ctx, orgID, email)
}
func InitMods(container *dig.Container) {
// pkg
server.Init(container)
logger.Init(container)
db.Init(container)
files.Init(container)
if err := eventbus.Init(container); err != nil {
panic(err)
}
if err := llm.Init(container); err != nil {
panic(err)
}
// Polar package must be initialized before payment module (payment depends on Polar client)
if err := polar.Init(container); err != nil {
panic(err)
}
// Redis must be initialized before auth (Stytch repositories rely on Redis-backed clients upstream)
if err := redisCmd.Init(container); err != nil {
panic(err)
}
// Stytch client package must be initialized before app/auth (for organization/member management)
// This provides: stytch.Config, stytch.Client, stytch.RBACPolicyService
if err := stytchCmd.ProvideStytchDependencies(container); err != nil {
panic(err)
}
// Auth package (pkg/auth) must be initialized before app/auth
// This provides: auth.AuthProvider (authentication/authorization)
if err := authCmd.Init(container); err != nil {
panic(err)
}
// docs
docs.Init(container)
// app
if err := organizations.Init(container); err != nil {
panic(err)
}
// Register auth resolvers (bridges organizations domain to auth package)
if err := auth.ProvideResolvers(container,
func(repo orgDomain.OrganizationRepository) auth.OrganizationResolver {
return auth.NewOrganizationResolver(&orgLookupAdapter{repo: repo})
},
func(repo orgDomain.AccountRepository) auth.AccountResolver {
return auth.NewAccountResolver(&accLookupAdapter{repo: repo})
},
); err != nil {
panic(err)
}
// Initialize auth middleware (requires resolvers to be registered)
if err := authCmd.InitMiddleware(container); err != nil {
panic(err)
}
// Register auth middleware as named middlewares for use in routes
if err := auth.RegisterNamedMiddlewares(container); err != nil {
panic(err)
}
// Billing module (subscription lifecycle, quotas, webhooks)
if err := billing.Init(container); err != nil {
panic(err)
}
// Paywall middleware (access gating based on subscription status)
if err := paywall.SetupMiddleware(container); err != nil {
panic(err)
}
if err := paywall.RegisterNamedMiddlewares(container); err != nil {
panic(err)
}
// OCR service (Mistral API for document text extraction)
// Must be initialized before documents module (documents depends on OCR)
if err := ocr.Init(container); err != nil {
panic(err)
}
// Documents module (PDF upload and text extraction)
if err := documents.Init(container); err != nil {
panic(err)
}
// Cognitive module (AI/RAG with embeddings and vector search)
// Note: This also wires the event listener for DocumentUploaded events
if err := cognitive.Init(container); err != nil {
panic(err)
}
// api
api.Init(container)
}
================================================
FILE: go-b2b-starter/internal/bootstrap/root.go
================================================
package bootstrap
import (
"log"
"github.com/joho/godotenv"
"go.uber.org/dig"
server "github.com/moasq/go-b2b-starter/internal/platform/server/domain"
)
func Execute() {
if err := godotenv.Load("app.env"); err != nil {
log.Printf("Warning: Error loading app.env file: %v", err)
}
container := dig.New()
InitMods(container)
var srv server.Server
if err := container.Invoke(func(s server.Server) {
srv = s
}); err != nil {
panic(err)
}
srv.Start()
}
================================================
FILE: go-b2b-starter/internal/db/README.md
================================================
# Database Layer Guide
This guide shows you how to work with the database layer using our adapter pattern. It's designed to be simple and practical.
## What's the Adapter Pattern?
We keep database code separate from business logic:
- **`adapters/`** - Interface definitions (what operations are available)
- **`postgres/adapter_impl/`** - Actual database code (how PostgreSQL does it)
Your business modules only need to know about `adapters/`. They never touch PostgreSQL directly.
## The Workflow
Here's the typical flow when you need to add something to the database:
### 1. Create a Database Migration
Use the Makefile to create migration files:
```bash
make create-migration MIGRATION_NAME=add_users_table
```
This creates two files in `postgres/sqlc/migrations/`:
- `000XXX_add_users_table.up.sql` (creates your changes)
- `000XXX_add_users_table.down.sql` (removes your changes)
Write your SQL in these files. Keep it simple.
### 2. Apply Your Migration
Run the migration to update your database:
```bash
make migrateup
```
If something goes wrong, you can rollback:
```bash
make migratedown
```
### 3. Write SQL Queries
Create a file in `postgres/sqlc/query/` with your queries. Use SQLC's comments to tell it what to generate:
```sql
-- name: GetUserByID :one
SELECT * FROM users WHERE id = $1;
-- name: CreateUser :one
INSERT INTO users (email, name) VALUES ($1, $2) RETURNING *;
-- name: UpdateUserBalance :exec
UPDATE users SET balance = balance + $1 WHERE id = $2;
```
The comment annotations tell SQLC what kind of method to create (`:one` returns single row, `:many` returns multiple, `:exec` runs without returning).
### 4. Generate Go
gitextract__wbx865y/ ├── .editorconfig ├── .gitignore ├── CLAUDE.md ├── Caddyfile ├── DEVELOPMENT.md ├── LICENSE ├── README.md ├── SECURITY.md ├── SETUP.md ├── docker-compose.production.yml ├── go-b2b-starter/ │ ├── .air.toml │ ├── .claude/ │ │ └── CLAUDE.md │ ├── .dockerignore │ ├── .gitignore │ ├── .gitlab-ci.yml │ ├── Dockerfile │ ├── Makefile │ ├── README.md │ ├── cmd/ │ │ └── api/ │ │ └── main.go │ ├── deps/ │ │ ├── Dockerfile │ │ └── docker-compose.yml │ ├── docs/ │ │ ├── README.md │ │ ├── adding-a-module.md │ │ ├── api-development.md │ │ ├── architecture.md │ │ ├── authentication.md │ │ ├── billing.md │ │ ├── database.md │ │ ├── event-bus.md │ │ └── file-manager.md │ ├── example.env │ ├── go.mod │ ├── go.sum │ ├── internal/ │ │ ├── api/ │ │ │ └── provider.go │ │ ├── bootstrap/ │ │ │ ├── init_mods.go │ │ │ └── root.go │ │ ├── db/ │ │ │ ├── README.md │ │ │ ├── adapters/ │ │ │ │ ├── cognitive_store.go │ │ │ │ ├── document_store.go │ │ │ │ ├── file_asset_store.go │ │ │ │ ├── organization_store.go │ │ │ │ └── subscription_store.go │ │ │ ├── cmd/ │ │ │ │ ├── init.go │ │ │ │ └── providers.go │ │ │ ├── core/ │ │ │ │ ├── connection.go │ │ │ │ ├── errors.go │ │ │ │ └── transaction.go │ │ │ ├── helpers/ │ │ │ │ └── helpers.go │ │ │ ├── inject.go │ │ │ └── postgres/ │ │ │ ├── adapter_impl/ │ │ │ │ ├── cognitive_store.go │ │ │ │ ├── document_store.go │ │ │ │ ├── file_asset_store.go │ │ │ │ ├── organization_store.go │ │ │ │ └── subscription_store.go │ │ │ ├── connection.go │ │ │ ├── db_config.go │ │ │ ├── init.go │ │ │ ├── postgres_manager.go │ │ │ ├── retry.go │ │ │ ├── sqlc/ │ │ │ │ ├── gen/ │ │ │ │ │ ├── cognitive.sql.go │ │ │ │ │ ├── db.go │ │ │ │ │ ├── documents.sql.go │ │ │ │ │ ├── error.go │ │ │ │ │ ├── example_resource.sql.go │ │ │ │ │ ├── exec.go │ │ │ │ │ ├── file_manager.sql.go │ │ │ │ │ ├── models.go │ │ │ │ │ ├── organizations.sql.go │ │ │ │ │ ├── querier.go │ │ │ │ │ ├── resource_embeddings.sql.go │ │ │ │ │ ├── store.go │ │ │ │ │ └── subscription_billing.sql.go │ │ │ │ ├── migrations/ │ │ │ │ │ ├── 000001_create_file_manager_schema.down.sql │ │ │ │ │ ├── 000001_create_file_manager_schema.up.sql │ │ │ │ │ ├── 000002_create_organizations_schema.down.sql │ │ │ │ │ ├── 000002_create_organizations_schema.up.sql │ │ │ │ │ ├── 000003_enforce_role_enum.down.sql │ │ │ │ │ ├── 000003_enforce_role_enum.up.sql │ │ │ │ │ ├── 000004_create_subscription_billing_schema.down.sql │ │ │ │ │ ├── 000004_create_subscription_billing_schema.up.sql │ │ │ │ │ ├── 000005_update_quota_tracking_schema.down.sql │ │ │ │ │ ├── 000005_update_quota_tracking_schema.up.sql │ │ │ │ │ ├── 000006_create_example_resources.down.sql │ │ │ │ │ ├── 000006_create_example_resources.up.sql │ │ │ │ │ ├── 000007_create_resource_embeddings.down.sql │ │ │ │ │ ├── 000007_create_resource_embeddings.up.sql │ │ │ │ │ ├── 000008_create_documents_schema.down.sql │ │ │ │ │ ├── 000008_create_documents_schema.up.sql │ │ │ │ │ ├── 000009_create_cognitive_schema.down.sql │ │ │ │ │ └── 000009_create_cognitive_schema.up.sql │ │ │ │ ├── query/ │ │ │ │ │ ├── cognitive.sql │ │ │ │ │ ├── documents.sql │ │ │ │ │ ├── example_resource.sql │ │ │ │ │ ├── file_manager.sql │ │ │ │ │ ├── organizations.sql │ │ │ │ │ └── subscription_billing.sql │ │ │ │ └── sqlc.yml │ │ │ └── types_transform.go │ │ ├── docs/ │ │ │ ├── api/ │ │ │ │ ├── handler.go │ │ │ │ └── routes.go │ │ │ ├── cmd/ │ │ │ │ └── init.go │ │ │ └── gen/ │ │ │ ├── docs.go │ │ │ ├── swagger.json │ │ │ └── swagger.yaml │ │ ├── modules/ │ │ │ ├── auth/ │ │ │ │ ├── README.md │ │ │ │ ├── adapters/ │ │ │ │ │ └── stytch/ │ │ │ │ │ ├── adapter.go │ │ │ │ │ ├── config.go │ │ │ │ │ ├── jwks_cache.go │ │ │ │ │ ├── jwt_parser.go │ │ │ │ │ ├── mock_adapter.go │ │ │ │ │ ├── rbac_policy.go │ │ │ │ │ └── token_verifier.go │ │ │ │ ├── auth.go │ │ │ │ ├── cmd/ │ │ │ │ │ └── init.go │ │ │ │ ├── context.go │ │ │ │ ├── errors.go │ │ │ │ ├── handler.go │ │ │ │ ├── middleware.go │ │ │ │ ├── permissions.go │ │ │ │ ├── provider.go │ │ │ │ ├── rbac.go │ │ │ │ ├── resolvers.go │ │ │ │ ├── roles.go │ │ │ │ └── routes.go │ │ │ ├── billing/ │ │ │ │ ├── README.md │ │ │ │ ├── app/ │ │ │ │ │ └── services/ │ │ │ │ │ ├── check_quota_availability_service.go │ │ │ │ │ ├── consume_invoice_quota_service.go │ │ │ │ │ ├── get_billing_status_service.go │ │ │ │ │ ├── module.go │ │ │ │ │ ├── process_webhook_event_service.go │ │ │ │ │ ├── refresh_subscription_status_service.go │ │ │ │ │ ├── subscription_service_dec.go │ │ │ │ │ ├── sync_subscription_service.go │ │ │ │ │ ├── verify_and_consume_quota_service.go │ │ │ │ │ └── verify_payment_service.go │ │ │ │ ├── cmd/ │ │ │ │ │ ├── init.go │ │ │ │ │ └── provider.go │ │ │ │ ├── domain/ │ │ │ │ │ ├── errors.go │ │ │ │ │ ├── repository.go │ │ │ │ │ └── types.go │ │ │ │ ├── handler.go │ │ │ │ ├── infra/ │ │ │ │ │ ├── adapters/ │ │ │ │ │ │ └── status_provider.go │ │ │ │ │ ├── polar/ │ │ │ │ │ │ └── polar_adapter.go │ │ │ │ │ └── repositories/ │ │ │ │ │ ├── organization_adapter.go │ │ │ │ │ └── subscription_repository.go │ │ │ │ ├── provider.go │ │ │ │ └── routes.go │ │ │ ├── cognitive/ │ │ │ │ ├── app/ │ │ │ │ │ └── services/ │ │ │ │ │ ├── document_listener.go │ │ │ │ │ ├── embedding_service.go │ │ │ │ │ ├── interface.go │ │ │ │ │ └── rag_service.go │ │ │ │ ├── cmd/ │ │ │ │ │ └── init.go │ │ │ │ ├── domain/ │ │ │ │ │ ├── ai_provider.go │ │ │ │ │ ├── entity.go │ │ │ │ │ ├── errors.go │ │ │ │ │ └── repository.go │ │ │ │ ├── handler.go │ │ │ │ ├── infra/ │ │ │ │ │ ├── ai/ │ │ │ │ │ │ ├── assistant_provider.go │ │ │ │ │ │ └── text_vectorizer.go │ │ │ │ │ └── repositories/ │ │ │ │ │ ├── chat_repository.go │ │ │ │ │ ├── embedding_repository.go │ │ │ │ │ └── helpers.go │ │ │ │ ├── module.go │ │ │ │ ├── provider.go │ │ │ │ └── routes.go │ │ │ ├── documents/ │ │ │ │ ├── app/ │ │ │ │ │ └── services/ │ │ │ │ │ ├── document_service.go │ │ │ │ │ └── interface.go │ │ │ │ ├── cmd/ │ │ │ │ │ └── init.go │ │ │ │ ├── domain/ │ │ │ │ │ ├── entity.go │ │ │ │ │ ├── errors.go │ │ │ │ │ ├── events/ │ │ │ │ │ │ └── document_events.go │ │ │ │ │ └── repository.go │ │ │ │ ├── handler.go │ │ │ │ ├── infra/ │ │ │ │ │ └── repositories/ │ │ │ │ │ └── document_repository.go │ │ │ │ ├── module.go │ │ │ │ ├── provider.go │ │ │ │ └── routes.go │ │ │ ├── files/ │ │ │ │ ├── README.md │ │ │ │ ├── cmd/ │ │ │ │ │ ├── init.go │ │ │ │ │ └── provider.go │ │ │ │ ├── config/ │ │ │ │ │ └── config.go │ │ │ │ ├── constants.go │ │ │ │ ├── domain/ │ │ │ │ │ ├── entity.go │ │ │ │ │ ├── helpers.go │ │ │ │ │ ├── repository.go │ │ │ │ │ ├── service.go │ │ │ │ │ └── validator.go │ │ │ │ ├── infra/ │ │ │ │ │ └── file_metadata_repository.go │ │ │ │ └── internal/ │ │ │ │ └── infra/ │ │ │ │ ├── composite_repository.go │ │ │ │ ├── db_repository.go │ │ │ │ ├── mock_r2_repository.go │ │ │ │ └── r2_repository.go │ │ │ ├── organizations/ │ │ │ │ ├── account_handler.go │ │ │ │ ├── app/ │ │ │ │ │ └── services/ │ │ │ │ │ ├── member_service.go │ │ │ │ │ ├── member_service_impl.go │ │ │ │ │ ├── organization_service.go │ │ │ │ │ └── organization_service_interface.go │ │ │ │ ├── cmd/ │ │ │ │ │ └── init.go │ │ │ │ ├── domain/ │ │ │ │ │ ├── auth_provider.go │ │ │ │ │ ├── entity.go │ │ │ │ │ ├── errors.go │ │ │ │ │ ├── events/ │ │ │ │ │ │ └── organization_events.go │ │ │ │ │ └── repository.go │ │ │ │ ├── infra/ │ │ │ │ │ └── repositories/ │ │ │ │ │ ├── account_repository.go │ │ │ │ │ ├── organization_repository.go │ │ │ │ │ ├── slug_generator.go │ │ │ │ │ ├── stytch_member_repository.go │ │ │ │ │ ├── stytch_organization_repository.go │ │ │ │ │ └── stytch_role_repository.go │ │ │ │ ├── member_handler.go │ │ │ │ ├── module.go │ │ │ │ ├── organization_handler.go │ │ │ │ ├── provider.go │ │ │ │ └── routes.go │ │ │ └── paywall/ │ │ │ ├── README.md │ │ │ ├── cmd/ │ │ │ │ └── init.go │ │ │ ├── context.go │ │ │ ├── errors.go │ │ │ ├── middleware.go │ │ │ ├── provider.go │ │ │ └── subscription.go │ │ └── platform/ │ │ ├── eventbus/ │ │ │ ├── bus.go │ │ │ ├── cmd/ │ │ │ │ ├── init.go │ │ │ │ └── provider.go │ │ │ ├── event.go │ │ │ ├── events.go │ │ │ └── middleware.go │ │ ├── llm/ │ │ │ ├── README.md │ │ │ ├── cmd/ │ │ │ │ └── init.go │ │ │ ├── domain/ │ │ │ │ ├── errors.go │ │ │ │ └── service.go │ │ │ └── infra/ │ │ │ └── openai_client.go │ │ ├── logger/ │ │ │ ├── cmd/ │ │ │ │ ├── init.go │ │ │ │ └── provider.go │ │ │ ├── domain/ │ │ │ │ ├── logger.go │ │ │ │ └── options.go │ │ │ ├── factory.go │ │ │ └── internal/ │ │ │ └── zerologger/ │ │ │ ├── factory.go │ │ │ └── logger.go │ │ ├── ocr/ │ │ │ ├── README.md │ │ │ ├── cmd/ │ │ │ │ └── init.go │ │ │ ├── domain/ │ │ │ │ ├── entity.go │ │ │ │ ├── errors.go │ │ │ │ └── service.go │ │ │ └── infra/ │ │ │ ├── config.go │ │ │ ├── mistral_ocr_client.go │ │ │ └── mock_ocr_client.go │ │ ├── polar/ │ │ │ ├── client.go │ │ │ ├── cmd/ │ │ │ │ └── init.go │ │ │ ├── config.go │ │ │ ├── inject.go │ │ │ └── webhook.go │ │ ├── redis/ │ │ │ ├── README.md │ │ │ ├── cmd/ │ │ │ │ ├── init.go │ │ │ │ └── provider.go │ │ │ ├── config.go │ │ │ ├── init.go │ │ │ ├── redis.go │ │ │ └── store.go │ │ ├── server/ │ │ │ ├── cmd/ │ │ │ │ ├── di.go │ │ │ │ └── init.go │ │ │ ├── config/ │ │ │ │ └── config.go │ │ │ ├── domain/ │ │ │ │ ├── health.go │ │ │ │ ├── http_server.go │ │ │ │ ├── middleware.go │ │ │ │ ├── middleware_resolver.go │ │ │ │ ├── server.go │ │ │ │ └── server_.go │ │ │ ├── errors/ │ │ │ │ └── errors.go │ │ │ ├── gin/ │ │ │ │ └── gin.go │ │ │ ├── logging/ │ │ │ │ ├── logger.go │ │ │ │ └── security_logger.go │ │ │ ├── metrics/ │ │ │ │ └── prometheus.go │ │ │ └── middleware/ │ │ │ ├── cors.go │ │ │ ├── ip_protection.go │ │ │ ├── ratelimit.go │ │ │ ├── recovery.go │ │ │ ├── request_id.go │ │ │ ├── request_size_limit.go │ │ │ ├── sanatization.go │ │ │ ├── security_headers.go │ │ │ ├── timeout.go │ │ │ └── validator.go │ │ └── stytch/ │ │ ├── client.go │ │ ├── cmd/ │ │ │ └── provider.go │ │ ├── config.go │ │ ├── errors.go │ │ ├── inject.go │ │ └── rbac_policy.go │ ├── pkg/ │ │ ├── httperr/ │ │ │ ├── errors.go │ │ │ └── http_error.go │ │ ├── pagination/ │ │ │ ├── pagination.go │ │ │ ├── pramas.go │ │ │ └── util.go │ │ ├── response/ │ │ │ └── response.go │ │ └── slugify/ │ │ └── slugify.go │ └── scripts/ │ ├── migrate_down.sh │ ├── migrate_up.sh │ └── run_tests_with_coverage.sh ├── next_b2b_starter/ │ ├── .claude/ │ │ └── CLAUDE.md │ ├── .dockerignore │ ├── .env.example │ ├── .eslintrc.json │ ├── .npmrc │ ├── Dockerfile │ ├── README.md │ ├── STYTCH_CONFIGURATION.md │ ├── app/ │ │ ├── api/ │ │ │ ├── auth/ │ │ │ │ └── session/ │ │ │ │ └── refresh/ │ │ │ │ └── route.ts │ │ │ └── billing/ │ │ │ └── webhook/ │ │ │ └── route.ts │ │ ├── auth/ │ │ │ └── page.tsx │ │ ├── authenticate/ │ │ │ └── page.tsx │ │ ├── dashboard/ │ │ │ ├── knowledge/ │ │ │ │ ├── components/ │ │ │ │ │ ├── chat-interface.tsx │ │ │ │ │ ├── chat-message.tsx │ │ │ │ │ ├── document-list.tsx │ │ │ │ │ ├── document-sources.tsx │ │ │ │ │ ├── document-upload.tsx │ │ │ │ │ ├── knowledge-content.tsx │ │ │ │ │ └── knowledge-sidebar.tsx │ │ │ │ ├── layout.tsx │ │ │ │ └── page.tsx │ │ │ ├── layout.tsx │ │ │ ├── page.tsx │ │ │ └── settings/ │ │ │ ├── components/ │ │ │ │ ├── invite-member.tsx │ │ │ │ ├── member-list.tsx │ │ │ │ ├── profile-section.tsx │ │ │ │ ├── profile-tab.tsx │ │ │ │ ├── settings-content.tsx │ │ │ │ └── subscription-tab.tsx │ │ │ ├── layout.tsx │ │ │ └── page.tsx │ │ ├── globals.css │ │ ├── head.tsx │ │ ├── layout.tsx │ │ ├── not-found.tsx │ │ ├── page.tsx │ │ ├── robots.ts │ │ ├── signup/ │ │ │ └── page.tsx │ │ └── sitemap.ts │ ├── components/ │ │ ├── auth/ │ │ │ ├── can.tsx │ │ │ ├── permission-gate.tsx │ │ │ └── stytch-provider.tsx │ │ ├── billing/ │ │ │ ├── plans-modal.tsx │ │ │ ├── subscription-alerts.tsx │ │ │ └── subscription-paywall.tsx │ │ ├── common/ │ │ │ └── obfuscated-email.tsx │ │ ├── layout/ │ │ │ ├── dashboard-layout.tsx │ │ │ ├── header.tsx │ │ │ ├── sidebar.tsx │ │ │ └── user-menu.tsx │ │ ├── seo/ │ │ │ └── jsonld.tsx │ │ └── ui/ │ │ ├── accordion.tsx │ │ ├── alert.tsx │ │ ├── avatar.tsx │ │ ├── badge.tsx │ │ ├── button.tsx │ │ ├── calendar.tsx │ │ ├── card.tsx │ │ ├── checkbox.tsx │ │ ├── date-picker.tsx │ │ ├── dialog.tsx │ │ ├── dropdown-menu.tsx │ │ ├── form.tsx │ │ ├── input.tsx │ │ ├── label.tsx │ │ ├── popover.tsx │ │ ├── progress.tsx │ │ ├── scroll-area.tsx │ │ ├── select.tsx │ │ ├── separator.tsx │ │ ├── sheet-header.tsx │ │ ├── sheet.tsx │ │ ├── skeleton.tsx │ │ ├── slider.tsx │ │ ├── switch.tsx │ │ ├── table.tsx │ │ ├── tabs.tsx │ │ └── textarea.tsx │ ├── components.json │ ├── docs/ │ │ ├── 01-getting-started.md │ │ ├── 02-authentication.md │ │ ├── 03-permissions-and-roles.md │ │ ├── 04-payments-and-billing.md │ │ ├── 05-making-api-requests.md │ │ ├── 06-creating-pages.md │ │ ├── 07-creating-apis.md │ │ ├── 08-using-hooks.md │ │ ├── 09-adding-a-feature.md │ │ ├── 10-server-actions.md │ │ ├── 11-feature-guards.md │ │ ├── 12-subscription-patterns.md │ │ ├── API-LOGGING.md │ │ └── README.md │ ├── hooks/ │ │ ├── use-signup-flow.ts │ │ └── use-toast.ts │ ├── lib/ │ │ ├── actions/ │ │ │ ├── auth/ │ │ │ │ ├── consume-magic-link.ts │ │ │ │ ├── logout.ts │ │ │ │ └── send-magic-link.ts │ │ │ └── billing/ │ │ │ ├── cancel-subscription.ts │ │ │ ├── create-checkout.ts │ │ │ ├── get-products.ts │ │ │ ├── get-subscription-status.ts │ │ │ └── verify-payment.ts │ │ ├── api/ │ │ │ └── api/ │ │ │ ├── client/ │ │ │ │ └── api-client.ts │ │ │ ├── dto/ │ │ │ │ ├── auth.dto.ts │ │ │ │ ├── cognitive.dto.ts │ │ │ │ ├── document.dto.ts │ │ │ │ ├── member.dto.ts │ │ │ │ ├── organization.dto.ts │ │ │ │ ├── profile.dto.ts │ │ │ │ └── rbac.dto.ts │ │ │ └── repositories/ │ │ │ ├── cognitive-repository.ts │ │ │ ├── document-repository.ts │ │ │ ├── member-repository.ts │ │ │ ├── profile-repository.ts │ │ │ ├── rbac-repository.ts │ │ │ └── signup-repository.ts │ │ ├── auth/ │ │ │ ├── README.md │ │ │ ├── bootstrap.ts │ │ │ ├── config-types.ts │ │ │ ├── constants.ts │ │ │ ├── permission-utils.ts │ │ │ ├── permissions.ts │ │ │ ├── server-constants.ts │ │ │ ├── server-permissions.ts │ │ │ ├── stytch/ │ │ │ │ └── server.ts │ │ │ ├── stytch-client.ts │ │ │ ├── stytch-server.ts │ │ │ ├── stytch.ts │ │ │ ├── subscription.ts │ │ │ └── token-utils.ts │ │ ├── contexts/ │ │ │ ├── auth-context.tsx │ │ │ └── stytch-config-context.tsx │ │ ├── hooks/ │ │ │ ├── mutations/ │ │ │ │ ├── use-chat.ts │ │ │ │ ├── use-delete-document.ts │ │ │ │ ├── use-invite-member.ts │ │ │ │ ├── use-remove-member.ts │ │ │ │ ├── use-resend-invitation.ts │ │ │ │ ├── use-update-profile.ts │ │ │ │ └── use-upload-document.ts │ │ │ ├── queries/ │ │ │ │ ├── query-keys.ts │ │ │ │ ├── use-documents-query.ts │ │ │ │ ├── use-members-query.ts │ │ │ │ ├── use-products-query.ts │ │ │ │ ├── use-profile-query.ts │ │ │ │ ├── use-sessions-query.ts │ │ │ │ └── use-subscription-query.ts │ │ │ └── use-permissions.ts │ │ ├── models/ │ │ │ ├── cognitive.model.ts │ │ │ ├── document.model.ts │ │ │ ├── member.model.ts │ │ │ └── signup.model.ts │ │ ├── polar/ │ │ │ ├── client.ts │ │ │ ├── config.ts │ │ │ ├── current-subscription.ts │ │ │ ├── plans.ts │ │ │ ├── server-meters.ts │ │ │ ├── server-products.ts │ │ │ ├── subscription.ts │ │ │ └── usage.ts │ │ ├── providers/ │ │ │ └── query-provider.tsx │ │ ├── stores/ │ │ │ └── sidebar-store.ts │ │ ├── types/ │ │ │ └── loadable.ts │ │ ├── utils/ │ │ │ ├── api-logger.ts │ │ │ ├── password-generator.ts │ │ │ └── server-action-helpers.ts │ │ └── utils.ts │ ├── lint/ │ │ └── README.md │ ├── next-env.d.ts │ ├── next.config.ts │ ├── package.json │ ├── postcss.config.js │ ├── proxy.ts │ ├── scripts/ │ │ ├── convert-svg-to-png.js │ │ ├── generate-favicons.js │ │ └── generate-og-images.js │ ├── stores/ │ │ └── ui-store.ts │ ├── tailwind.config.ts │ └── tsconfig.json └── setup.sh
Showing preview only (220K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2205 symbols across 361 files)
FILE: go-b2b-starter/cmd/api/main.go
function main (line 26) | func main() {
FILE: go-b2b-starter/internal/api/provider.go
type moduleRoutes (line 20) | type moduleRoutes struct
function Init (line 29) | func Init(container *dig.Container) error {
function registerAPI (line 41) | func registerAPI(container *dig.Container) error {
function setupDependencies (line 74) | func setupDependencies(container *dig.Container) error {
FILE: go-b2b-starter/internal/bootstrap/init_mods.go
type orgLookupAdapter (line 31) | type orgLookupAdapter struct
method GetByStytchID (line 35) | func (a *orgLookupAdapter) GetByStytchID(ctx context.Context, stytchOr...
type accLookupAdapter (line 40) | type accLookupAdapter struct
method GetByEmail (line 44) | func (a *accLookupAdapter) GetByEmail(ctx context.Context, orgID int32...
function InitMods (line 48) | func InitMods(container *dig.Container) {
FILE: go-b2b-starter/internal/bootstrap/root.go
function Execute (line 12) | func Execute() {
FILE: go-b2b-starter/internal/db/adapters/cognitive_store.go
type EmbeddingStore (line 11) | type EmbeddingStore interface
type ChatStore (line 21) | type ChatStore interface
type VectorHelper (line 38) | type VectorHelper interface
FILE: go-b2b-starter/internal/db/adapters/document_store.go
type DocumentStore (line 10) | type DocumentStore interface
FILE: go-b2b-starter/internal/db/adapters/file_asset_store.go
type FileAssetStore (line 11) | type FileAssetStore interface
FILE: go-b2b-starter/internal/db/adapters/organization_store.go
type OrganizationStore (line 11) | type OrganizationStore interface
type AccountStore (line 25) | type AccountStore interface
FILE: go-b2b-starter/internal/db/adapters/subscription_store.go
type SubscriptionStore (line 10) | type SubscriptionStore interface
FILE: go-b2b-starter/internal/db/cmd/init.go
function Init (line 7) | func Init(container *dig.Container) {
FILE: go-b2b-starter/internal/db/cmd/providers.go
function ProvideDependencies (line 9) | func ProvideDependencies(container *dig.Container) error {
function ProvideDependenciesWithOptions (line 15) | func ProvideDependenciesWithOptions(container *dig.Container, opts db.In...
FILE: go-b2b-starter/internal/db/core/connection.go
type Connection (line 9) | type Connection interface
type Pool (line 30) | type Pool interface
type PoolStats (line 47) | type PoolStats struct
type Rows (line 55) | type Rows interface
type Row (line 70) | type Row interface
FILE: go-b2b-starter/internal/db/core/errors.go
type ErrTxRollbackFailed (line 27) | type ErrTxRollbackFailed struct
method Error (line 32) | func (e ErrTxRollbackFailed) Error() string {
method Unwrap (line 36) | func (e ErrTxRollbackFailed) Unwrap() error {
type ErrTxCommitFailed (line 41) | type ErrTxCommitFailed struct
method Error (line 45) | func (e ErrTxCommitFailed) Error() string {
method Unwrap (line 49) | func (e ErrTxCommitFailed) Unwrap() error {
type ErrConstraintViolation (line 54) | type ErrConstraintViolation struct
method Error (line 59) | func (e ErrConstraintViolation) Error() string {
function IsNoRowsError (line 64) | func IsNoRowsError(err error) bool {
function IsConstraintError (line 69) | func IsConstraintError(err error) bool {
function IsTimeoutError (line 75) | func IsTimeoutError(err error) bool {
FILE: go-b2b-starter/internal/db/core/transaction.go
type Transaction (line 6) | type Transaction interface
type TxFunc (line 17) | type TxFunc
function WithTransaction (line 21) | func WithTransaction(ctx context.Context, pool Pool, fn TxFunc) error {
FILE: go-b2b-starter/internal/db/helpers/helpers.go
function ToPgText (line 14) | func ToPgText(s string) pgtype.Text {
function FromPgText (line 22) | func FromPgText(t pgtype.Text) string {
function ToPgInt4 (line 30) | func ToPgInt4(i int32) pgtype.Int4 {
function ToPgInt4Ptr (line 35) | func ToPgInt4Ptr(i *int32) pgtype.Int4 {
function FromPgInt4 (line 43) | func FromPgInt4(i pgtype.Int4) int32 {
function ToPgBool (line 51) | func ToPgBool(b bool) pgtype.Bool {
function ToPgBoolPtr (line 56) | func ToPgBoolPtr(b *bool) pgtype.Bool {
function FromPgBool (line 64) | func FromPgBool(b pgtype.Bool) bool {
function ToJSONB (line 72) | func ToJSONB(m map[string]any) []byte {
function FromJSONB (line 84) | func FromJSONB(b []byte) map[string]any {
function ToVector (line 96) | func ToVector(embedding []float64) pgvector.Vector {
function FromVector (line 106) | func FromVector(v pgvector.Vector) []float64 {
FILE: go-b2b-starter/internal/db/inject.go
function Inject (line 34) | func Inject(container *dig.Container) error {
function provideDBPool (line 69) | func provideDBPool(config postgres.Config) (*pgxpool.Pool, error) {
function provideSQLCStore (line 74) | func provideSQLCStore(pool *pgxpool.Pool) sqlc.Store {
function provideSQLDB (line 79) | func provideSQLDB(pool *pgxpool.Pool) *sql.DB {
function provideDBManager (line 86) | func provideDBManager(config postgres.Config, pool *pgxpool.Pool) *postg...
function registerDomainStores (line 92) | func registerDomainStores(container *dig.Container) error {
type InjectOptions (line 205) | type InjectOptions struct
function InjectWithOptions (line 214) | func InjectWithOptions(container *dig.Container, opts InjectOptions) err...
FILE: go-b2b-starter/internal/db/postgres/adapter_impl/cognitive_store.go
type embeddingStore (line 11) | type embeddingStore struct
method CreateDocumentEmbedding (line 19) | func (s *embeddingStore) CreateDocumentEmbedding(ctx context.Context, ...
method GetDocumentEmbeddingByID (line 23) | func (s *embeddingStore) GetDocumentEmbeddingByID(ctx context.Context,...
method GetDocumentEmbeddingsByDocumentID (line 27) | func (s *embeddingStore) GetDocumentEmbeddingsByDocumentID(ctx context...
method SearchSimilarDocuments (line 31) | func (s *embeddingStore) SearchSimilarDocuments(ctx context.Context, a...
method DeleteDocumentEmbeddings (line 35) | func (s *embeddingStore) DeleteDocumentEmbeddings(ctx context.Context,...
method CountDocumentEmbeddingsByOrganization (line 39) | func (s *embeddingStore) CountDocumentEmbeddingsByOrganization(ctx con...
function NewEmbeddingStore (line 15) | func NewEmbeddingStore(store sqlc.Store) adapters.EmbeddingStore {
type chatStore (line 44) | type chatStore struct
method CreateChatSession (line 54) | func (s *chatStore) CreateChatSession(ctx context.Context, arg sqlc.Cr...
method GetChatSessionByID (line 58) | func (s *chatStore) GetChatSessionByID(ctx context.Context, arg sqlc.G...
method ListChatSessionsByAccount (line 62) | func (s *chatStore) ListChatSessionsByAccount(ctx context.Context, arg...
method UpdateChatSessionTitle (line 66) | func (s *chatStore) UpdateChatSessionTitle(ctx context.Context, arg sq...
method DeleteChatSession (line 70) | func (s *chatStore) DeleteChatSession(ctx context.Context, arg sqlc.De...
method CreateChatMessage (line 76) | func (s *chatStore) CreateChatMessage(ctx context.Context, arg sqlc.Cr...
method GetChatMessagesBySession (line 80) | func (s *chatStore) GetChatMessagesBySession(ctx context.Context, sess...
method GetRecentChatMessages (line 84) | func (s *chatStore) GetRecentChatMessages(ctx context.Context, arg sql...
method CountChatMessagesBySession (line 88) | func (s *chatStore) CountChatMessagesBySession(ctx context.Context, se...
method DeleteChatMessage (line 92) | func (s *chatStore) DeleteChatMessage(ctx context.Context, id int32) e...
function NewChatStore (line 48) | func NewChatStore(store sqlc.Store) adapters.ChatStore {
FILE: go-b2b-starter/internal/db/postgres/adapter_impl/document_store.go
type documentStore (line 11) | type documentStore struct
method CreateDocument (line 19) | func (s *documentStore) CreateDocument(ctx context.Context, arg sqlc.C...
method GetDocumentByID (line 23) | func (s *documentStore) GetDocumentByID(ctx context.Context, arg sqlc....
method GetDocumentByFileAssetID (line 27) | func (s *documentStore) GetDocumentByFileAssetID(ctx context.Context, ...
method ListDocumentsByOrganization (line 31) | func (s *documentStore) ListDocumentsByOrganization(ctx context.Contex...
method ListDocumentsByStatus (line 35) | func (s *documentStore) ListDocumentsByStatus(ctx context.Context, arg...
method UpdateDocumentStatus (line 39) | func (s *documentStore) UpdateDocumentStatus(ctx context.Context, arg ...
method UpdateDocumentExtractedText (line 43) | func (s *documentStore) UpdateDocumentExtractedText(ctx context.Contex...
method UpdateDocument (line 47) | func (s *documentStore) UpdateDocument(ctx context.Context, arg sqlc.U...
method DeleteDocument (line 51) | func (s *documentStore) DeleteDocument(ctx context.Context, arg sqlc.D...
method CountDocumentsByOrganization (line 55) | func (s *documentStore) CountDocumentsByOrganization(ctx context.Conte...
method CountDocumentsByStatus (line 59) | func (s *documentStore) CountDocumentsByStatus(ctx context.Context, ar...
function NewDocumentStore (line 15) | func NewDocumentStore(store sqlc.Store) adapters.DocumentStore {
FILE: go-b2b-starter/internal/db/postgres/adapter_impl/file_asset_store.go
type fileAssetStore (line 12) | type fileAssetStore struct
method CreateFileAsset (line 23) | func (f *fileAssetStore) CreateFileAsset(ctx context.Context, arg sqlc...
method GetFileAssetByID (line 27) | func (f *fileAssetStore) GetFileAssetByID(ctx context.Context, id int3...
method DeleteFileAsset (line 31) | func (f *fileAssetStore) DeleteFileAsset(ctx context.Context, id int32...
method GetFileAssetsByEntity (line 35) | func (f *fileAssetStore) GetFileAssetsByEntity(ctx context.Context, ar...
method GetFileAssetsByEntityAndPurpose (line 39) | func (f *fileAssetStore) GetFileAssetsByEntityAndPurpose(ctx context.C...
method GetFileAssetsByCategory (line 44) | func (f *fileAssetStore) GetFileAssetsByCategory(ctx context.Context, ...
method GetFileAssetsByContext (line 48) | func (f *fileAssetStore) GetFileAssetsByContext(ctx context.Context, c...
method UpdateFileAsset (line 53) | func (f *fileAssetStore) UpdateFileAsset(ctx context.Context, arg sqlc...
method GetFileAssetByStoragePath (line 58) | func (f *fileAssetStore) GetFileAssetByStoragePath(ctx context.Context...
method ListFileAssets (line 62) | func (f *fileAssetStore) ListFileAssets(ctx context.Context, arg sqlc....
method GetFileCategories (line 67) | func (f *fileAssetStore) GetFileCategories(ctx context.Context) ([]sql...
method GetFileContexts (line 71) | func (f *fileAssetStore) GetFileContexts(ctx context.Context) ([]sqlc....
function NewFileAssetStore (line 16) | func NewFileAssetStore(store sqlc.Store) adapters.FileAssetStore {
FILE: go-b2b-starter/internal/db/postgres/adapter_impl/organization_store.go
type organizationStore (line 12) | type organizationStore struct
method GetOrganizationByID (line 20) | func (s *organizationStore) GetOrganizationByID(ctx context.Context, i...
method GetOrganizationBySlug (line 24) | func (s *organizationStore) GetOrganizationBySlug(ctx context.Context,...
method GetOrganizationByStytchID (line 28) | func (s *organizationStore) GetOrganizationByStytchID(ctx context.Cont...
method GetOrganizationByUserEmail (line 32) | func (s *organizationStore) GetOrganizationByUserEmail(ctx context.Con...
method CreateOrganization (line 36) | func (s *organizationStore) CreateOrganization(ctx context.Context, ar...
method UpdateOrganization (line 40) | func (s *organizationStore) UpdateOrganization(ctx context.Context, ar...
method UpdateOrganizationStytchInfo (line 44) | func (s *organizationStore) UpdateOrganizationStytchInfo(ctx context.C...
method ListOrganizations (line 48) | func (s *organizationStore) ListOrganizations(ctx context.Context, arg...
method DeleteOrganization (line 52) | func (s *organizationStore) DeleteOrganization(ctx context.Context, id...
method GetOrganizationStats (line 56) | func (s *organizationStore) GetOrganizationStats(ctx context.Context, ...
function NewOrganizationStore (line 16) | func NewOrganizationStore(store sqlc.Store) adapters.OrganizationStore {
type accountStore (line 61) | type accountStore struct
method CreateAccount (line 69) | func (s *accountStore) CreateAccount(ctx context.Context, arg sqlc.Cre...
method GetAccountByID (line 73) | func (s *accountStore) GetAccountByID(ctx context.Context, arg sqlc.Ge...
method GetAccountByEmail (line 77) | func (s *accountStore) GetAccountByEmail(ctx context.Context, arg sqlc...
method ListAccountsByOrganization (line 81) | func (s *accountStore) ListAccountsByOrganization(ctx context.Context,...
method UpdateAccount (line 85) | func (s *accountStore) UpdateAccount(ctx context.Context, arg sqlc.Upd...
method UpdateAccountStytchInfo (line 89) | func (s *accountStore) UpdateAccountStytchInfo(ctx context.Context, ar...
method UpdateAccountLastLogin (line 93) | func (s *accountStore) UpdateAccountLastLogin(ctx context.Context, arg...
method DeleteAccount (line 97) | func (s *accountStore) DeleteAccount(ctx context.Context, arg sqlc.Del...
method GetAccountOrganization (line 101) | func (s *accountStore) GetAccountOrganization(ctx context.Context, id ...
method CheckAccountPermission (line 105) | func (s *accountStore) CheckAccountPermission(ctx context.Context, arg...
method GetAccountStats (line 109) | func (s *accountStore) GetAccountStats(ctx context.Context, id int32) ...
function NewAccountStore (line 65) | func NewAccountStore(store sqlc.Store) adapters.AccountStore {
FILE: go-b2b-starter/internal/db/postgres/adapter_impl/subscription_store.go
type subscriptionStore (line 11) | type subscriptionStore struct
method GetSubscriptionByOrgID (line 21) | func (s *subscriptionStore) GetSubscriptionByOrgID(ctx context.Context...
method GetSubscriptionBySubscriptionID (line 25) | func (s *subscriptionStore) GetSubscriptionBySubscriptionID(ctx contex...
method UpsertSubscription (line 29) | func (s *subscriptionStore) UpsertSubscription(ctx context.Context, ar...
method DeleteSubscription (line 33) | func (s *subscriptionStore) DeleteSubscription(ctx context.Context, or...
method ListActiveSubscriptions (line 37) | func (s *subscriptionStore) ListActiveSubscriptions(ctx context.Contex...
method GetQuotaByOrgID (line 43) | func (s *subscriptionStore) GetQuotaByOrgID(ctx context.Context, organ...
method UpsertQuota (line 47) | func (s *subscriptionStore) UpsertQuota(ctx context.Context, arg sqlc....
method DecrementInvoiceCount (line 51) | func (s *subscriptionStore) DecrementInvoiceCount(ctx context.Context,...
method ResetQuotaForPeriod (line 55) | func (s *subscriptionStore) ResetQuotaForPeriod(ctx context.Context, a...
method GetQuotaStatus (line 61) | func (s *subscriptionStore) GetQuotaStatus(ctx context.Context, organi...
method ListQuotasNearLimit (line 65) | func (s *subscriptionStore) ListQuotasNearLimit(ctx context.Context, t...
function NewSubscriptionStore (line 15) | func NewSubscriptionStore(store sqlc.Store) adapters.SubscriptionStore {
FILE: go-b2b-starter/internal/db/postgres/connection.go
function connPool (line 12) | func connPool(cfg Config) (*pgxpool.Pool, error) {
FILE: go-b2b-starter/internal/db/postgres/db_config.go
type Config (line 10) | type Config struct
method ConnectionString (line 29) | func (c Config) ConnectionString() string {
function LoadConfig (line 35) | func LoadConfig() (Config, error) {
FILE: go-b2b-starter/internal/db/postgres/init.go
function InitDB (line 12) | func InitDB(cfg Config) (*pgxpool.Pool, error) {
FILE: go-b2b-starter/internal/db/postgres/postgres_manager.go
type PostgresManager (line 21) | type PostgresManager struct
method CheckHealth (line 34) | func (pm *PostgresManager) CheckHealth(ctx context.Context) error {
method RunMigrations (line 50) | func (pm *PostgresManager) RunMigrations() error {
method RunSeeds (line 104) | func (pm *PostgresManager) RunSeeds() error {
function NewPostgresManager (line 26) | func NewPostgresManager(config Config, connPool *pgxpool.Pool) *Postgres...
FILE: go-b2b-starter/internal/db/postgres/retry.go
constant maxRetries (line 11) | maxRetries = 3
constant retryDelay (line 12) | retryDelay = 100 * time.Millisecond
constant maxRetryDelay (line 13) | maxRetryDelay = 1 * time.Second
function RetryOperation (line 17) | func RetryOperation(ctx context.Context, operation func(context.Context)...
function CreateDBContext (line 55) | func CreateDBContext(parent context.Context) (context.Context, context.C...
FILE: go-b2b-starter/internal/db/postgres/sqlc/gen/cognitive.sql.go
constant countChatMessagesBySession (line 15) | countChatMessagesBySession = `-- name: CountChatMessagesBySession :one
method CountChatMessagesBySession (line 20) | func (q *Queries) CountChatMessagesBySession(ctx context.Context, sessio...
constant countDocumentEmbeddingsByOrganization (line 27) | countDocumentEmbeddingsByOrganization = `-- name: CountDocumentEmbedding...
method CountDocumentEmbeddingsByOrganization (line 32) | func (q *Queries) CountDocumentEmbeddingsByOrganization(ctx context.Cont...
constant createChatMessage (line 39) | createChatMessage = `-- name: CreateChatMessage :one
type CreateChatMessageParams (line 52) | type CreateChatMessageParams struct
method CreateChatMessage (line 61) | func (q *Queries) CreateChatMessage(ctx context.Context, arg CreateChatM...
constant createChatSession (line 82) | createChatSession = `-- name: CreateChatSession :one
type CreateChatSessionParams (line 93) | type CreateChatSessionParams struct
method CreateChatSession (line 100) | func (q *Queries) CreateChatSession(ctx context.Context, arg CreateChatS...
constant createDocumentEmbedding (line 114) | createDocumentEmbedding = `-- name: CreateDocumentEmbedding :one
type CreateDocumentEmbeddingParams (line 129) | type CreateDocumentEmbeddingParams struct
method CreateDocumentEmbedding (line 140) | func (q *Queries) CreateDocumentEmbedding(ctx context.Context, arg Creat...
constant deleteChatMessage (line 164) | deleteChatMessage = `-- name: DeleteChatMessage :exec
method DeleteChatMessage (line 169) | func (q *Queries) DeleteChatMessage(ctx context.Context, id int32) error {
constant deleteChatSession (line 174) | deleteChatSession = `-- name: DeleteChatSession :exec
type DeleteChatSessionParams (line 179) | type DeleteChatSessionParams struct
method DeleteChatSession (line 184) | func (q *Queries) DeleteChatSession(ctx context.Context, arg DeleteChatS...
constant deleteDocumentEmbeddings (line 189) | deleteDocumentEmbeddings = `-- name: DeleteDocumentEmbeddings :exec
type DeleteDocumentEmbeddingsParams (line 194) | type DeleteDocumentEmbeddingsParams struct
method DeleteDocumentEmbeddings (line 199) | func (q *Queries) DeleteDocumentEmbeddings(ctx context.Context, arg Dele...
constant getChatMessagesBySession (line 204) | getChatMessagesBySession = `-- name: GetChatMessagesBySession :many
method GetChatMessagesBySession (line 210) | func (q *Queries) GetChatMessagesBySession(ctx context.Context, sessionI...
constant getChatSessionByID (line 238) | getChatSessionByID = `-- name: GetChatSessionByID :one
type GetChatSessionByIDParams (line 243) | type GetChatSessionByIDParams struct
method GetChatSessionByID (line 248) | func (q *Queries) GetChatSessionByID(ctx context.Context, arg GetChatSes...
constant getDocumentEmbeddingByID (line 262) | getDocumentEmbeddingByID = `-- name: GetDocumentEmbeddingByID :one
type GetDocumentEmbeddingByIDParams (line 267) | type GetDocumentEmbeddingByIDParams struct
method GetDocumentEmbeddingByID (line 272) | func (q *Queries) GetDocumentEmbeddingByID(ctx context.Context, arg GetD...
constant getDocumentEmbeddingsByDocumentID (line 289) | getDocumentEmbeddingsByDocumentID = `-- name: GetDocumentEmbeddingsByDoc...
type GetDocumentEmbeddingsByDocumentIDParams (line 295) | type GetDocumentEmbeddingsByDocumentIDParams struct
method GetDocumentEmbeddingsByDocumentID (line 300) | func (q *Queries) GetDocumentEmbeddingsByDocumentID(ctx context.Context,...
constant getRecentChatMessages (line 330) | getRecentChatMessages = `-- name: GetRecentChatMessages :many
type GetRecentChatMessagesParams (line 337) | type GetRecentChatMessagesParams struct
method GetRecentChatMessages (line 342) | func (q *Queries) GetRecentChatMessages(ctx context.Context, arg GetRece...
constant listChatSessionsByAccount (line 370) | listChatSessionsByAccount = `-- name: ListChatSessionsByAccount :many
type ListChatSessionsByAccountParams (line 377) | type ListChatSessionsByAccountParams struct
method ListChatSessionsByAccount (line 384) | func (q *Queries) ListChatSessionsByAccount(ctx context.Context, arg Lis...
constant searchSimilarDocuments (line 416) | searchSimilarDocuments = `-- name: SearchSimilarDocuments :many
type SearchSimilarDocumentsParams (line 433) | type SearchSimilarDocumentsParams struct
type SearchSimilarDocumentsRow (line 439) | type SearchSimilarDocumentsRow struct
method SearchSimilarDocuments (line 451) | func (q *Queries) SearchSimilarDocuments(ctx context.Context, arg Search...
constant updateChatSessionTitle (line 481) | updateChatSessionTitle = `-- name: UpdateChatSessionTitle :one
type UpdateChatSessionTitleParams (line 488) | type UpdateChatSessionTitleParams struct
method UpdateChatSessionTitle (line 494) | func (q *Queries) UpdateChatSessionTitle(ctx context.Context, arg Update...
FILE: go-b2b-starter/internal/db/postgres/sqlc/gen/db.go
type DBTX (line 14) | type DBTX interface
function New (line 20) | func New(db DBTX) *Queries {
type Queries (line 24) | type Queries struct
method WithTx (line 28) | func (q *Queries) WithTx(tx pgx.Tx) *Queries {
FILE: go-b2b-starter/internal/db/postgres/sqlc/gen/documents.sql.go
constant countDocumentsByOrganization (line 14) | countDocumentsByOrganization = `-- name: CountDocumentsByOrganization :one
method CountDocumentsByOrganization (line 19) | func (q *Queries) CountDocumentsByOrganization(ctx context.Context, orga...
constant countDocumentsByStatus (line 26) | countDocumentsByStatus = `-- name: CountDocumentsByStatus :one
type CountDocumentsByStatusParams (line 31) | type CountDocumentsByStatusParams struct
method CountDocumentsByStatus (line 36) | func (q *Queries) CountDocumentsByStatus(ctx context.Context, arg CountD...
constant createDocument (line 43) | createDocument = `-- name: CreateDocument :one
type CreateDocumentParams (line 60) | type CreateDocumentParams struct
method CreateDocument (line 73) | func (q *Queries) CreateDocument(ctx context.Context, arg CreateDocument...
constant deleteDocument (line 103) | deleteDocument = `-- name: DeleteDocument :exec
type DeleteDocumentParams (line 108) | type DeleteDocumentParams struct
method DeleteDocument (line 113) | func (q *Queries) DeleteDocument(ctx context.Context, arg DeleteDocument...
constant getDocumentByFileAssetID (line 118) | getDocumentByFileAssetID = `-- name: GetDocumentByFileAssetID :one
type GetDocumentByFileAssetIDParams (line 123) | type GetDocumentByFileAssetIDParams struct
method GetDocumentByFileAssetID (line 128) | func (q *Queries) GetDocumentByFileAssetID(ctx context.Context, arg GetD...
constant getDocumentByID (line 148) | getDocumentByID = `-- name: GetDocumentByID :one
type GetDocumentByIDParams (line 153) | type GetDocumentByIDParams struct
method GetDocumentByID (line 158) | func (q *Queries) GetDocumentByID(ctx context.Context, arg GetDocumentBy...
constant listDocumentsByOrganization (line 178) | listDocumentsByOrganization = `-- name: ListDocumentsByOrganization :many
type ListDocumentsByOrganizationParams (line 185) | type ListDocumentsByOrganizationParams struct
method ListDocumentsByOrganization (line 191) | func (q *Queries) ListDocumentsByOrganization(ctx context.Context, arg L...
constant listDocumentsByStatus (line 224) | listDocumentsByStatus = `-- name: ListDocumentsByStatus :many
type ListDocumentsByStatusParams (line 231) | type ListDocumentsByStatusParams struct
method ListDocumentsByStatus (line 238) | func (q *Queries) ListDocumentsByStatus(ctx context.Context, arg ListDoc...
constant updateDocument (line 276) | updateDocument = `-- name: UpdateDocument :one
type UpdateDocumentParams (line 286) | type UpdateDocumentParams struct
method UpdateDocument (line 293) | func (q *Queries) UpdateDocument(ctx context.Context, arg UpdateDocument...
constant updateDocumentExtractedText (line 318) | updateDocumentExtractedText = `-- name: UpdateDocumentExtractedText :one
type UpdateDocumentExtractedTextParams (line 325) | type UpdateDocumentExtractedTextParams struct
method UpdateDocumentExtractedText (line 331) | func (q *Queries) UpdateDocumentExtractedText(ctx context.Context, arg U...
constant updateDocumentStatus (line 351) | updateDocumentStatus = `-- name: UpdateDocumentStatus :one
type UpdateDocumentStatusParams (line 358) | type UpdateDocumentStatusParams struct
method UpdateDocumentStatus (line 364) | func (q *Queries) UpdateDocumentStatus(ctx context.Context, arg UpdateDo...
FILE: go-b2b-starter/internal/db/postgres/sqlc/gen/error.go
constant ForeignKeyViolation (line 11) | ForeignKeyViolation = "23503"
constant UniqueViolation (line 12) | UniqueViolation = "23505"
function ErrorCode (line 21) | func ErrorCode(err error) string {
FILE: go-b2b-starter/internal/db/postgres/sqlc/gen/example_resource.sql.go
constant assignResourceApproval (line 14) | assignResourceApproval = `-- name: AssignResourceApproval :exec
type AssignResourceApprovalParams (line 22) | type AssignResourceApprovalParams struct
method AssignResourceApproval (line 29) | func (q *Queries) AssignResourceApproval(ctx context.Context, arg Assign...
constant attachFileToResource (line 34) | attachFileToResource = `-- name: AttachFileToResource :exec
type AttachFileToResourceParams (line 41) | type AttachFileToResourceParams struct
method AttachFileToResource (line 48) | func (q *Queries) AttachFileToResource(ctx context.Context, arg AttachFi...
constant countResources (line 53) | countResources = `-- name: CountResources :one
type CountResourcesParams (line 61) | type CountResourcesParams struct
method CountResources (line 69) | func (q *Queries) CountResources(ctx context.Context, arg CountResources...
constant createMinimalResource (line 81) | createMinimalResource = `-- name: CreateMinimalResource :one
type CreateMinimalResourceParams (line 89) | type CreateMinimalResourceParams struct
method CreateMinimalResource (line 97) | func (q *Queries) CreateMinimalResource(ctx context.Context, arg CreateM...
constant createResource (line 129) | createResource = `-- name: CreateResource :one
type CreateResourceParams (line 141) | type CreateResourceParams struct
method CreateResource (line 159) | func (q *Queries) CreateResource(ctx context.Context, arg CreateResource...
constant deleteResource (line 198) | deleteResource = `-- name: DeleteResource :exec
type DeleteResourceParams (line 206) | type DeleteResourceParams struct
method DeleteResource (line 213) | func (q *Queries) DeleteResource(ctx context.Context, arg DeleteResource...
constant getRecentResources (line 218) | getRecentResources = `-- name: GetRecentResources :many
type GetRecentResourcesParams (line 228) | type GetRecentResourcesParams struct
type GetRecentResourcesRow (line 233) | type GetRecentResourcesRow struct
method GetRecentResources (line 244) | func (q *Queries) GetRecentResources(ctx context.Context, arg GetRecentR...
constant getResourceByID (line 272) | getResourceByID = `-- name: GetResourceByID :one
type GetResourceByIDParams (line 278) | type GetResourceByIDParams struct
method GetResourceByID (line 284) | func (q *Queries) GetResourceByID(ctx context.Context, arg GetResourceBy...
constant getResourceByNumber (line 311) | getResourceByNumber = `-- name: GetResourceByNumber :one
type GetResourceByNumberParams (line 316) | type GetResourceByNumberParams struct
method GetResourceByNumber (line 321) | func (q *Queries) GetResourceByNumber(ctx context.Context, arg GetResour...
constant getResourceStats (line 348) | getResourceStats = `-- name: GetResourceStats :one
type GetResourceStatsRow (line 362) | type GetResourceStatsRow struct
method GetResourceStats (line 374) | func (q *Queries) GetResourceStats(ctx context.Context, organizationID i...
constant getResourcesByCreator (line 389) | getResourcesByCreator = `-- name: GetResourcesByCreator :many
type GetResourcesByCreatorParams (line 398) | type GetResourcesByCreatorParams struct
method GetResourcesByCreator (line 406) | func (q *Queries) GetResourcesByCreator(ctx context.Context, arg GetReso...
constant hardDeleteResource (line 451) | hardDeleteResource = `-- name: HardDeleteResource :exec
type HardDeleteResourceParams (line 456) | type HardDeleteResourceParams struct
method HardDeleteResource (line 462) | func (q *Queries) HardDeleteResource(ctx context.Context, arg HardDelete...
constant listResources (line 467) | listResources = `-- name: ListResources :many
type ListResourcesParams (line 482) | type ListResourcesParams struct
type ListResourcesRow (line 491) | type ListResourcesRow struct
method ListResources (line 509) | func (q *Queries) ListResources(ctx context.Context, arg ListResourcesPa...
constant searchResourcesByText (line 551) | searchResourcesByText = `-- name: SearchResourcesByText :many
type SearchResourcesByTextParams (line 565) | type SearchResourcesByTextParams struct
type SearchResourcesByTextRow (line 572) | type SearchResourcesByTextRow struct
method SearchResourcesByText (line 586) | func (q *Queries) SearchResourcesByText(ctx context.Context, arg SearchR...
constant updateResource (line 621) | updateResource = `-- name: UpdateResource :exec
type UpdateResourceParams (line 632) | type UpdateResourceParams struct
method UpdateResource (line 642) | func (q *Queries) UpdateResource(ctx context.Context, arg UpdateResource...
constant updateResourceApprovalStatus (line 654) | updateResourceApprovalStatus = `-- name: UpdateResourceApprovalStatus :exec
type UpdateResourceApprovalStatusParams (line 663) | type UpdateResourceApprovalStatusParams struct
method UpdateResourceApprovalStatus (line 672) | func (q *Queries) UpdateResourceApprovalStatus(ctx context.Context, arg ...
constant updateResourceProcessingData (line 683) | updateResourceProcessingData = `-- name: UpdateResourceProcessingData :exec
type UpdateResourceProcessingDataParams (line 693) | type UpdateResourceProcessingDataParams struct
method UpdateResourceProcessingData (line 703) | func (q *Queries) UpdateResourceProcessingData(ctx context.Context, arg ...
constant updateResourceStatus (line 715) | updateResourceStatus = `-- name: UpdateResourceStatus :exec
type UpdateResourceStatusParams (line 722) | type UpdateResourceStatusParams struct
method UpdateResourceStatus (line 728) | func (q *Queries) UpdateResourceStatus(ctx context.Context, arg UpdateRe...
FILE: go-b2b-starter/internal/db/postgres/sqlc/gen/exec.go
method execTx (line 9) | func (store *SQLStore) execTx(ctx context.Context, fn func(*Queries) err...
FILE: go-b2b-starter/internal/db/postgres/sqlc/gen/file_manager.sql.go
constant createFileAsset (line 14) | createFileAsset = `-- name: CreateFileAsset :one
type CreateFileAssetParams (line 35) | type CreateFileAssetParams struct
method CreateFileAsset (line 51) | func (q *Queries) CreateFileAsset(ctx context.Context, arg CreateFileAss...
constant deleteFileAsset (line 89) | deleteFileAsset = `-- name: DeleteFileAsset :exec
method DeleteFileAsset (line 94) | func (q *Queries) DeleteFileAsset(ctx context.Context, id int32) error {
constant getFileAssetByID (line 99) | getFileAssetByID = `-- name: GetFileAssetByID :one
method GetFileAssetByID (line 104) | func (q *Queries) GetFileAssetByID(ctx context.Context, id int32) (FileM...
constant getFileAssetByStoragePath (line 128) | getFileAssetByStoragePath = `-- name: GetFileAssetByStoragePath :one
method GetFileAssetByStoragePath (line 133) | func (q *Queries) GetFileAssetByStoragePath(ctx context.Context, storage...
constant getFileAssetsByCategory (line 157) | getFileAssetsByCategory = `-- name: GetFileAssetsByCategory :many
type GetFileAssetsByCategoryRow (line 165) | type GetFileAssetsByCategoryRow struct
method GetFileAssetsByCategory (line 185) | func (q *Queries) GetFileAssetsByCategory(ctx context.Context, name stri...
constant getFileAssetsByContext (line 223) | getFileAssetsByContext = `-- name: GetFileAssetsByContext :many
type GetFileAssetsByContextRow (line 231) | type GetFileAssetsByContextRow struct
method GetFileAssetsByContext (line 251) | func (q *Queries) GetFileAssetsByContext(ctx context.Context, name strin...
constant getFileAssetsByEntity (line 289) | getFileAssetsByEntity = `-- name: GetFileAssetsByEntity :many
type GetFileAssetsByEntityParams (line 294) | type GetFileAssetsByEntityParams struct
method GetFileAssetsByEntity (line 299) | func (q *Queries) GetFileAssetsByEntity(ctx context.Context, arg GetFile...
constant getFileAssetsByEntityAndPurpose (line 336) | getFileAssetsByEntityAndPurpose = `-- name: GetFileAssetsByEntityAndPurp...
type GetFileAssetsByEntityAndPurposeParams (line 342) | type GetFileAssetsByEntityAndPurposeParams struct
method GetFileAssetsByEntityAndPurpose (line 348) | func (q *Queries) GetFileAssetsByEntityAndPurpose(ctx context.Context, a...
constant getFileCategories (line 385) | getFileCategories = `-- name: GetFileCategories :many
method GetFileCategories (line 389) | func (q *Queries) GetFileCategories(ctx context.Context) ([]FileManagerF...
constant getFileContexts (line 409) | getFileContexts = `-- name: GetFileContexts :many
method GetFileContexts (line 413) | func (q *Queries) GetFileContexts(ctx context.Context) ([]FileManagerFil...
constant listFileAssets (line 433) | listFileAssets = `-- name: ListFileAssets :many
type ListFileAssetsParams (line 442) | type ListFileAssetsParams struct
type ListFileAssetsRow (line 447) | type ListFileAssetsRow struct
method ListFileAssets (line 468) | func (q *Queries) ListFileAssets(ctx context.Context, arg ListFileAssets...
constant updateFileAsset (line 507) | updateFileAsset = `-- name: UpdateFileAsset :exec
type UpdateFileAssetParams (line 518) | type UpdateFileAssetParams struct
method UpdateFileAsset (line 526) | func (q *Queries) UpdateFileAsset(ctx context.Context, arg UpdateFileAss...
FILE: go-b2b-starter/internal/db/postgres/sqlc/gen/models.go
type CognitiveChatMessage (line 13) | type CognitiveChatMessage struct
type CognitiveChatSession (line 24) | type CognitiveChatSession struct
type CognitiveDocumentEmbedding (line 34) | type CognitiveDocumentEmbedding struct
type DocumentsDocument (line 49) | type DocumentsDocument struct
type DuplicateCandidate (line 67) | type DuplicateCandidate struct
type ExampleResource (line 86) | type ExampleResource struct
type FileManagerFileAsset (line 112) | type FileManagerFileAsset struct
type FileManagerFileCategory (line 131) | type FileManagerFileCategory struct
type FileManagerFileContext (line 137) | type FileManagerFileContext struct
type OrganizationsAccount (line 143) | type OrganizationsAccount struct
type OrganizationsOrganization (line 165) | type OrganizationsOrganization struct
type ResourceEmbedding (line 182) | type ResourceEmbedding struct
type SubscriptionBillingQuotaTracking (line 196) | type SubscriptionBillingQuotaTracking struct
type SubscriptionBillingSubscription (line 210) | type SubscriptionBillingSubscription struct
FILE: go-b2b-starter/internal/db/postgres/sqlc/gen/organizations.sql.go
constant checkAccountPermission (line 14) | checkAccountPermission = `-- name: CheckAccountPermission :one
type CheckAccountPermissionParams (line 25) | type CheckAccountPermissionParams struct
type CheckAccountPermissionRow (line 30) | type CheckAccountPermissionRow struct
method CheckAccountPermission (line 37) | func (q *Queries) CheckAccountPermission(ctx context.Context, arg CheckA...
constant createAccount (line 49) | createAccount = `-- name: CreateAccount :one
type CreateAccountParams (line 87) | type CreateAccountParams struct
method CreateAccount (line 100) | func (q *Queries) CreateAccount(ctx context.Context, arg CreateAccountPa...
constant createOrganization (line 131) | createOrganization = `-- name: CreateOrganization :one
type CreateOrganizationParams (line 152) | type CreateOrganizationParams struct
method CreateOrganization (line 158) | func (q *Queries) CreateOrganization(ctx context.Context, arg CreateOrga...
constant deleteAccount (line 175) | deleteAccount = `-- name: DeleteAccount :exec
type DeleteAccountParams (line 183) | type DeleteAccountParams struct
method DeleteAccount (line 188) | func (q *Queries) DeleteAccount(ctx context.Context, arg DeleteAccountPa...
constant deleteOrganization (line 193) | deleteOrganization = `-- name: DeleteOrganization :exec
method DeleteOrganization (line 198) | func (q *Queries) DeleteOrganization(ctx context.Context, id int32) error {
constant getAccountByEmail (line 203) | getAccountByEmail = `-- name: GetAccountByEmail :one
type GetAccountByEmailParams (line 222) | type GetAccountByEmailParams struct
method GetAccountByEmail (line 227) | func (q *Queries) GetAccountByEmail(ctx context.Context, arg GetAccountB...
constant getAccountByID (line 248) | getAccountByID = `-- name: GetAccountByID :one
type GetAccountByIDParams (line 267) | type GetAccountByIDParams struct
method GetAccountByID (line 272) | func (q *Queries) GetAccountByID(ctx context.Context, arg GetAccountByID...
constant getAccountOrganization (line 293) | getAccountOrganization = `-- name: GetAccountOrganization :one
method GetAccountOrganization (line 309) | func (q *Queries) GetAccountOrganization(ctx context.Context, id int32) ...
constant getAccountStats (line 326) | getAccountStats = `-- name: GetAccountStats :one
type GetAccountStatsRow (line 348) | type GetAccountStatsRow struct
method GetAccountStats (line 366) | func (q *Queries) GetAccountStats(ctx context.Context, id int32) (GetAcc...
constant getOrganizationByID (line 389) | getOrganizationByID = `-- name: GetOrganizationByID :one
method GetOrganizationByID (line 404) | func (q *Queries) GetOrganizationByID(ctx context.Context, id int32) (Or...
constant getOrganizationBySlug (line 421) | getOrganizationBySlug = `-- name: GetOrganizationBySlug :one
method GetOrganizationBySlug (line 436) | func (q *Queries) GetOrganizationBySlug(ctx context.Context, slug string...
constant getOrganizationByStytchID (line 453) | getOrganizationByStytchID = `-- name: GetOrganizationByStytchID :one
method GetOrganizationByStytchID (line 468) | func (q *Queries) GetOrganizationByStytchID(ctx context.Context, stytchO...
constant getOrganizationByUserEmail (line 485) | getOrganizationByUserEmail = `-- name: GetOrganizationByUserEmail :one
method GetOrganizationByUserEmail (line 506) | func (q *Queries) GetOrganizationByUserEmail(ctx context.Context, email ...
constant getOrganizationStats (line 523) | getOrganizationStats = `-- name: GetOrganizationStats :one
type GetOrganizationStatsRow (line 543) | type GetOrganizationStatsRow struct
method GetOrganizationStats (line 558) | func (q *Queries) GetOrganizationStats(ctx context.Context, id int32) (G...
constant listAccountsByOrganization (line 577) | listAccountsByOrganization = `-- name: ListAccountsByOrganization :many
method ListAccountsByOrganization (line 597) | func (q *Queries) ListAccountsByOrganization(ctx context.Context, organi...
constant listOrganizations (line 631) | listOrganizations = `-- name: ListOrganizations :many
type ListOrganizationsParams (line 647) | type ListOrganizationsParams struct
method ListOrganizations (line 652) | func (q *Queries) ListOrganizations(ctx context.Context, arg ListOrganiz...
constant updateAccount (line 682) | updateAccount = `-- name: UpdateAccount :one
type UpdateAccountParams (line 709) | type UpdateAccountParams struct
method UpdateAccount (line 720) | func (q *Queries) UpdateAccount(ctx context.Context, arg UpdateAccountPa...
constant updateAccountLastLogin (line 750) | updateAccountLastLogin = `-- name: UpdateAccountLastLogin :one
type UpdateAccountLastLoginParams (line 772) | type UpdateAccountLastLoginParams struct
method UpdateAccountLastLogin (line 777) | func (q *Queries) UpdateAccountLastLogin(ctx context.Context, arg Update...
constant updateAccountStytchInfo (line 798) | updateAccountStytchInfo = `-- name: UpdateAccountStytchInfo :one
type UpdateAccountStytchInfoParams (line 823) | type UpdateAccountStytchInfoParams struct
method UpdateAccountStytchInfo (line 832) | func (q *Queries) UpdateAccountStytchInfo(ctx context.Context, arg Updat...
constant updateOrganization (line 860) | updateOrganization = `-- name: UpdateOrganization :one
type UpdateOrganizationParams (line 882) | type UpdateOrganizationParams struct
method UpdateOrganization (line 891) | func (q *Queries) UpdateOrganization(ctx context.Context, arg UpdateOrga...
constant updateOrganizationStytchInfo (line 915) | updateOrganizationStytchInfo = `-- name: UpdateOrganizationStytchInfo :one
type UpdateOrganizationStytchInfoParams (line 935) | type UpdateOrganizationStytchInfoParams struct
method UpdateOrganizationStytchInfo (line 942) | func (q *Queries) UpdateOrganizationStytchInfo(ctx context.Context, arg ...
FILE: go-b2b-starter/internal/db/postgres/sqlc/gen/querier.go
type Querier (line 13) | type Querier interface
FILE: go-b2b-starter/internal/db/postgres/sqlc/gen/resource_embeddings.sql.go
constant confirmDuplicate (line 15) | confirmDuplicate = `-- name: ConfirmDuplicate :exec
method ConfirmDuplicate (line 22) | func (q *Queries) ConfirmDuplicate(ctx context.Context, id int32) error {
constant countDuplicatesByStatus (line 27) | countDuplicatesByStatus = `-- name: CountDuplicatesByStatus :one
type CountDuplicatesByStatusParams (line 32) | type CountDuplicatesByStatusParams struct
method CountDuplicatesByStatus (line 38) | func (q *Queries) CountDuplicatesByStatus(ctx context.Context, arg Count...
constant countEmbeddingsByOrganization (line 45) | countEmbeddingsByOrganization = `-- name: CountEmbeddingsByOrganization ...
method CountEmbeddingsByOrganization (line 51) | func (q *Queries) CountEmbeddingsByOrganization(ctx context.Context, org...
constant createDuplicateCandidateExactMatch (line 58) | createDuplicateCandidateExactMatch = `-- name: CreateDuplicateCandidateE...
type CreateDuplicateCandidateExactMatchParams (line 72) | type CreateDuplicateCandidateExactMatchParams struct
method CreateDuplicateCandidateExactMatch (line 80) | func (q *Queries) CreateDuplicateCandidateExactMatch(ctx context.Context...
constant createDuplicateCandidateLLM (line 106) | createDuplicateCandidateLLM = `-- name: CreateDuplicateCandidateLLM :one
type CreateDuplicateCandidateLLMParams (line 123) | type CreateDuplicateCandidateLLMParams struct
method CreateDuplicateCandidateLLM (line 135) | func (q *Queries) CreateDuplicateCandidateLLM(ctx context.Context, arg C...
constant createResourceDuplicateCandidate (line 165) | createResourceDuplicateCandidate = `-- name: CreateResourceDuplicateCand...
type CreateResourceDuplicateCandidateParams (line 183) | type CreateResourceDuplicateCandidateParams struct
method CreateResourceDuplicateCandidate (line 198) | func (q *Queries) CreateResourceDuplicateCandidate(ctx context.Context, ...
constant deleteDuplicateCandidate (line 230) | deleteDuplicateCandidate = `-- name: DeleteDuplicateCandidate :exec
method DeleteDuplicateCandidate (line 236) | func (q *Queries) DeleteDuplicateCandidate(ctx context.Context, id int32...
constant deleteResourceEmbedding (line 241) | deleteResourceEmbedding = `-- name: DeleteResourceEmbedding :exec
type DeleteResourceEmbeddingParams (line 247) | type DeleteResourceEmbeddingParams struct
method DeleteResourceEmbedding (line 254) | func (q *Queries) DeleteResourceEmbedding(ctx context.Context, arg Delet...
constant dismissDuplicate (line 259) | dismissDuplicate = `-- name: DismissDuplicate :exec
method DismissDuplicate (line 266) | func (q *Queries) DismissDuplicate(ctx context.Context, id int32) error {
constant findExactDuplicateByHash (line 271) | findExactDuplicateByHash = `-- name: FindExactDuplicateByHash :many
type FindExactDuplicateByHashParams (line 282) | type FindExactDuplicateByHashParams struct
type FindExactDuplicateByHashRow (line 288) | type FindExactDuplicateByHashRow struct
method FindExactDuplicateByHash (line 295) | func (q *Queries) FindExactDuplicateByHash(ctx context.Context, arg Find...
constant findSimilarResources (line 315) | findSimilarResources = `-- name: FindSimilarResources :many
type FindSimilarResourcesParams (line 329) | type FindSimilarResourcesParams struct
type FindSimilarResourcesRow (line 337) | type FindSimilarResourcesRow struct
method FindSimilarResources (line 354) | func (q *Queries) FindSimilarResources(ctx context.Context, arg FindSimi...
constant getDuplicateCandidate (line 385) | getDuplicateCandidate = `-- name: GetDuplicateCandidate :one
method GetDuplicateCandidate (line 391) | func (q *Queries) GetDuplicateCandidate(ctx context.Context, id int32) (...
constant getResourceDuplicateStats (line 412) | getResourceDuplicateStats = `-- name: GetResourceDuplicateStats :one
type GetResourceDuplicateStatsRow (line 425) | type GetResourceDuplicateStatsRow struct
method GetResourceDuplicateStats (line 436) | func (q *Queries) GetResourceDuplicateStats(ctx context.Context, organiz...
constant getResourceEmbedding (line 451) | getResourceEmbedding = `-- name: GetResourceEmbedding :one
type GetResourceEmbeddingParams (line 457) | type GetResourceEmbeddingParams struct
method GetResourceEmbedding (line 463) | func (q *Queries) GetResourceEmbedding(ctx context.Context, arg GetResou...
constant listDuplicateCandidatesForResource (line 479) | listDuplicateCandidatesForResource = `-- name: ListDuplicateCandidatesFo...
type ListDuplicateCandidatesForResourceParams (line 485) | type ListDuplicateCandidatesForResourceParams struct
method ListDuplicateCandidatesForResource (line 491) | func (q *Queries) ListDuplicateCandidatesForResource(ctx context.Context...
constant listPendingDuplicates (line 525) | listPendingDuplicates = `-- name: ListPendingDuplicates :many
type ListPendingDuplicatesParams (line 532) | type ListPendingDuplicatesParams struct
method ListPendingDuplicates (line 539) | func (q *Queries) ListPendingDuplicates(ctx context.Context, arg ListPen...
constant saveResourceEmbedding (line 573) | saveResourceEmbedding = `-- name: SaveResourceEmbedding :exec
type SaveResourceEmbeddingParams (line 591) | type SaveResourceEmbeddingParams struct
method SaveResourceEmbedding (line 603) | func (q *Queries) SaveResourceEmbedding(ctx context.Context, arg SaveRes...
constant updateDuplicateCandidateStatus (line 614) | updateDuplicateCandidateStatus = `-- name: UpdateDuplicateCandidateStatu...
type UpdateDuplicateCandidateStatusParams (line 620) | type UpdateDuplicateCandidateStatusParams struct
method UpdateDuplicateCandidateStatus (line 626) | func (q *Queries) UpdateDuplicateCandidateStatus(ctx context.Context, ar...
FILE: go-b2b-starter/internal/db/postgres/sqlc/gen/store.go
type Store (line 13) | type Store interface
type SQLStore (line 17) | type SQLStore struct
method WithTx (line 29) | func (store *SQLStore) WithTx(db DBTX) Store {
method ExecTx (line 36) | func (store *SQLStore) ExecTx(ctx context.Context, fn func(*Queries) e...
function NewStore (line 22) | func NewStore(connPool *pgxpool.Pool) Store {
FILE: go-b2b-starter/internal/db/postgres/sqlc/gen/subscription_billing.sql.go
constant decrementInvoiceCount (line 14) | decrementInvoiceCount = `-- name: DecrementInvoiceCount :one
method DecrementInvoiceCount (line 24) | func (q *Queries) DecrementInvoiceCount(ctx context.Context, organizatio...
constant deleteSubscription (line 41) | deleteSubscription = `-- name: DeleteSubscription :exec
method DeleteSubscription (line 47) | func (q *Queries) DeleteSubscription(ctx context.Context, organizationID...
constant getQuotaByOrgID (line 52) | getQuotaByOrgID = `-- name: GetQuotaByOrgID :one
method GetQuotaByOrgID (line 59) | func (q *Queries) GetQuotaByOrgID(ctx context.Context, organizationID in...
constant getQuotaStatus (line 76) | getQuotaStatus = `-- name: GetQuotaStatus :one
type GetQuotaStatusRow (line 95) | type GetQuotaStatusRow struct
method GetQuotaStatus (line 106) | func (q *Queries) GetQuotaStatus(ctx context.Context, organizationID int...
constant getSubscriptionByOrgID (line 121) | getSubscriptionByOrgID = `-- name: GetSubscriptionByOrgID :one
method GetSubscriptionByOrgID (line 128) | func (q *Queries) GetSubscriptionByOrgID(ctx context.Context, organizati...
constant getSubscriptionBySubscriptionID (line 151) | getSubscriptionBySubscriptionID = `-- name: GetSubscriptionBySubscriptio...
method GetSubscriptionBySubscriptionID (line 158) | func (q *Queries) GetSubscriptionBySubscriptionID(ctx context.Context, s...
constant listActiveSubscriptions (line 181) | listActiveSubscriptions = `-- name: ListActiveSubscriptions :many
method ListActiveSubscriptions (line 188) | func (q *Queries) ListActiveSubscriptions(ctx context.Context) ([]Subscr...
constant listQuotasNearLimit (line 224) | listQuotasNearLimit = `-- name: ListQuotasNearLimit :many
type ListQuotasNearLimitRow (line 237) | type ListQuotasNearLimitRow struct
method ListQuotasNearLimit (line 252) | func (q *Queries) ListQuotasNearLimit(ctx context.Context, invoiceCount ...
constant resetQuotaForPeriod (line 284) | resetQuotaForPeriod = `-- name: ResetQuotaForPeriod :one
type ResetQuotaForPeriodParams (line 295) | type ResetQuotaForPeriodParams struct
method ResetQuotaForPeriod (line 303) | func (q *Queries) ResetQuotaForPeriod(ctx context.Context, arg ResetQuot...
constant upsertQuota (line 325) | upsertQuota = `-- name: UpsertQuota :one
type UpsertQuotaParams (line 348) | type UpsertQuotaParams struct
method UpsertQuota (line 357) | func (q *Queries) UpsertQuota(ctx context.Context, arg UpsertQuotaParams...
constant upsertSubscription (line 380) | upsertSubscription = `-- name: UpsertSubscription :one
type UpsertSubscriptionParams (line 415) | type UpsertSubscriptionParams struct
method UpsertSubscription (line 431) | func (q *Queries) UpsertSubscription(ctx context.Context, arg UpsertSubs...
FILE: go-b2b-starter/internal/db/postgres/sqlc/migrations/000001_create_file_manager_schema.up.sql
type file_manager (line 4) | CREATE TABLE file_manager.file_categories (
type file_manager (line 11) | CREATE TABLE file_manager.file_contexts (
type file_manager (line 17) | CREATE TABLE file_manager.file_assets (
type idx_file_assets_entity (line 37) | CREATE INDEX idx_file_assets_entity ON file_manager.file_assets(entity_t...
type idx_file_assets_category (line 38) | CREATE INDEX idx_file_assets_category ON file_manager.file_assets(file_c...
type idx_file_assets_context (line 39) | CREATE INDEX idx_file_assets_context ON file_manager.file_assets(file_co...
type idx_file_assets_created_at (line 40) | CREATE INDEX idx_file_assets_created_at ON file_manager.file_assets(crea...
FILE: go-b2b-starter/internal/db/postgres/sqlc/migrations/000002_create_organizations_schema.up.sql
type organizations (line 5) | CREATE TABLE organizations.organizations (
type organizations (line 24) | CREATE TABLE organizations.accounts (
type idx_organizations_slug (line 58) | CREATE INDEX idx_organizations_slug ON organizations.organizations(slug)...
type idx_organizations_status (line 59) | CREATE INDEX idx_organizations_status ON organizations.organizations(sta...
type idx_organizations_created_at (line 60) | CREATE INDEX idx_organizations_created_at ON organizations.organizations...
type idx_organizations_stytch_org_id (line 61) | CREATE UNIQUE INDEX idx_organizations_stytch_org_id ON organizations.org...
type idx_accounts_org_id (line 63) | CREATE INDEX idx_accounts_org_id ON organizations.accounts(organization_id)
type idx_accounts_email (line 64) | CREATE INDEX idx_accounts_email ON organizations.accounts(email)
type idx_accounts_status (line 65) | CREATE INDEX idx_accounts_status ON organizations.accounts(status)
type idx_accounts_role (line 66) | CREATE INDEX idx_accounts_role ON organizations.accounts(role)
type idx_accounts_stytch_member_id (line 67) | CREATE INDEX idx_accounts_stytch_member_id ON organizations.accounts(sty...
function update_updated_at_column (line 70) | CREATE OR REPLACE FUNCTION update_updated_at_column()
FILE: go-b2b-starter/internal/db/postgres/sqlc/migrations/000004_create_subscription_billing_schema.up.sql
type subscription_billing (line 5) | CREATE TABLE subscription_billing.subscriptions (
type subscription_billing (line 36) | CREATE TABLE subscription_billing.quota_tracking (
type idx_subscriptions_organization_id (line 60) | CREATE INDEX idx_subscriptions_organization_id ON subscription_billing.s...
type idx_subscriptions_subscription_status (line 61) | CREATE INDEX idx_subscriptions_subscription_status ON subscription_billi...
type idx_subscriptions_external_customer_id (line 62) | CREATE INDEX idx_subscriptions_external_customer_id ON subscription_bill...
type idx_quota_tracking_organization_id (line 64) | CREATE INDEX idx_quota_tracking_organization_id ON subscription_billing....
type idx_quota_tracking_period_end (line 65) | CREATE INDEX idx_quota_tracking_period_end ON subscription_billing.quota...
FILE: go-b2b-starter/internal/db/postgres/sqlc/migrations/000006_create_example_resources.up.sql
type example_resources (line 11) | CREATE TABLE IF NOT EXISTS example_resources (
type idx_example_resources_organization (line 48) | CREATE INDEX idx_example_resources_organization ON example_resources(org...
type idx_example_resources_status (line 49) | CREATE INDEX idx_example_resources_status ON example_resources(status_id)
type idx_example_resources_created_by (line 50) | CREATE INDEX idx_example_resources_created_by ON example_resources(creat...
type idx_example_resources_file (line 51) | CREATE INDEX idx_example_resources_file ON example_resources(file_id)
type idx_example_resources_approval_assigned (line 52) | CREATE INDEX idx_example_resources_approval_assigned ON example_resource...
type idx_example_resources_created_at (line 53) | CREATE INDEX idx_example_resources_created_at ON example_resources(creat...
type idx_example_resources_active (line 54) | CREATE INDEX idx_example_resources_active ON example_resources(is_active)
type idx_example_resources_search (line 57) | CREATE INDEX idx_example_resources_search ON example_resources USING gin...
function update_example_resources_updated_at (line 60) | CREATE OR REPLACE FUNCTION update_example_resources_updated_at()
FILE: go-b2b-starter/internal/db/postgres/sqlc/migrations/000007_create_resource_embeddings.up.sql
type resource_embeddings (line 6) | CREATE TABLE resource_embeddings (
type idx_resource_embeddings_vector (line 21) | CREATE INDEX idx_resource_embeddings_vector
type idx_resource_embeddings_organization (line 27) | CREATE INDEX idx_resource_embeddings_organization ON resource_embeddings...
type idx_resource_embeddings_content_hash (line 28) | CREATE INDEX idx_resource_embeddings_content_hash ON resource_embeddings...
type idx_resource_embeddings_resource (line 29) | CREATE INDEX idx_resource_embeddings_resource ON resource_embeddings(res...
type duplicate_candidates (line 33) | CREATE TABLE duplicate_candidates (
type idx_duplicate_candidates_resource (line 51) | CREATE INDEX idx_duplicate_candidates_resource ON duplicate_candidates(r...
type idx_duplicate_candidates_candidate (line 52) | CREATE INDEX idx_duplicate_candidates_candidate ON duplicate_candidates(...
type idx_duplicate_candidates_organization (line 53) | CREATE INDEX idx_duplicate_candidates_organization ON duplicate_candidat...
type idx_duplicate_candidates_status (line 54) | CREATE INDEX idx_duplicate_candidates_status ON duplicate_candidates(sta...
type idx_duplicate_candidates_method (line 55) | CREATE INDEX idx_duplicate_candidates_method ON duplicate_candidates(det...
type idx_duplicate_candidates_resource_org (line 58) | CREATE INDEX idx_duplicate_candidates_resource_org ON duplicate_candidat...
function update_resource_embeddings_updated_at (line 61) | CREATE OR REPLACE FUNCTION update_resource_embeddings_updated_at()
function update_duplicate_candidates_updated_at (line 74) | CREATE OR REPLACE FUNCTION update_duplicate_candidates_updated_at()
FILE: go-b2b-starter/internal/db/postgres/sqlc/migrations/000008_create_documents_schema.up.sql
type documents (line 5) | CREATE TABLE documents.documents (
type idx_documents_organization (line 22) | CREATE INDEX idx_documents_organization ON documents.documents(organizat...
type idx_documents_file_asset (line 23) | CREATE INDEX idx_documents_file_asset ON documents.documents(file_asset_id)
type idx_documents_status (line 24) | CREATE INDEX idx_documents_status ON documents.documents(status)
type idx_documents_created_at (line 25) | CREATE INDEX idx_documents_created_at ON documents.documents(created_at ...
function documents (line 28) | CREATE OR REPLACE FUNCTION documents.update_documents_updated_at()
FILE: go-b2b-starter/internal/db/postgres/sqlc/migrations/000009_create_cognitive_schema.up.sql
type cognitive (line 8) | CREATE TABLE cognitive.document_embeddings (
type idx_doc_embeddings_vector (line 22) | CREATE INDEX idx_doc_embeddings_vector ON cognitive.document_embeddings
type idx_doc_embeddings_organization (line 25) | CREATE INDEX idx_doc_embeddings_organization ON cognitive.document_embed...
type idx_doc_embeddings_document (line 26) | CREATE INDEX idx_doc_embeddings_document ON cognitive.document_embedding...
type idx_doc_embeddings_content_hash (line 27) | CREATE INDEX idx_doc_embeddings_content_hash ON cognitive.document_embed...
type cognitive (line 30) | CREATE TABLE cognitive.chat_sessions (
type idx_chat_sessions_organization (line 39) | CREATE INDEX idx_chat_sessions_organization ON cognitive.chat_sessions(o...
type idx_chat_sessions_account (line 40) | CREATE INDEX idx_chat_sessions_account ON cognitive.chat_sessions(accoun...
type idx_chat_sessions_created_at (line 41) | CREATE INDEX idx_chat_sessions_created_at ON cognitive.chat_sessions(cre...
type cognitive (line 44) | CREATE TABLE cognitive.chat_messages (
type idx_chat_messages_session (line 55) | CREATE INDEX idx_chat_messages_session ON cognitive.chat_messages(sessio...
type idx_chat_messages_created_at (line 56) | CREATE INDEX idx_chat_messages_created_at ON cognitive.chat_messages(cre...
function cognitive (line 59) | CREATE OR REPLACE FUNCTION cognitive.update_embeddings_updated_at()
function cognitive (line 72) | CREATE OR REPLACE FUNCTION cognitive.update_sessions_updated_at()
FILE: go-b2b-starter/internal/db/postgres/types_transform.go
function Int16Ptr (line 19) | func Int16Ptr(i pgtype.Int2) *int16 {
function Int32Ptr (line 27) | func Int32Ptr(i pgtype.Int4) *int32 {
function Int64Ptr (line 35) | func Int64Ptr(i pgtype.Int8) *int64 {
function Float32Ptr (line 43) | func Float32Ptr(f pgtype.Float4) *float32 {
function Float64Ptr (line 51) | func Float64Ptr(f pgtype.Float8) *float64 {
function StringPtr (line 59) | func StringPtr(t pgtype.Text) *string {
function TimeStampPtr (line 67) | func TimeStampPtr(t pgtype.Timestamp) *time.Time {
function TimeStampTzPtr (line 76) | func TimeStampTzPtr(t pgtype.Timestamptz) *time.Time {
function TimePtr (line 85) | func TimePtr(t pgtype.Time) *time.Time {
function BoolPtr (line 97) | func BoolPtr(b pgtype.Bool) *bool {
function PgInt2 (line 106) | func PgInt2(i *int16) pgtype.Int2 {
function PgInt4 (line 114) | func PgInt4(i *int32) pgtype.Int4 {
function PgInt8 (line 122) | func PgInt8(i *int64) pgtype.Int8 {
function PgFloat4 (line 130) | func PgFloat4(f *float32) pgtype.Float4 {
function PgFloat8 (line 138) | func PgFloat8(f *float64) pgtype.Float8 {
function PgText (line 146) | func PgText(s *string) pgtype.Text {
function PgTimestamp (line 154) | func PgTimestamp(t *time.Time) pgtype.Timestamp {
function PgTimestamptz (line 162) | func PgTimestamptz(t *time.Time) pgtype.Timestamptz {
function PgTime (line 170) | func PgTime(t *time.Time) pgtype.Time {
function PgBool (line 183) | func PgBool(b *bool) pgtype.Bool {
function UUIDPtr (line 191) | func UUIDPtr(u pgtype.UUID) *uuid.UUID {
function PgUUID (line 200) | func PgUUID(u *uuid.UUID) pgtype.UUID {
function NumericPtr (line 211) | func NumericPtr(n pgtype.Numeric) *float64 {
function Numeric (line 245) | func Numeric(f *float64) pgtype.Numeric {
function NumericFromDecimal (line 261) | func NumericFromDecimal(d *decimal.Decimal) pgtype.Numeric {
function NumericFromFloat32 (line 274) | func NumericFromFloat32(f float32) pgtype.Numeric {
function Float32FromNumeric (line 284) | func Float32FromNumeric(n pgtype.Numeric) float32 {
function DatePtr (line 320) | func DatePtr(d pgtype.Date) *time.Time {
function PgDate (line 328) | func PgDate(t *time.Time) pgtype.Date {
function PgTextFromString (line 336) | func PgTextFromString(s string) pgtype.Text {
function StringFromPgText (line 344) | func StringFromPgText(t pgtype.Text) string {
function PgInt4FromInt32 (line 352) | func PgInt4FromInt32(i int32) pgtype.Int4 {
function Int32FromPgInt4 (line 357) | func Int32FromPgInt4(i pgtype.Int4) int32 {
function ConvertWKBToPoint (line 364) | func ConvertWKBToPoint(wkbHex string) (*geomPkg.Point, error) {
function ConvertWKBToPointString (line 387) | func ConvertWKBToPointString(wkbHex string) (string, error) {
FILE: go-b2b-starter/internal/docs/api/handler.go
type Handler (line 3) | type Handler struct
function NewHandler (line 6) | func NewHandler() *Handler {
FILE: go-b2b-starter/internal/docs/api/routes.go
method Routes (line 11) | func (h *Handler) Routes(router *gin.RouterGroup, resolver domain.Middle...
FILE: go-b2b-starter/internal/docs/cmd/init.go
function Init (line 12) | func Init(container *dig.Container) {
FILE: go-b2b-starter/internal/docs/gen/docs.go
constant docTemplate (line 6) | docTemplate = `{
function init (line 1545) | func init() {
FILE: go-b2b-starter/internal/modules/auth/adapters/stytch/adapter.go
type StytchAuthAdapter (line 52) | type StytchAuthAdapter struct
method VerifyToken (line 132) | func (a *StytchAuthAdapter) VerifyToken(ctx context.Context, token str...
method Client (line 160) | func (a *StytchAuthAdapter) Client() *b2bstytchapi.API {
method Config (line 165) | func (a *StytchAuthAdapter) Config() *Config {
method PolicyService (line 172) | func (a *StytchAuthAdapter) PolicyService() *RBACPolicyService {
function NewStytchAuthAdapter (line 65) | func NewStytchAuthAdapter(
function NewStytchAuthAdapterWithClient (line 102) | func NewStytchAuthAdapterWithClient(
FILE: go-b2b-starter/internal/modules/auth/adapters/stytch/config.go
constant EnvTest (line 13) | EnvTest = "test"
constant EnvLive (line 14) | EnvLive = "live"
type Config (line 21) | type Config struct
method Validate (line 137) | func (c *Config) Validate() error {
function LoadConfig (line 65) | func LoadConfig() (*Config, error) {
function NewConfigFromExisting (line 148) | func NewConfigFromExisting(projectID, secret, env, baseURL, jwksURL stri...
FILE: go-b2b-starter/internal/modules/auth/adapters/stytch/jwks_cache.go
constant jwksCacheKeyPattern (line 19) | jwksCacheKeyPattern = "auth:stytch:jwks:key:%s"
constant jwksCacheTTL (line 20) | jwksCacheTTL = 24 * time.Hour
type JWKSCache (line 28) | type JWKSCache struct
method GetPublicKey (line 68) | func (c *JWKSCache) GetPublicKey(ctx context.Context, kid string) (*rs...
method fetchJWKS (line 133) | func (c *JWKSCache) fetchJWKS(ctx context.Context) (*JWKS, error) {
method jwkToPublicKey (line 162) | func (c *JWKSCache) jwkToPublicKey(jwk *JWK) (*rsa.PublicKey, error) {
method cachePublicKey (line 188) | func (c *JWKSCache) cachePublicKey(ctx context.Context, kid string, jw...
method deserializePublicKey (line 210) | func (c *JWKSCache) deserializePublicKey(serialized *serializedPublicK...
type JWKS (line 36) | type JWKS struct
type JWK (line 41) | type JWK struct
type serializedPublicKey (line 51) | type serializedPublicKey struct
function NewJWKSCache (line 56) | func NewJWKSCache(jwksURL string, redisClient redis.Client, logger logge...
FILE: go-b2b-starter/internal/modules/auth/adapters/stytch/jwt_parser.go
type JWTParser (line 15) | type JWTParser struct
method ParseWithoutVerification (line 31) | func (p *JWTParser) ParseWithoutVerification(token string) (header map...
method ExtractKeyID (line 65) | func (p *JWTParser) ExtractKeyID(token string) (string, error) {
function NewJWTParser (line 17) | func NewJWTParser() *JWTParser {
FILE: go-b2b-starter/internal/modules/auth/adapters/stytch/mock_adapter.go
type MockAuthAdapter (line 17) | type MockAuthAdapter struct
method VerifyToken (line 32) | func (m *MockAuthAdapter) VerifyToken(ctx context.Context, token strin...
method GetRolePermissions (line 60) | func (m *MockAuthAdapter) GetRolePermissions(ctx context.Context, role...
method ValidatePermission (line 72) | func (m *MockAuthAdapter) ValidatePermission(ctx context.Context, iden...
method RefreshSession (line 82) | func (m *MockAuthAdapter) RefreshSession(ctx context.Context, sessionT...
function NewMockAuthAdapter (line 24) | func NewMockAuthAdapter(log logger.Logger) *MockAuthAdapter {
FILE: go-b2b-starter/internal/modules/auth/adapters/stytch/rbac_policy.go
constant rbacPolicyCacheKey (line 19) | rbacPolicyCacheKey = "auth:stytch:rbac:policy"
constant rbacPolicyCacheTTL (line 21) | rbacPolicyCacheTTL = 5 * time.Minute
type RBACPolicyService (line 28) | type RBACPolicyService struct
method GetRolePermissions (line 45) | func (s *RBACPolicyService) GetRolePermissions(ctx context.Context, ro...
method getPolicy (line 71) | func (s *RBACPolicyService) getPolicy(ctx context.Context) (*rbac.Poli...
method fetchPolicyFromStytch (line 99) | func (s *RBACPolicyService) fetchPolicyFromStytch(ctx context.Context)...
method cachePolicy (line 120) | func (s *RBACPolicyService) cachePolicy(ctx context.Context, policy *r...
method convertPermissions (line 142) | func (s *RBACPolicyService) convertPermissions(permissions []rbac.Poli...
method expandWildcardActions (line 171) | func (s *RBACPolicyService) expandWildcardActions(resourceID string, a...
function NewRBACPolicyService (line 34) | func NewRBACPolicyService(client *b2bstytchapi.API, redisClient redis.Cl...
function normalizeRoleID (line 203) | func normalizeRoleID(roleID string) string {
FILE: go-b2b-starter/internal/modules/auth/adapters/stytch/token_verifier.go
type TokenVerifier (line 23) | type TokenVerifier struct
method Verify (line 69) | func (v *TokenVerifier) Verify(ctx context.Context, token string) (*au...
method verifyLocally (line 96) | func (v *TokenVerifier) verifyLocally(ctx context.Context, token strin...
method verifyViaAPI (line 157) | func (v *TokenVerifier) verifyViaAPI(ctx context.Context, token string...
method verifyWithoutSignature (line 210) | func (v *TokenVerifier) verifyWithoutSignature(ctx context.Context, to...
method parseClaimsFromMap (line 232) | func (v *TokenVerifier) parseClaimsFromMap(claimsMap map[string]any) *...
method validateClaims (line 322) | func (v *TokenVerifier) validateClaims(claims *internalClaims) error {
method derivePermissions (line 354) | func (v *TokenVerifier) derivePermissions(ctx context.Context, roles [...
method convertRoles (line 404) | func (v *TokenVerifier) convertRoles(roles []string) []auth.Role {
method translateStytchError (line 424) | func (v *TokenVerifier) translateStytchError(err error) error {
function NewTokenVerifier (line 32) | func NewTokenVerifier(
type internalClaims (line 50) | type internalClaims struct
function parseStringSlice (line 445) | func parseStringSlice(value any) []string {
function parseNumericTime (line 467) | func parseNumericTime(value any) time.Time {
function timeValue (line 480) | func timeValue(ts *time.Time) time.Time {
FILE: go-b2b-starter/internal/modules/auth/auth.go
type AuthProvider (line 76) | type AuthProvider interface
type Identity (line 89) | type Identity struct
method HasRole (line 121) | func (i *Identity) HasRole(role Role) bool {
method HasPermission (line 131) | func (i *Identity) HasPermission(permission Permission) bool {
method HasResourcePermission (line 141) | func (i *Identity) HasResourcePermission(resource, action string) bool {
type RequestContext (line 152) | type RequestContext struct
type OrganizationRepository (line 173) | type OrganizationRepository interface
type AccountRepository (line 183) | type AccountRepository interface
type Organization (line 190) | type Organization struct
type Account (line 196) | type Account struct
FILE: go-b2b-starter/internal/modules/auth/cmd/init.go
function Init (line 36) | func Init(container *dig.Container) error {
function InitMiddleware (line 90) | func InitMiddleware(container *dig.Container) error {
function isPlaceholderCredentials (line 98) | func isPlaceholderCredentials(cfg *stytch.Config) bool {
FILE: go-b2b-starter/internal/modules/auth/context.go
type contextKey (line 11) | type contextKey
constant identityKey (line 15) | identityKey contextKey = "auth_identity"
constant requestContextKey (line 18) | requestContextKey contextKey = "auth_request_context"
function SetIdentity (line 25) | func SetIdentity(c *gin.Context, identity *Identity) {
function GetIdentity (line 40) | func GetIdentity(c *gin.Context) *Identity {
function MustGetIdentity (line 53) | func MustGetIdentity(c *gin.Context) *Identity {
function SetRequestContext (line 65) | func SetRequestContext(c *gin.Context, reqCtx *RequestContext) {
function GetRequestContext (line 81) | func GetRequestContext(c *gin.Context) *RequestContext {
function MustGetRequestContext (line 100) | func MustGetRequestContext(c *gin.Context) *RequestContext {
function GetOrganizationID (line 112) | func GetOrganizationID(c *gin.Context) int32 {
function GetAccountID (line 123) | func GetAccountID(c *gin.Context) int32 {
function WithIdentity (line 134) | func WithIdentity(ctx context.Context, identity *Identity) context.Conte...
function IdentityFromContext (line 141) | func IdentityFromContext(ctx context.Context) *Identity {
function WithRequestContext (line 154) | func WithRequestContext(ctx context.Context, reqCtx *RequestContext) con...
function RequestContextFromContext (line 161) | func RequestContextFromContext(ctx context.Context) *RequestContext {
FILE: go-b2b-starter/internal/modules/auth/errors.go
function IsAuthError (line 58) | func IsAuthError(err error) bool {
function IsForbiddenError (line 67) | func IsForbiddenError(err error) bool {
function HTTPStatusCode (line 82) | func HTTPStatusCode(err error) int {
FILE: go-b2b-starter/internal/modules/auth/handler.go
type Handler (line 12) | type Handler struct
method GetRoles (line 30) | func (h *Handler) GetRoles(c *gin.Context) {
method GetPermissions (line 51) | func (h *Handler) GetPermissions(c *gin.Context) {
method GetPermissionsByCategory (line 72) | func (h *Handler) GetPermissionsByCategory(c *gin.Context) {
method GetRoleDetails (line 100) | func (h *Handler) GetRoleDetails(c *gin.Context) {
method CheckPermission (line 127) | func (h *Handler) CheckPermission(c *gin.Context) {
method GetMetadata (line 156) | func (h *Handler) GetMetadata(c *gin.Context) {
function NewHandler (line 16) | func NewHandler(service RBACService) *Handler {
FILE: go-b2b-starter/internal/modules/auth/middleware.go
type OrganizationResolver (line 15) | type OrganizationResolver interface
type AccountResolver (line 25) | type AccountResolver interface
type MiddlewareConfig (line 32) | type MiddlewareConfig struct
function DefaultMiddlewareConfig (line 38) | func DefaultMiddlewareConfig() *MiddlewareConfig {
function defaultErrorHandler (line 45) | func defaultErrorHandler(c *gin.Context, statusCode int, message string,...
type Middleware (line 59) | type Middleware struct
method RequireAuth (line 100) | func (m *Middleware) RequireAuth() gin.HandlerFunc {
method RequireOrganization (line 147) | func (m *Middleware) RequireOrganization() gin.HandlerFunc {
method RequirePermission (line 217) | func (m *Middleware) RequirePermission(resource, action string) gin.Ha...
method RequireAnyPermission (line 249) | func (m *Middleware) RequireAnyPermission(permissions ...Permission) g...
method RequireAllPermissions (line 282) | func (m *Middleware) RequireAllPermissions(permissions ...Permission) ...
method RequireRole (line 310) | func (m *Middleware) RequireRole(role Role) gin.HandlerFunc {
method RequireAnyRole (line 336) | func (m *Middleware) RequireAnyRole(roles ...Role) gin.HandlerFunc {
function NewMiddleware (line 71) | func NewMiddleware(
function extractBearerToken (line 360) | func extractBearerToken(c *gin.Context) (string, error) {
function hasPermission (line 375) | func hasPermission(identity *Identity, resource, action string) bool {
function hasRole (line 396) | func hasRole(identity *Identity, role Role) bool {
function errorMessage (line 407) | func errorMessage(err error) string {
function RequirePermissionFunc (line 434) | func RequirePermissionFunc(resource, action string) gin.HandlerFunc {
function RequireAnyPermissionFunc (line 461) | func RequireAnyPermissionFunc(permissions ...Permission) gin.HandlerFunc {
FILE: go-b2b-starter/internal/modules/auth/permissions.go
type Permission (line 26) | type Permission
method String (line 39) | func (p Permission) String() string {
method Resource (line 49) | func (p Permission) Resource() string {
method Action (line 63) | func (p Permission) Action() string {
method IsValid (line 72) | func (p Permission) IsValid() bool {
method Matches (line 81) | func (p Permission) Matches(other Permission) bool {
method MatchesWithWildcard (line 97) | func (p Permission) MatchesWithWildcard(other Permission) bool {
function NewPermission (line 34) | func NewPermission(resource, action string) Permission {
type PermissionSet (line 115) | type PermissionSet
method Contains (line 136) | func (ps PermissionSet) Contains(permission Permission) bool {
method ContainsResourceAction (line 142) | func (ps PermissionSet) ContainsResourceAction(resource, action string...
method ContainsAny (line 147) | func (ps PermissionSet) ContainsAny(permissions ...Permission) bool {
method ContainsAll (line 157) | func (ps PermissionSet) ContainsAll(permissions ...Permission) bool {
method ToSlice (line 167) | func (ps PermissionSet) ToSlice() []Permission {
function NewPermissionSet (line 118) | func NewPermissionSet(permissions []Permission) PermissionSet {
function NewPermissionSetFromStrings (line 127) | func NewPermissionSetFromStrings(permissions []string) PermissionSet {
function PermissionsToStrings (line 176) | func PermissionsToStrings(permissions []Permission) []string {
function StringsToPermissions (line 185) | func StringsToPermissions(permissions []string) []Permission {
FILE: go-b2b-starter/internal/modules/auth/provider.go
type ServerMiddlewareRegistrar (line 12) | type ServerMiddlewareRegistrar interface
type Provider (line 17) | type Provider struct
method RegisterDependencies (line 28) | func (p *Provider) RegisterDependencies() error {
function NewProvider (line 21) | func NewProvider(container *dig.Container) *Provider {
function SetupMiddleware (line 69) | func SetupMiddleware(container *dig.Container) error {
function RegisterNamedMiddlewares (line 95) | func RegisterNamedMiddlewares(container *dig.Container) error {
function ProvideResolvers (line 124) | func ProvideResolvers(
FILE: go-b2b-starter/internal/modules/auth/rbac.go
type RoleInfo (line 72) | type RoleInfo struct
function GetRoleInfo (line 144) | func GetRoleInfo(roleID string) *RoleInfo {
function GetRolePermissionIDs (line 155) | func GetRolePermissionIDs(roleID string) []string {
function HasPermission (line 169) | func HasPermission(roleID string, permission Permission) bool {
type PermissionDTO (line 209) | type PermissionDTO struct
function NewPermissionDTO (line 219) | func NewPermissionDTO(perm Permission) PermissionDTO {
type RoleDTO (line 232) | type RoleDTO struct
function NewRoleDTO (line 240) | func NewRoleDTO(role RoleInfo) RoleDTO {
type RolesResponse (line 255) | type RolesResponse struct
type PermissionsResponse (line 260) | type PermissionsResponse struct
type PermissionsByCategoryResponse (line 265) | type PermissionsByCategoryResponse struct
type RolePermissionsResponse (line 270) | type RolePermissionsResponse struct
type RoleStatistics (line 277) | type RoleStatistics struct
type RoleRestrictions (line 285) | type RoleRestrictions struct
function NewRolePermissionsResponse (line 292) | func NewRolePermissionsResponse(roleID string) *RolePermissionsResponse {
type PermissionCheckRequest (line 342) | type PermissionCheckRequest struct
type PermissionCheckResponse (line 348) | type PermissionCheckResponse struct
type RBACMetadata (line 355) | type RBACMetadata struct
function NewRBACMetadata (line 363) | func NewRBACMetadata() RBACMetadata {
type RBACService (line 382) | type RBACService interface
type defaultRBACService (line 394) | type defaultRBACService struct
method GetAllRoles (line 400) | func (s *defaultRBACService) GetAllRoles() []RoleInfo {
method GetRoleInfo (line 404) | func (s *defaultRBACService) GetRoleInfo(roleID string) *RoleInfo {
method GetAllPermissions (line 408) | func (s *defaultRBACService) GetAllPermissions() []Permission {
method GetRolePermissions (line 412) | func (s *defaultRBACService) GetRolePermissions(roleID string) []Permi...
method GetPermissionsByCategory (line 420) | func (s *defaultRBACService) GetPermissionsByCategory() map[string][]P...
method GetPermissionsByRoleID (line 427) | func (s *defaultRBACService) GetPermissionsByRoleID(roleID string) []s...
method HasPermission (line 431) | func (s *defaultRBACService) HasPermission(roleID string, permissionID...
method GetRBACMetadata (line 435) | func (s *defaultRBACService) GetRBACMetadata() RBACMetadata {
function NewRBACService (line 396) | func NewRBACService() RBACService {
FILE: go-b2b-starter/internal/modules/auth/resolvers.go
type OrganizationLookup (line 12) | type OrganizationLookup interface
type OrganizationEntity (line 19) | type OrganizationEntity interface
type AccountLookup (line 27) | type AccountLookup interface
type AccountEntity (line 34) | type AccountEntity interface
function NewOrganizationResolver (line 49) | func NewOrganizationResolver(lookup OrganizationLookup) OrganizationReso...
function NewAccountResolver (line 61) | func NewAccountResolver(lookup AccountLookup) AccountResolver {
type orgResolverAdapter (line 66) | type orgResolverAdapter struct
method ResolveByProviderID (line 70) | func (a *orgResolverAdapter) ResolveByProviderID(ctx context.Context, ...
type accResolverAdapter (line 79) | type accResolverAdapter struct
method ResolveByEmail (line 83) | func (a *accResolverAdapter) ResolveByEmail(ctx context.Context, orgID...
type SimpleOrganization (line 93) | type SimpleOrganization struct
method GetID (line 97) | func (o *SimpleOrganization) GetID() int32 { return o.ID }
type SimpleAccount (line 101) | type SimpleAccount struct
method GetID (line 105) | func (a *SimpleAccount) GetID() int32 { return a.ID }
FILE: go-b2b-starter/internal/modules/auth/roles.go
type Role (line 24) | type Role
method String (line 67) | func (r Role) String() string {
method IsValid (line 72) | func (r Role) IsValid() bool {
constant RoleMember (line 33) | RoleMember Role = "member"
constant RoleManager (line 38) | RoleManager Role = "manager"
constant RoleAdmin (line 42) | RoleAdmin Role = "admin"
constant RoleOwner (line 51) | RoleOwner Role = "owner"
constant RoleApprover (line 55) | RoleApprover Role = "approver"
constant RoleReviewer (line 59) | RoleReviewer Role = "reviewer"
constant RoleEmployee (line 63) | RoleEmployee Role = "employee"
function NormalizeRole (line 86) | func NormalizeRole(roleStr string) Role {
function GetRolePermissions (line 118) | func GetRolePermissions(role Role) []Permission {
function HasRolePermission (line 135) | func HasRolePermission(role Role, resource, action string) bool {
FILE: go-b2b-starter/internal/modules/auth/routes.go
type Routes (line 10) | type Routes struct
method RegisterRoutes (line 23) | func (r *Routes) RegisterRoutes(router *gin.RouterGroup, resolver serv...
method Routes (line 61) | func (r *Routes) Routes(router *gin.RouterGroup, resolver serverDomain...
function NewRoutes (line 14) | func NewRoutes(handler *Handler) *Routes {
FILE: go-b2b-starter/internal/modules/billing/app/services/check_quota_availability_service.go
method CheckQuotaAvailability (line 14) | func (s *billingService) CheckQuotaAvailability(ctx context.Context, org...
FILE: go-b2b-starter/internal/modules/billing/app/services/consume_invoice_quota_service.go
method ConsumeInvoiceQuota (line 14) | func (s *billingService) ConsumeInvoiceQuota(ctx context.Context, organi...
method ingestMeterEventToPolar (line 65) | func (s *billingService) ingestMeterEventToPolar(ctx context.Context, or...
FILE: go-b2b-starter/internal/modules/billing/app/services/get_billing_status_service.go
method GetBillingStatus (line 11) | func (s *billingService) GetBillingStatus(ctx context.Context, organizat...
method buildStatusReason (line 37) | func (s *billingService) buildStatusReason(status *domain.QuotaStatus) s...
FILE: go-b2b-starter/internal/modules/billing/app/services/module.go
type Module (line 16) | type Module struct
method Configure (line 23) | func (m *Module) Configure(container *dig.Container) error {
function NewModule (line 18) | func NewModule() *Module {
FILE: go-b2b-starter/internal/modules/billing/app/services/process_webhook_event_service.go
constant invoicesProcessedMeterSlug (line 15) | invoicesProcessedMeterSlug = "invoice.processed"
method ProcessWebhookEvent (line 17) | func (s *billingService) ProcessWebhookEvent(ctx context.Context, eventT...
method parseSubscriptionWebhookPayload (line 56) | func (s *billingService) parseSubscriptionWebhookPayload(payload map[str...
method handleSubscriptionUpsert (line 211) | func (s *billingService) handleSubscriptionUpsert(ctx context.Context, e...
method handleSubscriptionCanceled (line 304) | func (s *billingService) handleSubscriptionCanceled(ctx context.Context,...
method handleCustomerUpdated (line 351) | func (s *billingService) handleCustomerUpdated(ctx context.Context, even...
method handleMeterGrantEvent (line 421) | func (s *billingService) handleMeterGrantEvent(ctx context.Context, payl...
method parseMeterGrantPayload (line 486) | func (s *billingService) parseMeterGrantPayload(payload map[string]any) ...
function normalizePolarObject (line 618) | func normalizePolarObject(payload map[string]any) map[string]any {
function extractProductMap (line 646) | func extractProductMap(input map[string]any) map[string]any {
function firstMapFromSlice (line 681) | func firstMapFromSlice(value any) map[string]any {
function stringMapFrom (line 696) | func stringMapFrom(value any) map[string]string {
function toStringMap (line 710) | func toStringMap(input map[string]any) map[string]string {
function toString (line 720) | func toString(value any) (string, bool) {
function toInt32 (line 770) | func toInt32(value any) (int32, bool) {
function parseISOTime (line 851) | func parseISOTime(value any) (time.Time, bool) {
function toBool (line 869) | func toBool(value any) (bool, bool) {
function mapKeys (line 897) | func mapKeys(m map[string]any) []string {
function extractInvoiceCountFromProduct (line 909) | func extractInvoiceCountFromProduct(product map[string]any) string {
FILE: go-b2b-starter/internal/modules/billing/app/services/refresh_subscription_status_service.go
method RefreshSubscriptionStatus (line 14) | func (s *billingService) RefreshSubscriptionStatus(ctx context.Context, ...
FILE: go-b2b-starter/internal/modules/billing/app/services/subscription_service_dec.go
type BillingService (line 27) | type BillingService interface
type billingService (line 73) | type billingService struct
function NewBillingService (line 80) | func NewBillingService(
FILE: go-b2b-starter/internal/modules/billing/app/services/sync_subscription_service.go
method SyncSubscriptionFromPolar (line 12) | func (s *billingService) SyncSubscriptionFromPolar(ctx context.Context, ...
FILE: go-b2b-starter/internal/modules/billing/app/services/verify_and_consume_quota_service.go
method VerifyAndConsumeQuota (line 11) | func (s *billingService) VerifyAndConsumeQuota(ctx context.Context, orga...
method needsFallbackVerification (line 77) | func (s *billingService) needsFallbackVerification(status *domain.QuotaS...
FILE: go-b2b-starter/internal/modules/billing/app/services/verify_payment_service.go
method VerifyPaymentFromCheckout (line 12) | func (s *billingService) VerifyPaymentFromCheckout(ctx context.Context, ...
FILE: go-b2b-starter/internal/modules/billing/cmd/init.go
function Init (line 16) | func Init(container *dig.Container) error {
FILE: go-b2b-starter/internal/modules/billing/cmd/provider.go
function ProvideDependencies (line 14) | func ProvideDependencies(container *dig.Container) error {
FILE: go-b2b-starter/internal/modules/billing/domain/repository.go
type SubscriptionRepository (line 6) | type SubscriptionRepository interface
type OrganizationAdapter (line 22) | type OrganizationAdapter interface
type BillingProvider (line 29) | type BillingProvider interface
FILE: go-b2b-starter/internal/modules/billing/domain/types.go
type Subscription (line 6) | type Subscription struct
type QuotaTracking (line 25) | type QuotaTracking struct
type QuotaStatus (line 39) | type QuotaStatus struct
type BillingStatus (line 50) | type BillingStatus struct
type WebhookEvent (line 61) | type WebhookEvent struct
type SubscriptionEventData (line 67) | type SubscriptionEventData struct
type MeterGrantEventData (line 82) | type MeterGrantEventData struct
type CheckoutSessionResponse (line 89) | type CheckoutSessionResponse struct
FILE: go-b2b-starter/internal/modules/billing/handler.go
type Handler (line 18) | type Handler struct
method GetBillingStatus (line 40) | func (h *Handler) GetBillingStatus(c *gin.Context) {
method VerifyPayment (line 97) | func (h *Handler) VerifyPayment(c *gin.Context) {
function NewHandler (line 23) | func NewHandler(billingService billingServices.BillingService, log logge...
type VerifyPaymentRequest (line 81) | type VerifyPaymentRequest struct
FILE: go-b2b-starter/internal/modules/billing/infra/adapters/status_provider.go
type StatusProviderAdapter (line 16) | type StatusProviderAdapter struct
method GetSubscriptionStatus (line 28) | func (a *StatusProviderAdapter) GetSubscriptionStatus(ctx context.Cont...
method RefreshSubscriptionStatus (line 59) | func (a *StatusProviderAdapter) RefreshSubscriptionStatus(ctx context....
function NewStatusProviderAdapter (line 20) | func NewStatusProviderAdapter(service services.BillingService) paywall.S...
function parseStatusFromReason (line 87) | func parseStatusFromReason(reason string) string {
function containsStatus (line 104) | func containsStatus(reason, status string) bool {
function contains (line 109) | func contains(s, substr string) bool {
FILE: go-b2b-starter/internal/modules/billing/infra/polar/polar_adapter.go
type polarAdapter (line 21) | type polarAdapter struct
method GetSubscription (line 33) | func (p *polarAdapter) GetSubscription(ctx context.Context, externalCu...
method GetCheckoutSession (line 128) | func (p *polarAdapter) GetCheckoutSession(ctx context.Context, session...
method GetCheckoutSessionWithPolling (line 207) | func (p *polarAdapter) GetCheckoutSessionWithPolling(ctx context.Conte...
method IngestMeterEvent (line 330) | func (p *polarAdapter) IngestMeterEvent(ctx context.Context, externalC...
function NewPolarAdapter (line 26) | func NewPolarAdapter(client *polarpkg.Client, log logger.Logger) domain....
function isRetryableError (line 299) | func isRetryableError(err error) bool {
function parseTime (line 378) | func parseTime(s string) (time.Time, error) {
FILE: go-b2b-starter/internal/modules/billing/infra/repositories/organization_adapter.go
type organizationAdapter (line 12) | type organizationAdapter struct
method GetStytchOrgID (line 22) | func (a *organizationAdapter) GetStytchOrgID(ctx context.Context, orga...
method GetOrganizationIDByStytchOrgID (line 35) | func (a *organizationAdapter) GetOrganizationIDByStytchOrgID(ctx conte...
function NewOrganizationAdapter (line 16) | func NewOrganizationAdapter(orgStore adapters.OrganizationStore) domain....
FILE: go-b2b-starter/internal/modules/billing/infra/repositories/subscription_repository.go
type subscriptionRepository (line 19) | type subscriptionRepository struct
method GetSubscriptionByOrgID (line 28) | func (r *subscriptionRepository) GetSubscriptionByOrgID(ctx context.Co...
method UpsertSubscription (line 40) | func (r *subscriptionRepository) UpsertSubscription(ctx context.Contex...
method DeleteSubscription (line 70) | func (r *subscriptionRepository) DeleteSubscription(ctx context.Contex...
method GetQuotaByOrgID (line 77) | func (r *subscriptionRepository) GetQuotaByOrgID(ctx context.Context, ...
method UpsertQuota (line 89) | func (r *subscriptionRepository) UpsertQuota(ctx context.Context, quot...
method DecrementInvoiceCount (line 106) | func (r *subscriptionRepository) DecrementInvoiceCount(ctx context.Con...
method GetQuotaStatus (line 115) | func (r *subscriptionRepository) GetQuotaStatus(ctx context.Context, o...
method mapToDomainSubscription (line 129) | func (r *subscriptionRepository) mapToDomainSubscription(s *sqlc.Subsc...
method mapToDomainQuota (line 162) | func (r *subscriptionRepository) mapToDomainQuota(q *sqlc.Subscription...
method mapToDomainQuotaStatus (line 182) | func (r *subscriptionRepository) mapToDomainQuotaStatus(qs *sqlc.GetQu...
function NewSubscriptionRepository (line 24) | func NewSubscriptionRepository(store sqlc.Store) domain.SubscriptionRepo...
function toPgTimestamp (line 204) | func toPgTimestamp(t time.Time) pgtype.Timestamp {
function toPgTimestampPtr (line 211) | func toPgTimestampPtr(t *time.Time) pgtype.Timestamp {
FILE: go-b2b-starter/internal/modules/billing/provider.go
function RegisterHandlers (line 8) | func RegisterHandlers(container *dig.Container) error {
function ProvideHandler (line 16) | func ProvideHandler(container *dig.Container) error {
FILE: go-b2b-starter/internal/modules/billing/routes.go
method Routes (line 11) | func (h *Handler) Routes(router *gin.RouterGroup, resolver serverDomain....
FILE: go-b2b-starter/internal/modules/cognitive/app/services/document_listener.go
type documentListener (line 8) | type documentListener struct
method HandleDocumentUploaded (line 20) | func (l *documentListener) HandleDocumentUploaded(ctx context.Context,...
function NewDocumentListener (line 12) | func NewDocumentListener(
FILE: go-b2b-starter/internal/modules/cognitive/app/services/embedding_service.go
constant MaxChunkSize (line 14) | MaxChunkSize = 8000
constant ContentPreviewLength (line 16) | ContentPreviewLength = 500
type embeddingService (line 19) | type embeddingService struct
method EmbedDocument (line 34) | func (s *embeddingService) EmbedDocument(ctx context.Context, orgID, d...
method GetDocumentEmbeddings (line 68) | func (s *embeddingService) GetDocumentEmbeddings(ctx context.Context, ...
method SearchSimilarDocuments (line 72) | func (s *embeddingService) SearchSimilarDocuments(ctx context.Context,...
method DeleteDocumentEmbeddings (line 83) | func (s *embeddingService) DeleteDocumentEmbeddings(ctx context.Contex...
method GetStats (line 91) | func (s *embeddingService) GetStats(ctx context.Context, orgID int32) ...
method hashContent (line 104) | func (s *embeddingService) hashContent(content string) string {
function NewEmbeddingService (line 24) | func NewEmbeddingService(
FILE: go-b2b-starter/internal/modules/cognitive/app/services/interface.go
type EmbeddingService (line 10) | type EmbeddingService interface
type RAGService (line 28) | type RAGService interface
type DocumentListener (line 49) | type DocumentListener interface
FILE: go-b2b-starter/internal/modules/cognitive/app/services/rag_service.go
constant DefaultMaxDocuments (line 13) | DefaultMaxDocuments = 3
constant DefaultContextHistory (line 15) | DefaultContextHistory = 10
constant SystemPrompt (line 17) | SystemPrompt = `You are a helpful assistant that answers questions based...
type ragService (line 22) | type ragService struct
method Chat (line 43) | func (s *ragService) Chat(ctx context.Context, orgID, accountID int32,...
method GetSession (line 155) | func (s *ragService) GetSession(ctx context.Context, orgID, sessionID ...
method ListSessions (line 159) | func (s *ragService) ListSessions(ctx context.Context, orgID, accountI...
method DeleteSession (line 163) | func (s *ragService) DeleteSession(ctx context.Context, orgID, session...
method GetSessionHistory (line 167) | func (s *ragService) GetSessionHistory(ctx context.Context, orgID, ses...
method UpdateSessionTitle (line 177) | func (s *ragService) UpdateSessionTitle(ctx context.Context, orgID, se...
method buildRAGPrompt (line 182) | func (s *ragService) buildRAGPrompt(query string, docs []*domain.Simil...
method buildPromptWithHistory (line 203) | func (s *ragService) buildPromptWithHistory(prompt string, history []*...
function NewRAGService (line 29) | func NewRAGService(
function generateSessionTitle (line 228) | func generateSessionTitle(message string) string {
FILE: go-b2b-starter/internal/modules/cognitive/cmd/init.go
function Init (line 15) | func Init(container *dig.Container) error {
FILE: go-b2b-starter/internal/modules/cognitive/domain/ai_provider.go
type TextVectorizer (line 8) | type TextVectorizer interface
type AssistantProvider (line 16) | type AssistantProvider interface
type AssistantResponse (line 22) | type AssistantResponse struct
FILE: go-b2b-starter/internal/modules/cognitive/domain/entity.go
type ChatRole (line 8) | type ChatRole
constant ChatRoleUser (line 11) | ChatRoleUser ChatRole = "user"
constant ChatRoleAssistant (line 12) | ChatRoleAssistant ChatRole = "assistant"
constant ChatRoleSystem (line 13) | ChatRoleSystem ChatRole = "system"
type DocumentEmbedding (line 17) | type DocumentEmbedding struct
type SimilarDocument (line 30) | type SimilarDocument struct
type ChatSession (line 36) | type ChatSession struct
method GetID (line 45) | func (s *ChatSession) GetID() int32 {
method Validate (line 50) | func (s *ChatSession) Validate() error {
type ChatMessage (line 61) | type ChatMessage struct
method GetID (line 71) | func (m *ChatMessage) GetID() int32 {
method Validate (line 76) | func (m *ChatMessage) Validate() error {
method IsUserMessage (line 89) | func (m *ChatMessage) IsUserMessage() bool {
method IsAssistantMessage (line 93) | func (m *ChatMessage) IsAssistantMessage() bool {
type RAGContext (line 98) | type RAGContext struct
type ChatRequest (line 104) | type ChatRequest struct
type ChatResponse (line 113) | type ChatResponse struct
type EmbeddingStats (line 121) | type EmbeddingStats struct
type ChatStats (line 127) | type ChatStats struct
FILE: go-b2b-starter/internal/modules/cognitive/domain/repository.go
type EmbeddingRepository (line 6) | type EmbeddingRepository interface
type ChatRepository (line 27) | type ChatRepository interface
FILE: go-b2b-starter/internal/modules/cognitive/handler.go
type Handler (line 15) | type Handler struct
method Chat (line 47) | func (h *Handler) Chat(c *gin.Context) {
method ListSessions (line 100) | func (h *Handler) ListSessions(c *gin.Context) {
method GetSessionHistory (line 142) | func (h *Handler) GetSessionHistory(c *gin.Context) {
function NewHandler (line 20) | func NewHandler(ragService services.RAGService, embeddingService service...
type ChatRequest (line 28) | type ChatRequest struct
FILE: go-b2b-starter/internal/modules/cognitive/infra/ai/assistant_provider.go
type openAIAssistantProvider (line 10) | type openAIAssistantProvider struct
method GenerateResponse (line 19) | func (p *openAIAssistantProvider) GenerateResponse(ctx context.Context...
function NewAssistantProvider (line 15) | func NewAssistantProvider(llmClient llmdomain.LLMClient) domain.Assistan...
FILE: go-b2b-starter/internal/modules/cognitive/infra/ai/text_vectorizer.go
constant embeddingModel (line 10) | embeddingModel = "text-embedding-3-small"
type openAITextVectorizer (line 12) | type openAITextVectorizer struct
method Vectorize (line 20) | func (v *openAITextVectorizer) Vectorize(ctx context.Context, text str...
function NewTextVectorizer (line 16) | func NewTextVectorizer(llmClient llmdomain.LLMClient) domain.TextVectori...
FILE: go-b2b-starter/internal/modules/cognitive/infra/repositories/chat_repository.go
type chatRepository (line 14) | type chatRepository struct
method CreateSession (line 25) | func (r *chatRepository) CreateSession(ctx context.Context, session *d...
method GetSessionByID (line 40) | func (r *chatRepository) GetSessionByID(ctx context.Context, orgID, se...
method ListSessionsByAccount (line 54) | func (r *chatRepository) ListSessionsByAccount(ctx context.Context, or...
method UpdateSessionTitle (line 75) | func (r *chatRepository) UpdateSessionTitle(ctx context.Context, orgID...
method DeleteSession (line 90) | func (r *chatRepository) DeleteSession(ctx context.Context, orgID, ses...
method CreateMessage (line 105) | func (r *chatRepository) CreateMessage(ctx context.Context, message *d...
method GetMessagesBySession (line 122) | func (r *chatRepository) GetMessagesBySession(ctx context.Context, ses...
method GetRecentMessages (line 136) | func (r *chatRepository) GetRecentMessages(ctx context.Context, sessio...
method CountMessagesBySession (line 155) | func (r *chatRepository) CountMessagesBySession(ctx context.Context, s...
method DeleteMessage (line 164) | func (r *chatRepository) DeleteMessage(ctx context.Context, messageID ...
method mapSessionToDomain (line 174) | func (r *chatRepository) mapSessionToDomain(s *sqlc.CognitiveChatSessi...
method mapMessageToDomain (line 187) | func (r *chatRepository) mapMessageToDomain(m *sqlc.CognitiveChatMessa...
function NewChatRepository (line 19) | func NewChatRepository(store sqlc.Store) domain.ChatRepository {
FILE: go-b2b-starter/internal/modules/cognitive/infra/repositories/embedding_repository.go
type embeddingRepository (line 14) | type embeddingRepository struct
method Create (line 23) | func (r *embeddingRepository) Create(ctx context.Context, embedding *d...
method GetByID (line 41) | func (r *embeddingRepository) GetByID(ctx context.Context, orgID, embe...
method GetByDocumentID (line 55) | func (r *embeddingRepository) GetByDocumentID(ctx context.Context, org...
method SearchSimilar (line 74) | func (r *embeddingRepository) SearchSimilar(ctx context.Context, orgID...
method Delete (line 106) | func (r *embeddingRepository) Delete(ctx context.Context, orgID, docum...
method Count (line 119) | func (r *embeddingRepository) Count(ctx context.Context, orgID int32) ...
method mapToDomain (line 130) | func (r *embeddingRepository) mapToDomain(e *sqlc.CognitiveDocumentEmb...
function NewEmbeddingRepository (line 19) | func NewEmbeddingRepository(store sqlc.Store) domain.EmbeddingRepository {
FILE: go-b2b-starter/internal/modules/cognitive/infra/repositories/helpers.go
function toPgText (line 7) | func toPgText(s string) pgtype.Text {
function fromPgText (line 14) | func fromPgText(t pgtype.Text) string {
function toPgInt4 (line 21) | func toPgInt4(i int32) pgtype.Int4 {
function fromPgInt4 (line 28) | func fromPgInt4(i pgtype.Int4) int32 {
FILE: go-b2b-starter/internal/modules/cognitive/module.go
type Module (line 13) | type Module struct
method RegisterDependencies (line 25) | func (m *Module) RegisterDependencies() error {
function NewModule (line 17) | func NewModule(container *dig.Container) *Module {
FILE: go-b2b-starter/internal/modules/cognitive/provider.go
type Provider (line 7) | type Provider struct
method RegisterDependencies (line 15) | func (p *Provider) RegisterDependencies() error {
function NewProvider (line 11) | func NewProvider(container *dig.Container) *Provider {
FILE: go-b2b-starter/internal/modules/cognitive/routes.go
type Routes (line 10) | type Routes struct
method RegisterRoutes (line 20) | func (r *Routes) RegisterRoutes(router *gin.RouterGroup, resolver serv...
method Routes (line 48) | func (r *Routes) Routes(router *gin.RouterGroup, resolver serverDomain...
function NewRoutes (line 14) | func NewRoutes(handler *Handler) *Routes {
FILE: go-b2b-starter/internal/modules/documents/app/services/document_service.go
type documentService (line 21) | type documentService struct
method UploadDocument (line 45) | func (s *documentService) UploadDocument(ctx context.Context, orgID in...
method GetDocument (line 101) | func (s *documentService) GetDocument(ctx context.Context, orgID, docI...
method ListDocuments (line 110) | func (s *documentService) ListDocuments(ctx context.Context, orgID int...
method UpdateDocument (line 141) | func (s *documentService) UpdateDocument(ctx context.Context, orgID, d...
method DeleteDocument (line 164) | func (s *documentService) DeleteDocument(ctx context.Context, orgID, d...
method GetDocumentStats (line 184) | func (s *documentService) GetDocumentStats(ctx context.Context, orgID ...
method ProcessDocument (line 213) | func (s *documentService) ProcessDocument(ctx context.Context, orgID, ...
method markDocumentFailed (line 252) | func (s *documentService) markDocumentFailed(ctx context.Context, orgI...
method extractTextFromPDF (line 261) | func (s *documentService) extractTextFromPDF(content io.Reader) (strin...
function NewDocumentService (line 29) | func NewDocumentService(
FILE: go-b2b-starter/internal/modules/documents/app/services/interface.go
type DocumentService (line 11) | type DocumentService interface
type UploadDocumentRequest (line 35) | type UploadDocumentRequest struct
type ListDocumentsRequest (line 44) | type ListDocumentsRequest struct
type ListDocumentsResponse (line 51) | type ListDocumentsResponse struct
type UpdateDocumentRequest (line 59) | type UpdateDocumentRequest struct
FILE: go-b2b-starter/internal/modules/documents/cmd/init.go
function Init (line 9) | func Init(container *dig.Container) error {
FILE: go-b2b-starter/internal/modules/documents/domain/entity.go
type DocumentStatus (line 8) | type DocumentStatus
constant DocumentStatusPending (line 11) | DocumentStatusPending DocumentStatus = "pending"
constant DocumentStatusProcessing (line 12) | DocumentStatusProcessing DocumentStatus = "processing"
constant DocumentStatusProcessed (line 13) | DocumentStatusProcessed DocumentStatus = "processed"
constant DocumentStatusFailed (line 14) | DocumentStatusFailed DocumentStatus = "failed"
type Document (line 18) | type Document struct
method GetID (line 33) | func (d *Document) GetID() int32 {
method Validate (line 38) | func (d *Document) Validate() error {
method IsProcessed (line 54) | func (d *Document) IsProcessed() bool {
method IsPending (line 58) | func (d *Document) IsPending() bool {
method HasText (line 62) | func (d *Document) HasText() bool {
type DocumentUploadRequest (line 67) | type DocumentUploadRequest struct
type DocumentFilter (line 77) | type DocumentFilter struct
type DocumentStats (line 82) | type DocumentStats struct
FILE: go-b2b-starter/internal/modules/documents/domain/events/document_events.go
constant DocumentUploadedEventType (line 11) | DocumentUploadedEventType = "document.uploaded"
constant DocumentProcessedEventType (line 12) | DocumentProcessedEventType = "document.processed"
constant DocumentFailedEventType (line 13) | DocumentFailedEventType = "document.failed"
type DocumentUploaded (line 17) | type DocumentUploaded struct
function NewDocumentUploaded (line 26) | func NewDocumentUploaded(documentID, organizationID, fileAssetID int32, ...
type DocumentProcessed (line 43) | type DocumentProcessed struct
function NewDocumentProcessed (line 50) | func NewDocumentProcessed(documentID, organizationID, embeddingID int32)...
type DocumentFailed (line 65) | type DocumentFailed struct
function NewDocumentFailed (line 72) | func NewDocumentFailed(documentID, organizationID int32, err string) *Do...
FILE: go-b2b-starter/internal/modules/documents/domain/repository.go
type DocumentRepository (line 6) | type DocumentRepository interface
FILE: go-b2b-starter/internal/modules/documents/handler.go
type Handler (line 16) | type Handler struct
method UploadDocument (line 36) | func (h *Handler) UploadDocument(c *gin.Context) {
method ListDocuments (line 98) | func (h *Handler) ListDocuments(c *gin.Context) {
method DeleteDocument (line 142) | func (h *Handler) DeleteDocument(c *gin.Context) {
function NewHandler (line 20) | func NewHandler(service services.DocumentService) *Handler {
FILE: go-b2b-starter/internal/modules/documents/infra/repositories/document_repository.go
type documentRepository (line 14) | type documentRepository struct
method Create (line 23) | func (r *documentRepository) Create(ctx context.Context, doc *domain.D...
method GetByID (line 44) | func (r *documentRepository) GetByID(ctx context.Context, orgID, docID...
method GetByFileAssetID (line 58) | func (r *documentRepository) GetByFileAssetID(ctx context.Context, org...
method List (line 72) | func (r *documentRepository) List(ctx context.Context, orgID int32, li...
method ListByStatus (line 92) | func (r *documentRepository) ListByStatus(ctx context.Context, orgID i...
method UpdateStatus (line 113) | func (r *documentRepository) UpdateStatus(ctx context.Context, orgID, ...
method UpdateExtractedText (line 128) | func (r *documentRepository) UpdateExtractedText(ctx context.Context, ...
method Update (line 143) | func (r *documentRepository) Update(ctx context.Context, doc *domain.D...
method Delete (line 159) | func (r *documentRepository) Delete(ctx context.Context, orgID, docID ...
method Count (line 172) | func (r *documentRepository) Count(ctx context.Context, orgID int32) (...
method CountByStatus (line 181) | func (r *documentRepository) CountByStatus(ctx context.Context, orgID ...
method mapToDomain (line 197) | func (r *documentRepository) mapToDomain(doc *sqlc.DocumentsDocument) ...
function NewDocumentRepository (line 19) | func NewDocumentRepository(store sqlc.Store) domain.DocumentRepository {
FILE: go-b2b-starter/internal/modules/documents/module.go
type Module (line 15) | type Module struct
method RegisterDependencies (line 27) | func (m *Module) RegisterDependencies() error {
function NewModule (line 19) | func NewModule(container *dig.Container) *Module {
FILE: go-b2b-starter/internal/modules/documents/provider.go
type Provider (line 7) | type Provider struct
method RegisterDependencies (line 15) | func (p *Provider) RegisterDependencies() error {
function NewProvider (line 11) | func NewProvider(container *dig.Container) *Provider {
FILE: go-b2b-starter/internal/modules/documents/routes.go
type Routes (line 10) | type Routes struct
method RegisterRoutes (line 20) | func (r *Routes) RegisterRoutes(router *gin.RouterGroup, resolver serv...
method Routes (line 46) | func (r *Routes) Routes(router *gin.RouterGroup, resolver serverDomain...
function NewRoutes (line 14) | func NewRoutes(handler *Handler) *Routes {
FILE: go-b2b-starter/internal/modules/files/cmd/init.go
function Init (line 10) | func Init(container *dig.Container) {
FILE: go-b2b-starter/internal/modules/files/cmd/provider.go
function SetupDependencies (line 15) | func SetupDependencies(container *dig.Container) error {
function isPlaceholderR2Credentials (line 52) | func isPlaceholderR2Credentials(cfg *config.Config) bool {
FILE: go-b2b-starter/internal/modules/files/config/config.go
type Config (line 7) | type Config struct
type R2Config (line 11) | type R2Config struct
function LoadConfig (line 19) | func LoadConfig() (*Config, error) {
FILE: go-b2b-starter/internal/modules/files/constants.go
type FileCategory (line 8) | type FileCategory
constant CategoryDocument (line 11) | CategoryDocument FileCategory = "document"
constant CategoryImage (line 12) | CategoryImage FileCategory = "image"
constant CategoryArchive (line 13) | CategoryArchive FileCategory = "archive"
type FileContext (line 27) | type FileContext
constant ContextInvoice (line 30) | ContextInvoice FileContext = "invoice"
constant ContextReceipt (line 31) | ContextReceipt FileContext = "receipt"
constant ContextContract (line 32) | ContextContract FileContext = "contract"
constant ContextReport (line 33) | ContextReport FileContext = "report"
constant ContextProfile (line 34) | ContextProfile FileContext = "profile"
constant ContextGeneral (line 35) | ContextGeneral FileContext = "general"
constant ContextPaymentInstruction (line 36) | ContextPaymentInstruction FileContext = "payment_instruction"
constant ContextPaymentBatch (line 37) | ContextPaymentBatch FileContext = "payment_batch"
constant MaxDocumentSize (line 43) | MaxDocumentSize = 2 * 1024 * 1024
constant MaxImageSize (line 44) | MaxImageSize = 1 * 1024 * 1024
constant MaxArchiveSize (line 45) | MaxArchiveSize = 0
function GetFileCategory (line 49) | func GetFileCategory(filename string) FileCategory {
function GetMaxFileSize (line 74) | func GetMaxFileSize(category FileCategory) int64 {
function IsAllowedFileType (line 86) | func IsAllowedFileType(filename string) bool {
function getFileExtension (line 101) | func getFileExtension(filename string) string {
FILE: go-b2b-starter/internal/modules/files/domain/entity.go
type FileAsset (line 10) | type FileAsset struct
type FileUploadRequest (line 31) | type FileUploadRequest struct
type FileSearchFilter (line 39) | type FileSearchFilter struct
FILE: go-b2b-starter/internal/modules/files/domain/helpers.go
function ConvertFileToBase64 (line 12) | func ConvertFileToBase64(ctx context.Context, repo FileRepository, fileI...
function ConvertReaderToBase64 (line 32) | func ConvertReaderToBase64(content io.Reader, contentType string) (strin...
function formatAsDataURI (line 44) | func formatAsDataURI(data []byte, contentType string) string {
FILE: go-b2b-starter/internal/modules/files/domain/repository.go
type FileRepository (line 10) | type FileRepository interface
type R2Repository (line 27) | type R2Repository interface
type FileMetadataRepository (line 36) | type FileMetadataRepository interface
FILE: go-b2b-starter/internal/modules/files/domain/service.go
type FileService (line 13) | type FileService interface
type fileService (line 22) | type fileService struct
method UploadFile (line 32) | func (s *fileService) UploadFile(ctx context.Context, req *FileUploadR...
method DownloadFile (line 94) | func (s *fileService) DownloadFile(ctx context.Context, id int32) (io....
method GetFile (line 103) | func (s *fileService) GetFile(ctx context.Context, id int32) (*FileAss...
method DeleteFile (line 107) | func (s *fileService) DeleteFile(ctx context.Context, id int32) error {
method ListFiles (line 120) | func (s *fileService) ListFiles(ctx context.Context, filter *FileSearc...
method GetFileURL (line 124) | func (s *fileService) GetFileURL(ctx context.Context, id int32, expiry...
function NewFileService (line 26) | func NewFileService(repo FileRepository) FileService {
function generateFilePath (line 165) | func generateFilePath(category files.FileCategory, context files.FileCon...
FILE: go-b2b-starter/internal/modules/files/domain/validator.go
function ValidateFileContent (line 15) | func ValidateFileContent(reader io.Reader, filename string) error {
function getAllowedMIMETypes (line 43) | func getAllowedMIMETypes(ext string) ([]string, bool) {
function SanitizeFilename (line 66) | func SanitizeFilename(filename string) string {
function IsInvoiceFileType (line 115) | func IsInvoiceFileType(filename string) bool {
FILE: go-b2b-starter/internal/modules/files/infra/file_metadata_repository.go
type fileMetadataRepository (line 18) | type fileMetadataRepository struct
method Create (line 27) | func (r *fileMetadataRepository) Create(ctx context.Context, file *dom...
method GetByID (line 69) | func (r *fileMetadataRepository) GetByID(ctx context.Context, id int32...
method Update (line 78) | func (r *fileMetadataRepository) Update(ctx context.Context, file *dom...
method Delete (line 95) | func (r *fileMetadataRepository) Delete(ctx context.Context, id int32)...
method List (line 99) | func (r *fileMetadataRepository) List(ctx context.Context, filter *dom...
method GetByStoragePath (line 118) | func (r *fileMetadataRepository) GetByStoragePath(ctx context.Context,...
method GetByCategory (line 127) | func (r *fileMetadataRepository) GetByCategory(ctx context.Context, ca...
method GetByContext (line 141) | func (r *fileMetadataRepository) GetByContext(ctx context.Context, fil...
method GetByEntity (line 155) | func (r *fileMetadataRepository) GetByEntity(ctx context.Context, enti...
method getCategoryID (line 176) | func (r *fileMetadataRepository) getCategoryID(ctx context.Context, ca...
method getContextID (line 191) | func (r *fileMetadataRepository) getContextID(ctx context.Context, fil...
method convertFromDBModel (line 208) | func (r *fileMetadataRepository) convertFromDBModel(dbFile *sqlc.FileM...
method convertFromListRow (line 253) | func (r *fileMetadataRepository) convertFromListRow(row *sqlc.ListFile...
method convertFromCategoryRow (line 300) | func (r *fileMetadataRepository) convertFromCategoryRow(row *sqlc.GetF...
method convertFromContextRow (line 346) | func (r *fileMetadataRepository) convertFromContextRow(row *sqlc.GetFi...
function NewFileMetadataRepository (line 23) | func NewFileMetadataRepository(store sqlc.Store) domain.FileMetadataRepo...
FILE: go-b2b-starter/internal/modules/files/internal/infra/composite_repository.go
type compositeRepository (line 14) | type compositeRepository struct
method Upload (line 28) | func (r *compositeRepository) Upload(ctx context.Context, file *domain...
method Download (line 101) | func (r *compositeRepository) Download(ctx context.Context, id int32) ...
method GetByID (line 117) | func (r *compositeRepository) GetByID(ctx context.Context, id int32) (...
method Delete (line 121) | func (r *compositeRepository) Delete(ctx context.Context, id int32) er...
method List (line 143) | func (r *compositeRepository) List(ctx context.Context, filter *domain...
method GetURL (line 147) | func (r *compositeRepository) GetURL(ctx context.Context, id int32, ex...
method Exists (line 195) | func (r *compositeRepository) Exists(ctx context.Context, id int32) (b...
method GetByCategory (line 249) | func (r *compositeRepository) GetByCategory(ctx context.Context, categ...
method GetByContext (line 253) | func (r *compositeRepository) GetByContext(ctx context.Context, contex...
method GetByEntity (line 257) | func (r *compositeRepository) GetByEntity(ctx context.Context, entityT...
method generateStoragePath (line 262) | func (r *compositeRepository) generateStoragePath(category file_manage...
method generateObjectKey (line 267) | func (r *compositeRepository) generateObjectKey(id int32, filename str...
function NewCompositeRepository (line 20) | func NewCompositeRepository(cfg *config.Config, r2Repo domain.R2Reposito...
FILE: go-b2b-starter/internal/modules/files/internal/infra/db_repository.go
type dbRepository (line 17) | type dbRepository struct
method Create (line 27) | func (r *dbRepository) Create(ctx context.Context, file *domain.FileAs...
method GetByID (line 69) | func (r *dbRepository) GetByID(ctx context.Context, id int32) (*domain...
method Update (line 104) | func (r *dbRepository) Update(ctx context.Context, file *domain.FileAs...
method Delete (line 143) | func (r *dbRepository) Delete(ctx context.Context, id int32) error {
method List (line 147) | func (r *dbRepository) List(ctx context.Context, filter *domain.FileSe...
method GetByStoragePath (line 166) | func (r *dbRepository) GetByStoragePath(ctx context.Context, storagePa...
method GetByCategory (line 175) | func (r *dbRepository) GetByCategory(ctx context.Context, category str...
method GetByContext (line 189) | func (r *dbRepository) GetByContext(ctx context.Context, context strin...
method GetByEntity (line 203) | func (r *dbRepository) GetByEntity(ctx context.Context, entityType str...
method getCategoryID (line 223) | func (r *dbRepository) getCategoryID(ctx context.Context, category fil...
method getContextID (line 238) | func (r *dbRepository) getContextID(ctx context.Context, context file_...
method convertFromDBModel (line 253) | func (r *dbRepository) convertFromDBModel(dbFile *sqlc.FileManagerFile...
method convertFromListRow (line 298) | func (r *dbRepository) convertFromListRow(row *sqlc.ListFileAssetsRow)...
method convertFromCategoryRow (line 345) | func (r *dbRepository) convertFromCategoryRow(row *sqlc.GetFileAssetsB...
method convertFromContextRow (line 391) | func (r *dbRepository) convertFromContextRow(row *sqlc.GetFileAssetsBy...
function NewDBRepository (line 21) | func NewDBRepository(store adapters.FileAssetStore) domain.FileMetadataR...
FILE: go-b2b-starter/internal/modules/files/internal/infra/mock_r2_repository.go
type mockR2Repository (line 13) | type mockR2Repository struct
method UploadObject (line 25) | func (m *mockR2Repository) UploadObject(ctx context.Context, objectKey...
method DownloadObject (line 38) | func (m *mockR2Repository) DownloadObject(ctx context.Context, objectK...
method DeleteObject (line 47) | func (m *mockR2Repository) DeleteObject(ctx context.Context, objectKey...
method GetPresignedURL (line 55) | func (m *mockR2Repository) GetPresignedURL(ctx context.Context, object...
method ObjectExists (line 65) | func (m *mockR2Repository) ObjectExists(ctx context.Context, objectKey...
function NewMockR2Repository (line 19) | func NewMockR2Repository(log logger.Logger) domain.R2Repository {
FILE: go-b2b-starter/internal/modules/files/internal/infra/r2_repository.go
type r2Repository (line 20) | type r2Repository struct
method ensureBucket (line 63) | func (r *r2Repository) ensureBucket(ctx context.Context) error {
method UploadObject (line 76) | func (r *r2Repository) UploadObject(ctx context.Context, objectKey str...
method DownloadObject (line 93) | func (r *r2Repository) DownloadObject(ctx context.Context, objectKey s...
method DeleteObject (line 106) | func (r *r2Repository) DeleteObject(ctx context.Context, objectKey str...
method GetPresignedURL (line 120) | func (r *r2Repository) GetPresignedURL(ctx context.Context, objectKey ...
method ObjectExists (line 140) | func (r *r2Repository) ObjectExists(ctx context.Context, objectKey str...
function NewR2Repository (line 25) | func NewR2Repository(cfg *fileconfig.Config) (domain.R2Repository, error) {
FILE: go-b2b-starter/internal/modules/organizations/account_handler.go
type AccountHandler (line 16) | type AccountHandler struct
method CreateAccount (line 29) | func (h *AccountHandler) CreateAccount(c *gin.Context) {
method GetAccount (line 60) | func (h *AccountHandler) GetAccount(c *gin.Context) {
method GetAccountByEmail (line 92) | func (h *AccountHandler) GetAccountByEmail(c *gin.Context) {
method ListAccounts (line 121) | func (h *AccountHandler) ListAccounts(c *gin.Context) {
method UpdateAccount (line 144) | func (h *AccountHandler) UpdateAccount(c *gin.Context) {
method DeleteAccount (line 183) | func (h *AccountHandler) DeleteAccount(c *gin.Context) {
method UpdateAccountLastLogin (line 215) | func (h *AccountHandler) UpdateAccountLastLogin(c *gin.Context) {
method CheckAccountPermission (line 246) | func (h *AccountHandler) CheckAccountPermission(c *gin.Context) {
method GetAccountStats (line 278) | func (h *AccountHandler) GetAccountStats(c *gin.Context) {
function NewAccountHandler (line 21) | func NewAccountHandler(orgService services.OrganizationService, logger l...
FILE: go-b2b-starter/internal/modules/organizations/app/services/member_service.go
type MemberService (line 11) | type MemberService interface
type BootstrapOrganizationRequest (line 39) | type BootstrapOrganizationRequest struct
method Validate (line 49) | func (r *BootstrapOrganizationRequest) Validate() error {
type BootstrapOrganizationResponse (line 63) | type BootstrapOrganizationResponse struct
type AddMemberRequest (line 75) | type AddMemberRequest struct
method Validate (line 88) | func (r *AddMemberRequest) Validate() error {
type AddMemberResponse (line 100) | type AddMemberResponse struct
type MemberInfo (line 110) | type MemberInfo struct
type ListMembersResponse (line 122) | type ListMembersResponse struct
type ProfileResponse (line 129) | type ProfileResponse struct
type ProfileOrganization (line 149) | type ProfileOrganization struct
type CheckEmailRequest (line 158) | type CheckEmailRequest struct
FILE: go-b2b-starter/internal/modules/organizations/app/services/member_service_impl.go
type rollbackFunc (line 14) | type rollbackFunc
type rollbackStack (line 17) | type rollbackStack
method add (line 20) | func (rs *rollbackStack) add(fn rollbackFunc) {
method execute (line 25) | func (rs rollbackStack) execute(ctx context.Context, logger loggerDoma...
type memberService (line 38) | type memberService struct
method BootstrapOrganizationWithOwner (line 67) | func (s *memberService) BootstrapOrganizationWithOwner(
method AddMemberDirect (line 263) | func (s *memberService) AddMemberDirect(
method ListOrganizationMembers (line 362) | func (s *memberService) ListOrganizationMembers(
method GetCurrentUserProfile (line 407) | func (s *memberService) GetCurrentUserProfile(
method DeleteOrganizationMember (line 495) | func (s *memberService) DeleteOrganizationMember(
method CheckEmailExists (line 534) | func (s *memberService) CheckEmailExists(ctx context.Context, email st...
method resolveLocalOrganizationID (line 563) | func (s *memberService) resolveLocalOrganizationID(ctx context.Context...
function NewMemberService (line 47) | func NewMemberService(
function mapRoleSlugToAccountRole (line 571) | func mapRoleSlugToAccountRole(slug string) string {
FILE: go-b2b-starter/internal/modules/organizations/app/services/organization_service.go
type organizationService (line 10) | type organizationService struct
method CreateOrganization (line 22) | func (s *organizationService) CreateOrganization(ctx context.Context, ...
method GetOrganization (line 65) | func (s *organizationService) GetOrganization(ctx context.Context, org...
method GetOrganizationBySlug (line 69) | func (s *organizationService) GetOrganizationBySlug(ctx context.Contex...
method GetOrganizationByStytchID (line 73) | func (s *organizationService) GetOrganizationByStytchID(ctx context.Co...
method GetOrganizationByUserEmail (line 77) | func (s *organizationService) GetOrganizationByUserEmail(ctx context.C...
method UpdateOrganization (line 81) | func (s *organizationService) UpdateOrganization(ctx context.Context, ...
method ListOrganizations (line 104) | func (s *organizationService) ListOrganizations(ctx context.Context, r...
method GetOrganizationStats (line 122) | func (s *organizationService) GetOrganizationStats(ctx context.Context...
method CreateAccount (line 126) | func (s *organizationService) CreateAccount(ctx context.Context, orgID...
method GetAccount (line 148) | func (s *organizationService) GetAccount(ctx context.Context, orgID, a...
method GetAccountByEmail (line 152) | func (s *organizationService) GetAccountByEmail(ctx context.Context, o...
method ListAccounts (line 156) | func (s *organizationService) ListAccounts(ctx context.Context, orgID ...
method UpdateAccount (line 166) | func (s *organizationService) UpdateAccount(ctx context.Context, orgID...
method DeleteAccount (line 190) | func (s *organizationService) DeleteAccount(ctx context.Context, orgID...
method UpdateAccountLastLogin (line 194) | func (s *organizationService) UpdateAccountLastLogin(ctx context.Conte...
method CheckAccountPermission (line 198) | func (s *organizationService) CheckAccountPermission(ctx context.Conte...
method GetAccountStats (line 202) | func (s *organizationService) GetAccountStats(ctx context.Context, acc...
function NewOrganizationService (line 15) | func NewOrganizationService(orgRepo domain.OrganizationRepository, accou...
FILE: go-b2b-starter/internal/modules/organizations/app/services/organization_service_interface.go
type OrganizationService (line 10) | type OrganizationService interface
type CreateOrganizationRequest (line 36) | type CreateOrganizationRequest struct
type UpdateOrganizationRequest (line 47) | type UpdateOrganizationRequest struct
type CreateAccountRequest (line 56) | type CreateAccountRequest struct
type UpdateAccountRequest (line 67) | type UpdateAccountRequest struct
type ListOrganizationsRequest (line 77) | type ListOrganizationsRequest struct
type ListOrganizationsResponse (line 83) | type ListOrganizationsResponse struct
FILE: go-b2b-starter/internal/modules/organizations/cmd/init.go
function Init (line 9) | func Init(container *dig.Container) error {
FILE: go-b2b-starter/internal/modules/organizations/domain/auth_provider.go
type AuthMember (line 10) | type AuthMember struct
type AuthOrganization (line 23) | type AuthOrganization struct
type AuthRole (line 33) | type AuthRole struct
type CreateAuthMemberRequest (line 41) | type CreateAuthMemberRequest struct
method Validate (line 88) | func (r *CreateAuthMemberRequest) Validate() error {
type UpdateAuthMemberRequest (line 51) | type UpdateAuthMemberRequest struct
method Validate (line 119) | func (r *UpdateAuthMemberRequest) Validate() error {
type CreateAuthOrganizationRequest (line 61) | type CreateAuthOrganizationRequest struct
method Validate (line 130) | func (r *CreateAuthOrganizationRequest) Validate() error {
type AssignAuthRolesRequest (line 67) | type AssignAuthRolesRequest struct
method Validate (line 141) | func (r *AssignAuthRolesRequest) Validate() error {
type RemoveAuthMembersRequest (line 74) | type RemoveAuthMembersRequest struct
method Validate (line 155) | func (r *RemoveAuthMembersRequest) Validate() error {
type SendMagicLinkRequest (line 80) | type SendMagicLinkRequest struct
method Validate (line 105) | func (r *SendMagicLinkRequest) Validate() error {
type AuthOrganizationRepository (line 166) | type AuthOrganizationRepository interface
type AuthMemberRepository (line 174) | type AuthMemberRepository interface
type AuthRoleRepository (line 186) | type AuthRoleRepository interface
FILE: go-b2b-starter/internal/modules/organizations/domain/entity.go
type Organization (line 6) | type Organization struct
method GetID (line 43) | func (o *Organization) GetID() int32 {
method Validate (line 48) | func (o *Organization) Validate() error {
type Account (line 19) | type Account struct
method GetID (line 62) | func (a *Account) GetID() int32 {
method Validate (line 67) | func (a *Account) Validate() error {
method IsOwner (line 81) | func (a *Account) IsOwner() bool {
method IsAdmin (line 86) | func (a *Account) IsAdmin() bool {
method CanManageAccounts (line 91) | func (a *Account) CanManageAccounts() bool {
type OrganizationContext (line 36) | type OrganizationContext struct
FILE: go-b2b-starter/internal/modules/organizations/domain/errors.go
type OrganizationError (line 69) | type OrganizationError struct
method Error (line 76) | func (e *OrganizationError) Error() string {
method Unwrap (line 80) | func (e *OrganizationError) Unwrap() error {
function NewOrganizationError (line 84) | func NewOrganizationError(errorType, message string, orgID *int32, cause...
type AccountError (line 94) | type AccountError struct
method Error (line 102) | func (e *AccountError) Error() string {
method Unwrap (line 106) | func (e *AccountError) Unwrap() error {
function NewAccountError (line 110) | func NewAccountError(errorType, message string, accountID, orgID *int32,...
FILE: go-b2b-starter/internal/modules/organizations/domain/events/organization_events.go
constant OrganizationCreatedEventType (line 10) | OrganizationCreatedEventType = "organization.created"
constant OrganizationUpdatedEventType (line 11) | OrganizationUpdatedEventType = "organization.updated"
constant AccountCreatedEventType (line 12) | AccountCreatedEventType = "account.created"
constant AccountUpdatedEventType (line 13) | AccountUpdatedEventType = "account.updated"
constant AccountDeletedEventType (line 14) | AccountDeletedEventType = "account.deleted"
constant AccountLoginEventType (line 15) | AccountLoginEventType = "account.login"
type OrganizationCreatedEvent (line 18) | type OrganizationCreatedEvent struct
type OrganizationUpdatedEvent (line 26) | type OrganizationUpdatedEvent struct
type AccountCreatedEvent (line 34) | type AccountCreatedEvent struct
type AccountUpdatedEvent (line 42) | type AccountUpdatedEvent struct
type AccountDeletedEvent (line 52) | type AccountDeletedEvent struct
type AccountLoginEvent (line 61) | type AccountLoginEvent struct
FILE: go-b2b-starter/internal/modules/organizations/domain/repository.go
type OrganizationRepository (line 6) | type OrganizationRepository interface
type AccountRepository (line 20) | type AccountRepository interface
type OrganizationStats (line 35) | type OrganizationStats struct
type AccountStats (line 42) | type AccountStats struct
type AccountPermission (line 49) | type AccountPermission struct
FILE: go-b2b-starter/internal/modules/organizations/infra/repositories/account_repository.go
type accountRepository (line 16) | type accountRepository struct
method Create (line 25) | func (r *accountRepository) Create(ctx context.Context, account *domai...
method GetByID (line 46) | func (r *accountRepository) GetByID(ctx context.Context, orgID, accoun...
method GetByEmail (line 63) | func (r *accountRepository) GetByEmail(ctx context.Context, orgID int3...
method ListByOrganization (line 80) | func (r *accountRepository) ListByOrganization(ctx context.Context, or...
method Update (line 94) | func (r *accountRepository) Update(ctx context.Context, account *domai...
method UpdateStytchInfo (line 117) | func (r *accountRepository) UpdateStytchInfo(ctx context.Context, orgI...
method UpdateLastLogin (line 138) | func (r *accountRepository) UpdateLastLogin(ctx context.Context, orgID...
method Delete (line 155) | func (r *accountRepository) Delete(ctx context.Context, orgID, account...
method GetOrganization (line 172) | func (r *accountRepository) GetOrganization(ctx context.Context, accou...
method CheckPermission (line 191) | func (r *accountRepository) CheckPermission(ctx context.Context, orgID...
method GetStats (line 213) | func (r *accountRepository) GetStats(ctx context.Context, accountID in...
method mapToDomain (line 252) | func (r *accountRepository) mapToDomain(sqlcAccount *sqlc.Organization...
function NewAccountRepository (line 21) | func NewAccountRepository(store sqlc.Store) domain.AccountRepository {
FILE: go-b2b-starter/internal/modules/organizations/infra/repositories/organization_repository.go
type organizationRepository (line 16) | type organizationRepository struct
method Create (line 25) | func (r *organizationRepository) Create(ctx context.Context, org *doma...
method GetByID (line 40) | func (r *organizationRepository) GetByID(ctx context.Context, id int32...
method GetBySlug (line 52) | func (r *organizationRepository) GetBySlug(ctx context.Context, slug s...
method GetByStytchID (line 64) | func (r *organizationRepository) GetByStytchID(ctx context.Context, st...
method GetByUserEmail (line 76) | func (r *organizationRepository) GetByUserEmail(ctx context.Context, e...
method Update (line 88) | func (r *organizationRepository) Update(ctx context.Context, org *doma...
method UpdateStytchInfo (line 109) | func (r *organizationRepository) UpdateStytchInfo(ctx context.Context,...
method List (line 128) | func (r *organizationRepository) List(ctx context.Context, limit, offs...
method Delete (line 147) | func (r *organizationRepository) Delete(ctx context.Context, id int32)...
method GetStats (line 154) | func (r *organizationRepository) GetStats(ctx context.Context, id int3...
method mapToDomain (line 186) | func (r *organizationRepository) mapToDomain(sqlcOrg *sqlc.Organizatio...
function NewOrganizationRepository (line 21) | func NewOrganizationRepository(store sqlc.Store) domain.OrganizationRepo...
FILE: go-b2b-starter/internal/modules/organizations/infra/repositories/slug_generator.go
function generateSlug (line 11) | func generateSlug(name string) string {
function generateSlugWithSuffix (line 42) | func generateSlugWithSuffix(baseSlug string, attempt int) string {
FILE: go-b2b-starter/internal/modules/organizations/infra/repositories/stytch_member_repository.go
type stytchMemberRepository (line 17) | type stytchMemberRepository struct
method CreateMember (line 32) | func (r *stytchMemberRepository) CreateMember(ctx context.Context, req...
method UpdateMember (line 58) | func (r *stytchMemberRepository) UpdateMember(ctx context.Context, req...
method GetMember (line 90) | func (r *stytchMemberRepository) GetMember(ctx context.Context, organi...
method GetMemberByEmail (line 109) | func (r *stytchMemberRepository) GetMemberByEmail(ctx context.Context,...
method ListMembers (line 128) | func (r *stytchMemberRepository) ListMembers(ctx context.Context, orga...
method RemoveMembers (line 173) | func (r *stytchMemberRepository) RemoveMembers(ctx context.Context, re...
method AssignRoles (line 191) | func (r *stytchMemberRepository) AssignRoles(ctx context.Context, req ...
method SendMagicLink (line 212) | func (r *stytchMemberRepository) SendMagicLink(ctx context.Context, re...
function NewStytchMemberRepository (line 24) | func NewStytchMemberRepository(client *stytchcfg.Client, cfg stytchcfg.C...
function mapToAuthMember (line 248) | func mapToAuthMember(src organizations.Member) *domain.AuthMember {
FILE: go-b2b-starter/internal/modules/organizations/infra/repositories/stytch_organization_repository.go
type stytchOrganizationRepository (line 16) | type stytchOrganizationRepository struct
method CreateOrganization (line 35) | func (r *stytchOrganizationRepository) CreateOrganization(ctx context....
method GetOrganization (line 109) | func (r *stytchOrganizationRepository) GetOrganization(ctx context.Con...
method DeleteOrganization (line 122) | func (r *stytchOrganizationRepository) DeleteOrganization(ctx context....
method CheckEmailExists (line 135) | func (r *stytchOrganizationRepository) CheckEmailExists(ctx context.Co...
function NewStytchOrganizationRepository (line 23) | func NewStytchOrganizationRepository(
function mapToAuthOrganization (line 169) | func mapToAuthOrganization(src organizations.Organization) *domain.AuthO...
FILE: go-b2b-starter/internal/modules/organizations/infra/repositories/stytch_role_repository.go
type stytchRoleRepository (line 13) | type stytchRoleRepository struct
method GetRoleByID (line 26) | func (r *stytchRoleRepository) GetRoleByID(ctx context.Context, roleID...
method GetRoleBySlug (line 43) | func (r *stytchRoleRepository) GetRoleBySlug(ctx context.Context, slug...
method ListRoles (line 60) | func (r *stytchRoleRepository) ListRoles(ctx context.Context, limit, o...
method findRole (line 91) | func (r *stytchRoleRepository) findRole(ctx context.Context, predicate...
method fetchPolicy (line 109) | func (r *stytchRoleRepository) fetchPolicy(ctx context.Context) (*rbac...
function NewStytchRoleRepository (line 19) | func NewStytchRoleRepository(client *stytchcfg.Client, logger loggerDoma...
function mapToAuthRole (line 117) | func mapToAuthRole(src *rbac.PolicyRole) *domain.AuthRole {
FILE: go-b2b-starter/internal/modules/organizations/member_handler.go
type MemberHandler (line 15) | type MemberHandler struct
method BootstrapOrganization (line 41) | func (h *MemberHandler) BootstrapOrganization(c *gin.Context) {
method AddMember (line 85) | func (h *MemberHandler) AddMember(c *gin.Context) {
method ListMembers (line 138) | func (h *MemberHandler) ListMembers(c *gin.Context) {
method GetProfile (line 175) | func (h *MemberHandler) GetProfile(c *gin.Context) {
method DeleteMember (line 234) | func (h *MemberHandler) DeleteMember(c *gin.Context) {
method CheckEmail (line 300) | func (h *MemberHandler) CheckEmail(c *gin.Context) {
function NewMemberHandler (line 20) | func NewMemberHandler(
FILE: go-b2b-starter/internal/modules/organizations/module.go
type Module (line 14) | type Module struct
method RegisterDependencies (line 26) | func (m *Module) RegisterDependencies() error {
function NewModule (line 18) | func NewModule(container *dig.Container) *Module {
FILE: go-b2b-starter/internal/modules/organizations/organization_handler.go
type OrganizationHandler (line 15) | type OrganizationHandler struct
method CreateOrganization (line 28) | func (h *OrganizationHandler) CreateOrganization(c *gin.Context) {
method GetOrganization (line 47) | func (h *OrganizationHandler) GetOrganization(c *gin.Context) {
method GetOrganizationBySlug (line 70) | func (h *OrganizationHandler) GetOrganizationBySlug(c *gin.Context) {
method UpdateOrganization (line 92) | func (h *OrganizationHandler) UpdateOrganization(c *gin.Context) {
method ListOrganizations (line 122) | func (h *OrganizationHandler) ListOrganizations(c *gin.Context) {
method GetOrganizationStats (line 146) | func (h *OrganizationHandler) GetOrganizationStats(c *gin.Context) {
function NewOrganizationHandler (line 20) | func NewOrganizationHandler(orgService services.OrganizationService, log...
FILE: go-b2b-starter/internal/modules/organizations/provider.go
type Provider (line 11) | type Provider struct
method RegisterDependencies (line 22) | func (p *Provider) RegisterDependencies() error {
function NewProvider (line 15) | func NewProvider(container *dig.Container) *Provider {
FILE: go-b2b-starter/internal/modules/organizations/routes.go
type Routes (line 10) | type Routes struct
method RegisterRoutes (line 29) | func (r *Routes) RegisterRoutes(router *gin.RouterGroup, resolver serv...
method Routes (line 100) | func (r *Routes) Routes(router *gin.RouterGroup, resolver serverDomain...
function NewRoutes (line 16) | func NewRoutes(
FILE: go-b2b-starter/internal/modules/paywall/cmd/init.go
function InitMiddleware (line 27) | func InitMiddleware(container *dig.Container) error {
function InitMiddlewareWithConfig (line 44) | func InitMiddlewareWithConfig(container *dig.Container, config *paywall....
function SetupMiddleware (line 52) | func SetupMiddleware(container *dig.Container) error {
function RegisterNamedMiddlewares (line 57) | func RegisterNamedMiddlewares(container *dig.Container) error {
FILE: go-b2b-starter/internal/modules/paywall/context.go
type contextKey (line 11) | type contextKey
constant subscriptionStatusKey (line 15) | subscriptionStatusKey contextKey = "subscription_status"
function SetSubscriptionStatus (line 22) | func SetSubscriptionStatus(c *gin.Context, status *SubscriptionStatus) {
function GetSubscriptionStatus (line 37) | func GetSubscriptionStatus(c *gin.Context) *SubscriptionStatus {
function MustGetSubscriptionStatus (line 50) | func MustGetSubscriptionStatus(c *gin.Context) *SubscriptionStatus {
function IsSubscriptionActive (line 68) | func IsSubscriptionActive(c *gin.Context) bool {
function WithSubscriptionStatus (line 79) | func WithSubscriptionStatus(ctx context.Context, status *SubscriptionSta...
function SubscriptionStatusFromContext (line 86) | func SubscriptionStatusFromContext(ctx context.Context) *SubscriptionSta...
FILE: go-b2b-starter/internal/modules/paywall/errors.go
function IsPaymentRequiredError (line 38) | func IsPaymentRequiredError(err error) bool {
function HTTPStatusCode (line 51) | func HTTPStatusCode(err error) int {
type ErrorResponse (line 65) | type ErrorResponse struct
FILE: go-b2b-starter/internal/modules/paywall/middleware.go
type MiddlewareConfig (line 12) | type MiddlewareConfig struct
function DefaultMiddlewareConfig (line 27) | func DefaultMiddlewareConfig() *MiddlewareConfig {
function defaultErrorHandler (line 36) | func defaultErrorHandler(c *gin.Context, statusCode int, response *Error...
type Middleware (line 43) | type Middleware struct
method RequireActiveSubscription (line 79) | func (m *Middleware) RequireActiveSubscription() gin.HandlerFunc {
method buildErrorResponse (line 145) | func (m *Middleware) buildErrorResponse(status *SubscriptionStatus) *E...
method OptionalSubscriptionStatus (line 200) | func (m *Middleware) OptionalSubscriptionStatus() gin.HandlerFunc {
function NewMiddleware (line 51) | func NewMiddleware(provider SubscriptionStatusProvider, config *Middlewa...
function RequireActiveSubscriptionFunc (line 182) | func RequireActiveSubscriptionFunc(provider SubscriptionStatusProvider) ...
FILE: go-b2b-starter/internal/modules/paywall/provider.go
type ServerMiddlewareRegistrar (line 12) | type ServerMiddlewareRegistrar interface
function SetupMiddleware (line 30) | func SetupMiddleware(container *dig.Container) error {
function SetupMiddlewareWithConfig (line 52) | func SetupMiddlewareWithConfig(container *dig.Container, config *Middlew...
function RegisterNamedMiddlewares (line 80) | func RegisterNamedMiddlewares(container *dig.Container) error {
FILE: go-b2b-starter/internal/modules/paywall/subscription.go
type SubscriptionStatusProvider (line 85) | type SubscriptionStatusProvider interface
type SubscriptionStatus (line 102) | type SubscriptionStatus struct
method IsTrialing (line 124) | func (s *SubscriptionStatus) IsTrialing() bool {
method IsPastDue (line 129) | func (s *SubscriptionStatus) IsPastDue() bool {
method IsCanceled (line 134) | func (s *SubscriptionStatus) IsCanceled() bool {
constant StatusActive (line 141) | StatusActive = "active"
constant StatusTrialing (line 142) | StatusTrialing = "trialing"
constant StatusPastDue (line 143) | StatusPastDue = "past_due"
constant StatusCanceled (line 144) | StatusCanceled = "canceled"
constant StatusUnpaid (line 145) | StatusUnpaid = "unpaid"
constant StatusNone (line 146) | StatusNone = "none"
function IsActiveStatus (line 151) | func IsActiveStatus(status string) bool {
FILE: go-b2b-starter/internal/platform/eventbus/bus.go
type EventBus (line 11) | type EventBus interface
type InMemoryEventBus (line 23) | type InMemoryEventBus struct
method Publish (line 39) | func (bus *InMemoryEventBus) Publish(ctx context.Context, event Event)...
method Subscribe (line 93) | func (bus *InMemoryEventBus) Subscribe(eventName string, handler Event...
method Unsubscribe (line 107) | func (bus *InMemoryEventBus) Unsubscribe(eventName string, handler Eve...
method Close (line 124) | func (bus *InMemoryEventBus) Close() error {
method GetSubscriberCount (line 134) | func (bus *InMemoryEventBus) GetSubscriberCount(eventName string) int {
function NewInMemoryEventBus (line 30) | func NewInMemoryEventBus(middleware ...EventMiddleware) EventBus {
FILE: go-b2b-starter/internal/platform/eventbus/cmd/init.go
function Init (line 5) | func Init(container *dig.Container) error {
FILE: go-b2b-starter/internal/platform/eventbus/cmd/provider.go
function ProvideEventBus (line 11) | func ProvideEventBus(container *dig.Container) error {
FILE: go-b2b-starter/internal/platform/eventbus/event.go
type Event (line 9) | type Event interface
type BaseEvent (line 21) | type BaseEvent struct
method EventName (line 28) | func (e BaseEvent) EventName() string {
method EventID (line 32) | func (e BaseEvent) EventID() string {
method Timestamp (line 36) | func (e BaseEvent) Timestamp() time.Time {
method Metadata (line 40) | func (e BaseEvent) Metadata() map[string]interface{} {
type EventHandler (line 45) | type EventHandler
type EventMiddleware (line 48) | type EventMiddleware
FILE: go-b2b-starter/internal/platform/eventbus/events.go
type InvoiceUploaded (line 13) | type InvoiceUploaded struct
function NewInvoiceUploaded (line 22) | func NewInvoiceUploaded(invoiceID, fileID, userID int32, vendorName stri...
type InvoiceValidated (line 38) | type InvoiceValidated struct
function NewInvoiceValidated (line 45) | func NewInvoiceValidated(invoiceID, fileID int32, validationData map[str...
type OCRRequested (line 60) | type OCRRequested struct
function NewOCRRequested (line 66) | func NewOCRRequested(invoiceID, fileID int32) *OCRRequested {
type TextExtracted (line 79) | type TextExtracted struct
function NewTextExtracted (line 87) | func NewTextExtracted(invoiceID, fileID int32, extractedData map[string]...
type DuplicateCheckRequested (line 103) | type DuplicateCheckRequested struct
function NewDuplicateCheckRequested (line 109) | func NewDuplicateCheckRequested(invoiceID int32, data map[string]interfa...
type DuplicateDetected (line 122) | type DuplicateDetected struct
function NewDuplicateDetected (line 130) | func NewDuplicateDetected(invoiceID, duplicateOf int32, similarityScore ...
type UniqueConfirmed (line 145) | type UniqueConfirmed struct
function NewUniqueConfirmed (line 150) | func NewUniqueConfirmed(invoiceID int32) *UniqueConfirmed {
type ApprovalRequested (line 163) | type ApprovalRequested struct
function NewApprovalRequested (line 172) | func NewApprovalRequested(invoiceID, vendorID, requesterID int32, amount...
type ApprovalGranted (line 188) | type ApprovalGranted struct
function NewApprovalGranted (line 196) | func NewApprovalGranted(invoiceID, approverID, approvalID int32, comment...
type ApprovalRejected (line 211) | type ApprovalRejected struct
function NewApprovalRejected (line 219) | func NewApprovalRejected(invoiceID, approverID, approvalID int32, reason...
type PaymentScheduled (line 235) | type PaymentScheduled struct
function NewPaymentScheduled (line 245) | func NewPaymentScheduled(invoiceID, paymentID int32, scheduledDate time....
type PaymentExecuted (line 262) | type PaymentExecuted struct
function NewPaymentExecuted (line 273) | func NewPaymentExecuted(invoiceID, paymentID, organizationID int32, tran...
FILE: go-b2b-starter/internal/platform/eventbus/middleware.go
function LoggingMiddleware (line 13) | func LoggingMiddleware(logger domain.Logger) EventMiddleware {
function RecoveryMiddleware (line 47) | func RecoveryMiddleware(logger domain.Logger) EventMiddleware {
function getMapKeys (line 78) | func getMapKeys(m map[string]interface{}) []string {
function MetricsMiddleware (line 87) | func MetricsMiddleware() EventMiddleware {
FILE: go-b2b-starter/internal/platform/llm/cmd/init.go
function Init (line 11) | func Init(container *dig.Container) error {
FILE: go-b2b-starter/internal/platform/llm/domain/service.go
type CompletionRequest (line 5) | type CompletionRequest struct
type CompletionResponse (line 11) | type CompletionResponse struct
type EmbeddingRequest (line 17) | type EmbeddingRequest struct
type EmbeddingResponse (line 22) | type EmbeddingResponse struct
type StreamChunk (line 28) | type StreamChunk struct
type LLMService (line 33) | type LLMService interface
type LLMClient (line 38) | type LLMClient interface
FILE: go-b2b-starter/internal/platform/llm/infra/openai_client.go
type Config (line 23) | type Config struct
method Validate (line 33) | func (c Config) Validate() error {
type CircuitBreaker (line 44) | type CircuitBreaker struct
method CanExecute (line 63) | func (cb *CircuitBreaker) CanExecute() bool {
method RecordSuccess (line 84) | func (cb *CircuitBreaker) RecordSuccess() {
method RecordFailure (line 96) | func (cb *CircuitBreaker) RecordFailure() {
method GetStats (line 109) | func (cb *CircuitBreaker) GetStats() map[string]interface{} {
function NewCircuitBreaker (line 54) | func NewCircuitBreaker(maxFailures int, resetTimeout time.Duration) *Cir...
type OpenAIClient (line 121) | type OpenAIClient struct
method Complete (line 260) | func (c *OpenAIClient) Complete(ctx context.Context, request domain.Co...
method CompleteStream (line 427) | func (c *OpenAIClient) CompleteStream(ctx context.Context, request dom...
method makeRequest (line 527) | func (c *OpenAIClient) makeRequest(ctx context.Context, request openAI...
method GenerateEmbedding (line 659) | func (c *OpenAIClient) GenerateEmbedding(ctx context.Context, text str...
method makeStreamRequest (line 756) | func (c *OpenAIClient) makeStreamRequest(ctx context.Context, request ...
type openAIRequest (line 128) | type openAIRequest struct
type ToolCall (line 137) | type ToolCall struct
type openAIMessage (line 146) | type openAIMessage struct
type openAIResponse (line 153) | type openAIResponse struct
type openAIChoice (line 163) | type openAIChoice struct
type CompletionTokensDetails (line 169) | type CompletionTokensDetails struct
type openAIUsage (line 173) | type openAIUsage struct
type openAIError (line 181) | type openAIError struct
function NewLLMConfig (line 188) | func NewLLMConfig() Config {
function NewOpenAIClient (line 206) | func NewOpenAIClient(config Config, logger loggerDomain.Logger) (domain....
function getEnvOrDefault (line 641) | func getEnvOrDefault(key, defaultValue string) string {
function supportsTemperature (line 648) | func supportsTemperature(model string) bool {
function supportsStop (line 653) | func supportsStop(model string) bool {
type streamResponse (line 741) | type streamResponse struct
function generateJitter (line 863) | func generateJitter(maxJitterMs int64) int64 {
function isTemporaryError (line 876) | func isTemporaryError(err error) bool {
function isPermanentError (line 904) | func isPermanentError(err error) bool {
FILE: go-b2b-starter/internal/platform/logger/cmd/init.go
function Init (line 7) | func Init(container *dig.Container) {
FILE: go-b2b-starter/internal/platform/logger/cmd/provider.go
function ProvideDependencies (line 8) | func ProvideDependencies(container *dig.Container) {
FILE: go-b2b-starter/internal/platform/logger/domain/logger.go
type Level (line 3) | type Level
constant DebugLevel (line 6) | DebugLevel Level = iota
constant InfoLevel (line 7) | InfoLevel
constant WarnLevel (line 8) | WarnLevel
constant ErrorLevel (line 9) | ErrorLevel
constant FatalLevel (line 10) | FatalLevel
type OutputType (line 13) | type OutputType
constant ConsoleOutput (line 16) | ConsoleOutput OutputType = iota
constant FileOutput (line 17) | FileOutput
constant BothOutput (line 18) | BothOutput
type Logger (line 23) | type Logger interface
FILE: go-b2b-starter/internal/platform/logger/domain/options.go
type Option (line 3) | type Option
type Options (line 5) | type Options struct
type FileOptions (line 11) | type FileOptions struct
function WithLevel (line 19) | func WithLevel(level Level) Option {
function WithOutput (line 25) | func WithOutput(output OutputType) Option {
function WithFileOptions (line 31) | func WithFileOptions(fileOpts FileOptions) Option {
FILE: go-b2b-starter/internal/platform/logger/factory.go
function New (line 8) | func New(opts ...domain.Option) domain.Logger {
FILE: go-b2b-starter/internal/platform/logger/internal/zerologger/factory.go
function NewLogger (line 7) | func NewLogger(opts *domain.Options) domain.Logger {
FILE: go-b2b-starter/internal/platform/logger/internal/zerologger/logger.go
type zerologLogger (line 13) | type zerologLogger struct
method Debug (line 55) | func (l *zerologLogger) Debug(msg string, fields ...logger.Fields) {
method Info (line 59) | func (l *zerologLogger) Info(msg string, fields ...logger.Fields) {
method Warn (line 63) | func (l *zerologLogger) Warn(msg string, fields ...logger.Fields) {
method Error (line 67) | func (l *zerologLogger) Error(msg string, fields ...logger.Fields) {
method Fatal (line 71) | func (l *zerologLogger) Fatal(msg string, fields ...logger.Fields) {
method WithFields (line 75) | func (l *zerologLogger) WithFields(fields logger.Fields) logger.Logger {
method log (line 79) | func (l *zerologLogger) log(event *zerolog.Event, msg string, fields ....
function newZerologLogger (line 17) | func newZerologLogger(opts *logger.Options) logger.Logger {
function convertLogLevel (line 86) | func convertLogLevel(level logger.Level) zerolog.Level {
FILE: go-b2b-starter/internal/platform/ocr/cmd/init.go
function Init (line 11) | func Init(container *dig.Container) error {
FILE: go-b2b-starter/internal/platform/ocr/domain/entity.go
type OCRResponse (line 4) | type OCRResponse struct
FILE: go-b2b-starter/internal/platform/ocr/domain/service.go
type OCRService (line 6) | type OCRService interface
FILE: go-b2b-starter/internal/platform/ocr/infra/config.go
type Config (line 9) | type Config struct
method Validate (line 15) | func (c Config) Validate() error {
function NewOCRConfig (line 25) | func NewOCRConfig() Config {
function getEnvOrDefault (line 35) | func getEnvOrDefault(key, defaultValue string) string {
FILE: go-b2b-starter/internal/platform/ocr/infra/mistral_ocr_client.go
type MistralOCRClient (line 17) | type MistralOCRClient struct
method ExtractText (line 76) | func (m *MistralOCRClient) ExtractText(ctx context.Context, base64File...
method validateInput (line 108) | func (m *MistralOCRClient) validateInput(base64File string, mimeType s...
method isSupportedMimeType (line 122) | func (m *MistralOCRClient) isSupportedMimeType(mimeType string) bool {
method buildMistralRequest (line 142) | func (m *MistralOCRClient) buildMistralRequest(base64File string, mime...
method callMistralAPI (line 166) | func (m *MistralOCRClient) callMistralAPI(ctx context.Context, mistral...
method convertResponse (line 210) | func (m *MistralOCRClient) convertResponse(mistralResponse *MistralOCR...
method calculateConfidence (line 230) | func (m *MistralOCRClient) calculateConfidence(text string, pages int)...
type MistralOCRRequest (line 24) | type MistralOCRRequest struct
type MistralDocument (line 30) | type MistralDocument struct
type MistralOCRResponse (line 36) | type MistralOCRResponse struct
type MistralPage (line 40) | type MistralPage struct
type MistralImage (line 47) | type MistralImage struct
type MistralBoundingBox (line 51) | type MistralBoundingBox struct
function NewMistralOCRClient (line 59) | func NewMistralOCRClient(config Config, logger loggerDomain.Logger) (dom...
FILE: go-b2b-starter/internal/platform/ocr/infra/mock_ocr_client.go
type MockOCRClient (line 14) | type MockOCRClient struct
method ExtractText (line 30) | func (m *MockOCRClient) ExtractText(ctx context.Context, base64File st...
function NewMockOCRClient (line 19) | func NewMockOCRClient(config Config, logger loggerDomain.Logger) (domain...
FILE: go-b2b-starter/internal/platform/polar/client.go
type Client (line 15) | type Client struct
method Get (line 38) | func (c *Client) Get(ctx context.Context, path string) (*http.Response...
method Patch (line 43) | func (c *Client) Patch(ctx context.Context, path string, body interfac...
method Post (line 48) | func (c *Client) Post(ctx context.Context, path string, body interface...
method doRequest (line 53) | func (c *Client) doRequest(ctx context.Context, method, path string, b...
function NewClient (line 22) | func NewClient(config *Config) (*Client, error) {
function DecodeJSON (line 95) | func DecodeJSON(resp *http.Response, v interface{}) error {
FILE: go-b2b-starter/internal/platform/polar/cmd/init.go
function Init (line 10) | func Init(container *dig.Container) error {
FILE: go-b2b-starter/internal/platform/polar/config.go
type Config (line 10) | type Config struct
method Validate (line 59) | func (c *Config) Validate() error {
function LoadConfig (line 29) | func LoadConfig() (Config, error) {
function DefaultConfig (line 75) | func DefaultConfig() *Config {
function SandboxConfig (line 83) | func SandboxConfig() *Config {
FILE: go-b2b-starter/internal/platform/polar/inject.go
function Module (line 10) | func Module(container *dig.Container) error {
FILE: go-b2b-starter/internal/platform/polar/webhook.go
function VerifyWebhookSignature (line 26) | func VerifyWebhookSignature(secret string, webhookID string, timestamp s...
function ComputeWebhookSignature (line 78) | func ComputeWebhookSignature(secret string, webhookID string, timestamp ...
FILE: go-b2b-starter/internal/platform/redis/cmd/init.go
function Init (line 9) | func Init(dig *dig.Container) error {
FILE: go-b2b-starter/internal/platform/redis/cmd/provider.go
function provideRedisDependencies (line 10) | func provideRedisDependencies(container *dig.Container) error {
function provideRedisStore (line 25) | func provideRedisStore() (redis.Client, error) {
FILE: go-b2b-starter/internal/platform/redis/config.go
type Config (line 7) | type Config struct
function LoadConfig (line 15) | func LoadConfig() (Config, error) {
FILE: go-b2b-starter/internal/platform/redis/init.go
function InitRedis (line 5) | func InitRedis() (Client, error) {
FILE: go-b2b-starter/internal/platform/redis/redis.go
type redisClient (line 11) | type redisClient struct
method Set (line 30) | func (c *redisClient) Set(ctx context.Context, key string, value inter...
method Get (line 34) | func (c *redisClient) Get(ctx context.Context, key string) (string, er...
method Delete (line 38) | func (c *redisClient) Delete(ctx context.Context, key string) error {
method Exists (line 42) | func (c *redisClient) Exists(ctx context.Context, key string) (bool, e...
function newRedisClient (line 15) | func newRedisClient(cfg Config) (*redisClient, error) {
FILE: go-b2b-starter/internal/platform/redis/store.go
type Client (line 8) | type Client interface
FILE: go-b2b-starter/internal/platform/server/cmd/di.go
type serverMiddlewareAdapter (line 16) | type serverMiddlewareAdapter struct
method RegisterNamedMiddleware (line 20) | func (a *serverMiddlewareAdapter) RegisterNamedMiddleware(name string,...
function SetupDependencies (line 25) | func SetupDependencies(container *dig.Container) {
FILE: go-b2b-starter/internal/platform/server/cmd/init.go
function Init (line 5) | func Init(container *dig.Container) {
FILE: go-b2b-starter/internal/platform/server/config/config.go
type Environment (line 10) | type Environment
constant DEV (line 13) | DEV Environment = "DEV"
constant PROD (line 14) | PROD Environment = "PROD"
type Config (line 17) | type Config struct
method GetSanitizationConfig (line 73) | func (c *Config) GetSanitizationConfig() SanitizationConfig {
method IsProd (line 81) | func (c *Config) IsProd() bool {
type SanitizationConfig (line 66) | type SanitizationConfig struct
function LoadConfig (line 86) | func LoadConfig() (*Config, error) {
function validateProductionConfig (line 129) | func validateProductionConfig(cfg *Config) error {
FILE: go-b2b-starter/internal/platform/server/domain/health.go
method setupHealthCheck (line 10) | func (s *HTTPServer) setupHealthCheck() {
method setupRootEndpoint (line 31) | func (s *HTTPServer) setupRootEndpoint() {
FILE: go-b2b-starter/internal/platform/server/domain/http_server.go
type HTTPServer (line 17) | type HTTPServer struct
method Start (line 53) | func (s *HTTPServer) Start() error {
method MiddlewareResolver (line 62) | func (s *HTTPServer) MiddlewareResolver() MiddlewareResolver {
method RegisterRoutes (line 67) | func (s *HTTPServer) RegisterRoutes(registrar RouteRegistrar, prefix s...
method RegisterNamedMiddleware (line 84) | func (s *HTTPServer) RegisterNamedMiddleware(name string, middleware M...
method createHTTPServer (line 89) | func (s *HTTPServer) createHTTPServer() *http.Server {
method startServer (line 101) | func (s *HTTPServer) startServer(srv *http.Server) {
method handleGracefulShutdown (line 119) | func (s *HTTPServer) handleGracefulShutdown(srv *http.Server) error {
method Get (line 142) | func (s *HTTPServer) Get(name string) gin.HandlerFunc {
method GetMiddleware (line 154) | func (s *HTTPServer) GetMiddleware(name string) gin.HandlerFunc {
function NewHTTPServer (line 27) | func NewHTTPServer(
FILE: go-b2b-starter/internal/platform/server/domain/middleware.go
method setupMiddleware (line 10) | func (s *HTTPServer) setupMiddleware() {
method requestLoggingMiddleware (line 40) | func (s *HTTPServer) requestLoggingMiddleware() gin.HandlerFunc {
FILE: go-b2b-starter/internal/platform/server/domain/middleware_resolver.go
type MiddlewareResolver (line 6) | type MiddlewareResolver interface
FILE: go-b2b-starter/internal/platform/server/domain/server.go
constant ApiPrefix (line 7) | ApiPrefix = "/api"
constant ApiVersion1 (line 8) | ApiVersion1 = "v1"
type RouteRegistrar (line 13) | type RouteRegistrar
type MiddlewareFunc (line 16) | type MiddlewareFunc
type Server (line 21) | type Server interface
FILE: go-b2b-starter/internal/platform/server/errors/errors.go
type APIError (line 3) | type APIError struct
function NewAPIError (line 8) | func NewAPIError(code int, message string) *APIError {
FILE: go-b2b-starter/internal/platform/server/gin/gin.go
type GinRouter (line 8) | type GinRouter struct
method GetHandler (line 22) | func (g *GinRouter) GetHandler() *gin.Engine {
function NewGinRouter (line 13) | func NewGinRouter(cfg *config.Config) *GinRouter {
FILE: go-b2b-starter/internal/platform/server/logging/logger.go
type Logger (line 7) | type Logger struct
method Error (line 20) | func (l *Logger) Error(msg string, err error) {
method Fatal (line 24) | func (l *Logger) Fatal(msg string, err error) {
function InitLogger (line 11) | func InitLogger() (*Logger, error) {
function Error (line 29) | func Error(err error) zap.Field {
FILE: go-b2b-starter/internal/platform/server/logging/security_logger.go
type SecurityLogger (line 11) | type SecurityLogger struct
method LogSecurityEvent (line 32) | func (sl *SecurityLogger) LogSecurityEvent(event SecurityEvent) {
method LogFailedAuth (line 45) | func (sl *SecurityLogger) LogFailedAuth(ip string, userID string, reas...
method LogSuspiciousActivity (line 56) | func (sl *SecurityLogger) LogSuspiciousActivity(ip string, description...
method LogBlacklisted (line 66) | func (sl *SecurityLogger) LogBlacklisted(ip string) {
type SecurityEvent (line 15) | type SecurityEvent struct
function NewSecurityLogger (line 26) | func NewSecurityLogger(baseLogger *zap.SugaredLogger) *SecurityLogger {
FILE: go-b2b-starter/internal/platform/server/metrics/prometheus.go
function SetupPrometheus (line 8) | func SetupPrometheus(router *gin.Engine) {
FILE: go-b2b-starter/internal/platform/server/middleware/cors.go
function CORS (line 10) | func CORS(allowedOrigins []string) gin.HandlerFunc {
FILE: go-b2b-starter/internal/platform/server/middleware/ip_protection.go
type IPProtection (line 12) | type IPProtection struct
method Stop (line 43) | func (ip *IPProtection) Stop() {
method periodicCleanup (line 49) | func (ip *IPProtection) periodicCleanup() {
method cleanupFailedAttempts (line 61) | func (ip *IPProtection) cleanupFailedAttempts() {
method Protect (line 75) | func (ip *IPProtection) Protect() gin.HandlerFunc {
method isWhitelisted (line 102) | func (ip *IPProtection) isWhitelisted(clientIP string) bool {
method isBlacklisted (line 108) | func (ip *IPProtection) isBlacklisted(clientIP string) bool {
method isSuspicious (line 115) | func (ip *IPProtection) isSuspicious(clientIP string) bool {
method RecordFailedAttempt (line 132) | func (ip *IPProtection) RecordFailedAttempt(clientIP string) {
method addToBlacklist (line 157) | func (ip *IPProtection) addToBlacklist(clientIP string) {
method AddToWhitelist (line 164) | func (ip *IPProtection) AddToWhitelist(clientIP string) {
method RemoveFromBlacklist (line 171) | func (ip *IPProtection) RemoveFromBlacklist(clientIP string) {
type FailedAttempt (line 21) | type FailedAttempt struct
function NewIPProtection (line 27) | func NewIPProtection() *IPProtection {
FILE: go-b2b-starter/internal/platform/server/middleware/ratelimit.go
function RateLimiter (line 10) | func RateLimiter(rateLimitPerSecond int) gin.HandlerFunc {
FILE: go-b2b-starter/internal/platform/server/middleware/recovery.go
constant stackSize (line 18) | stackSize = 4 << 10
function Recovery (line 21) | func Recovery(logger *logging.Logger) gin.HandlerFunc {
function stack (line 61) | func stack(_ int) []byte {
FILE: go-b2b-starter/internal/platform/server/middleware/request_id.go
constant RequestIDHeader (line 10) | RequestIDHeader = "X-Request-ID"
constant RequestIDKey (line 13) | RequestIDKey = "request_id"
function RequestID (line 17) | func RequestID() gin.HandlerFunc {
function generateRequestID (line 36) | func generateRequestID() string {
function GetRequestID (line 41) | func GetRequestID(c *gin.Context) string {
FILE: go-b2b-starter/internal/platform/server/middleware/request_size_limit.go
function RequestSizeLimit (line 12) | func RequestSizeLimit(maxSize int64) gin.HandlerFunc {
FILE: go-b2b-starter/internal/platform/server/middleware/sanatization.go
function RequestSanitization (line 14) | func RequestSanitization(config config.SanitizationConfig) gin.HandlerFu...
function containsPathTraversal (line 51) | func containsPathTraversal(path string) bool {
function containsXSS (line 61) | func containsXSS(input string) bool {
function containsSQLInjection (line 77) | func containsSQLInjection(input string) bool {
FILE: go-b2b-starter/internal/platform/server/middleware/security_headers.go
function SecurityHeaders (line 7) | func SecurityHeaders() gin.HandlerFunc {
FILE: go-b2b-starter/internal/platform/server/middleware/timeout.go
function Timeout (line 14) | func Timeout(timeout time.Duration) gin.HandlerFunc {
type bodyLogWriter (line 67) | type bodyLogWriter struct
method WriteHeader (line 72) | func (w *bodyLogWriter) WriteHeader(code int) {
FILE: go-b2b-starter/internal/platform/server/middleware/validator.go
function InitValidator (line 10) | func InitValidator() *validator.Validate {
function ValidateRequest (line 15) | func ValidateRequest(structPtr interface{}) gin.HandlerFunc {
FILE: go-b2b-starter/internal/platform/stytch/client.go
type Client (line 12) | type Client struct
method API (line 43) | func (c *Client) API() *b2bstytchapi.API {
method Config (line 48) | func (c *Client) Config() Config {
function NewClient (line 18) | func NewClient(cfg Config) (*Client, error) {
FILE: go-b2b-starter/internal/platform/stytch/cmd/provider.go
function ProvideStytchDependencies (line 14) | func ProvideStytchDependencies(container *dig.Container) error {
function provideStytchClient (line 30) | func provideStytchClient(cfg *stytch.Config, log logger.Logger) (*stytch...
function isPlaceholderCredentials (line 45) | func isPlaceholderCredentials(cfg *stytch.Config) bool {
function provideRBACPolicyService (line 52) | func provideRBACPolicyService(
FILE: go-b2b-starter/internal/platform/stytch/config.go
constant EnvTest (line 13) | EnvTest = "test"
constant EnvLive (line 14) | EnvLive = "live"
type Config (line 18) | type Config struct
function LoadConfig (line 34) | func LoadConfig() (*Config, error) {
FILE: go-b2b-starter/internal/platform/stytch/errors.go
function IsDuplicateSlugError (line 32) | func IsDuplicateSlugError(err error) bool {
function MapError (line 46) | func MapError(err error) error {
FILE: go-b2b-starter/internal/platform/stytch/inject.go
function ProvideDependencies (line 12) | func ProvideDependencies(container *dig.Container) error {
FILE: go-b2b-starter/internal/platform/stytch/rbac_policy.go
constant rbacPolicyCacheKey (line 17) | rbacPolicyCacheKey = "stytch:rbac:policy"
constant rbacPolicyCacheTTL (line 19) | rbacPolicyCacheTTL = 5 * time.Minute
type RBACPolicyService (line 23) | type RBACPolicyService struct
method GetRolePermissions (line 43) | func (s *RBACPolicyService) GetRolePermissions(ctx context.Context, ro...
method getPolicy (line 65) | func (s *RBACPolicyService) getPolicy(ctx context.Context) (*rbac.Poli...
method fetchPolicyFromStytch (line 93) | func (s *RBACPolicyService) fetchPolicyFromStytch(ctx context.Context)...
method cachePolicy (line 114) | func (s *RBACPolicyService) cachePolicy(ctx context.Context, policy *r...
method convertPermissions (line 144) | func (s *RBACPolicyService) convertPermissions(permissions []rbac.Poli...
method expandWildcardActions (line 177) | func (s *RBACPolicyService) expandWildcardActions(resourceID string, a...
function NewRBACPolicyService (line 29) | func NewRBACPolicyService(
function normalizeRoleID (line 218) | func normalizeRoleID(roleID string) string {
FILE: go-b2b-starter/pkg/httperr/errors.go
function IsNotFoundError (line 8) | func IsNotFoundError(err error) bool {
function IsConflictError (line 16) | func IsConflictError(err error) bool {
function IsBadRequestError (line 24) | func IsBadRequestError(err error) bool {
function IsAuthenticationError (line 32) | func IsAuthenticationError(err error) bool {
function IsAuthorizationError (line 40) | func IsAuthorizationError(err error) bool {
function IsInternalServerError (line 48) | func IsInternalServerError(err error) bool {
function GetErrorCode (line 56) | func GetErrorCode(err error) string {
function GetErrorMessage (line 64) | func GetErrorMessage(err error) string {
FILE: go-b2b-starter/pkg/httperr/http_error.go
type HTTPError (line 3) | type HTTPError struct
method Error (line 9) | func (e HTTPError) Error() string {
function NewHTTPError (line 13) | func NewHTTPError(statusCode int, code, message string) HTTPError {
FILE: go-b2b-starter/pkg/pagination/pagination.go
type PagePagination (line 5) | type PagePagination struct
type Meta (line 10) | type Meta struct
function NewPagePagination (line 23) | func NewPagePagination[T any](totalItems, page, pageSize int, items []T)...
function PageToOffset (line 62) | func PageToOffset(page int, limit int) (int, error) {
FILE: go-b2b-starter/pkg/pagination/pramas.go
type SearchableParams (line 3) | type SearchableParams struct
method Validate (line 10) | func (s *SearchableParams) Validate() error {
type ListableParams (line 26) | type ListableParams struct
method Validate (line 32) | func (s *ListableParams) Validate() error {
FILE: go-b2b-starter/pkg/pagination/util.go
function PaginationCalc (line 5) | func PaginationCalc(offset, limit int) (page, pageSize int) {
FILE: go-b2b-starter/pkg/response/response.go
function Success (line 10) | func Success(c *gin.Context, statusCode int, data interface{}) {
function Error (line 18) | func Error(c *gin.Context, statusCode int, message string, err error) {
FILE: go-b2b-starter/pkg/slugify/slugify.go
function Slugify (line 10) | func Slugify(s string) string {
FILE: next_b2b_starter/app/api/auth/session/refresh/route.ts
function POST (line 15) | async function POST() {
FILE: next_b2b_starter/app/api/billing/webhook/route.ts
function handleSubscriptionEvent (line 6) | async function handleSubscriptionEvent(_eventType: string, _payload: unk...
constant POST (line 16) | const POST = webhookSecret
FILE: next_b2b_starter/app/auth/page.tsx
function AuthPage (line 40) | function AuthPage() {
FILE: next_b2b_starter/app/authenticate/page.tsx
constant SESSION_DURATION_MINUTES (line 11) | const SESSION_DURATION_MINUTES = Number(
constant DEFAULT_DESTINATION (line 15) | const DEFAULT_DESTINATION = "/dashboard";
type StatusState (line 17) | type StatusState = {
constant INITIAL_STATUS (line 23) | const INITIAL_STATUS: StatusState = {
function extractErrorMessage (line 29) | function extractErrorMessage(error: unknown): string {
function AuthenticateRedirectPage (line 45) | function AuthenticateRedirectPage() {
FILE: next_b2b_starter/app/dashboard/knowledge/components/chat-interface.tsx
type ChatInterfaceProps (line 13) | interface ChatInterfaceProps {
function EmptyState (line 24) | function EmptyState({ onSuggestionClick }: { onSuggestionClick?: (text: ...
function LoadingSkeleton (line 61) | function LoadingSkeleton() {
function ChatInterface (line 75) | function ChatInterface({
FILE: next_b2b_starter/app/dashboard/knowledge/components/chat-message.tsx
type ChatMessageProps (line 11) | interface ChatMessageProps {
function ChatMessage (line 16) | function ChatMessage({ message, sources }: ChatMessageProps) {
function TypingIndicator (line 59) | function TypingIndicator() {
FILE: next_b2b_starter/app/dashboard/knowledge/components/document-list.tsx
type DocumentListProps (line 26) | interface DocumentListProps {
function DocumentCard (line 35) | function DocumentCard({
function DocumentListSkeleton (line 137) | function DocumentListSkeleton({ compact }: { compact?: boolean }) {
function EmptyDocumentsState (line 153) | function EmptyDocumentsState({ compact }: { compact?: boolean }) {
function DocumentList (line 180) | function DocumentList({
FILE: next_b2b_starter/app/dashboard/knowledge/components/document-sources.tsx
type DocumentSourcesProps (line 8) | interface DocumentSourcesProps {
function DocumentSources (line 12) | function DocumentSources({ sources }: DocumentSourcesProps) {
FILE: next_b2b_starter/app/dashboard/knowledge/components/document-upload.tsx
type DocumentUploadProps (line 13) | interface DocumentUploadProps {
function DocumentUpload (line 18) | function DocumentUpload({
FILE: next_b2b_starter/app/dashboard/knowledge/components/knowledge-content.tsx
function KnowledgeContent (line 13) | function KnowledgeContent() {
FILE: next_b2b_starter/app/dashboard/knowledge/components/knowledge-sidebar.tsx
type KnowledgeSidebarProps (line 14) | interface KnowledgeSidebarProps {
function KnowledgeSidebar (line 29) | function KnowledgeSidebar({
function ChatsTab (line 103) | function ChatsTab({
function SourcesTab (line 172) | function SourcesTab({
FILE: next_b2b_starter/app/dashboard/knowledge/layout.tsx
function KnowledgeLayout (line 8) | function KnowledgeLayout({
FILE: next_b2b_starter/app/dashboard/knowledge/page.tsx
function KnowledgePage (line 3) | function KnowledgePage() {
FILE: next_b2b_starter/app/dashboard/layout.tsx
function Layout (line 7) | async function Layout({
FILE: next_b2b_starter/app/dashboard/page.tsx
type DashboardPageProps (line 4) | interface DashboardPageProps {
function DashboardPage (line 8) | async function DashboardPage({ searchParams }: DashboardPageProps) {
FILE: next_b2b_starter/app/dashboard/settings/components/invite-member.tsx
type InviteMemberProps (line 19) | interface InviteMemberProps {
type RoleOption (line 29) | interface RoleOption {
constant DEFAULT_ROLES (line 38) | const DEFAULT_ROLES: RoleOption[] = [
function InviteMember (line 59) | function InviteMember({
FILE: next_b2b_starter/app/dashboard/settings/components/member-list.tsx
type MemberListProps (line 27) | interface MemberListProps {
function MemberList (line 36) | function MemberList({
FILE: next_b2b_starter/app/dashboard/settings/components/profile-section.tsx
type ProfileSectionProps (line 5) | interface ProfileSectionProps {
function ProfileSection (line 9) | function ProfileSection({ profile }: ProfileSectionProps) {
FILE: next_b2b_starter/app/dashboard/settings/components/profile-tab.tsx
type ProfileTabProps (line 24) | interface ProfileTabProps {
function ProfileTab (line 34) | function ProfileTab({
FILE: next_b2b_starter/app/dashboard/settings/components/settings-content.tsx
type SettingsContentProps (line 50) | interface SettingsContentProps {
type SettingsView (line 54) | type SettingsView = "overview" | "profile" | "members" | "subscription";
type OverviewSection (line 56) | interface OverviewSection {
constant DETAIL_META (line 66) | const DETAIL_META: Record<Exclude<SettingsView, "overview">, { title: st...
function parseViewParam (line 81) | function parseViewParam(raw: string | null): SettingsView | null {
function getPlanNameFromRecord (line 90) | function getPlanNameFromRecord(record: Record<string, unknown> | null | ...
function resolvePlanLabel (line 117) | function resolvePlanLabel(state: SubscriptionGateState | null): string {
function getSubscriptionQuickStatus (line 150) | function getSubscriptionQuickStatus(
function SettingsContent (line 213) | function SettingsContent({}: SettingsContentProps = {}) {
FILE: next_b2b_starter/app/dashboard/settings/components/subscription-tab.tsx
type SubscriptionTabProps (line 43) | interface SubscriptionTabProps {
function SubscriptionTab (line 50) | function SubscriptionTab({
function SummaryMetric (line 481) | function SummaryMetric({ label, value }: { label: string; value: string ...
function remainingInvoicesText (line 492) | function remainingInvoicesText(limit: number, used: number) {
function SubscriptionSkeleton (line 498) | function SubscriptionSkeleton() {
function getStatusDisplay (line 516) | function getStatusDisplay(
function titleCase (line 560) | function titleCase(value: string) {
FILE: next_b2b_starter/app/dashboard/settings/layout.tsx
function SettingsLayout (line 8) | function SettingsLayout({
FILE: next_b2b_starter/app/dashboard/settings/page.tsx
function SettingsPage (line 3) | function SettingsPage() {
FILE: next_b2b_starter/app/head.tsx
function Head (line 1) | function Head() {
FILE: next_b2b_starter/app/layout.tsx
function RootLayout (line 92) | async function RootLayout({
FILE: next_b2b_starter/app/not-found.tsx
function NotFound (line 7) | function NotFound() {
FILE: next_b2b_starter/app/page.tsx
function HomePage (line 5) | function HomePage() {
FILE: next_b2b_starter/app/robots.ts
function robots (line 3) | function robots(): MetadataRoute.Robots {
FILE: next_b2b_starter/app/signup/page.tsx
function SignupPage (line 9) | function SignupPage() {
FILE: next_b2b_starter/app/sitemap.ts
function sitemap (line 3) | function sitemap(): MetadataRoute.Sitemap {
FILE: next_b2b_starter/components/auth/can.tsx
type CanProps (line 11) | interface CanProps {
function Can (line 92) | function Can({
FILE: next_b2b_starter/components/auth/permission-gate.tsx
type PermissionGateProps (line 15) | interface PermissionGateProps {
function AccessDenied (line 66) | function AccessDenied({ onGoBack }: { onGoBack: () => void }) {
function PermissionGate (line 133) | function PermissionGate({
FILE: next_b2b_starter/components/auth/stytch-provider.tsx
type Props (line 13) | interface Props {
constant COOKIE_OPTIONS (line 18) | const COOKIE_OPTIONS = {
function StytchProvider (line 26) | function StytchProvider({ children, config }: Props) {
FILE: next_b2b_starter/components/billing/plans-modal.tsx
type PlansModalProps (line 10) | interface PlansModalProps {
function PlansModal (line 17) | function PlansModal({
type PlanCardProps (line 191) | interface PlanCardProps {
function PlanCard (line 199) | function PlanCard({ plan, disabled, isSelected, isCurrent, onSelect }: P...
function formatCurrency (line 271) | function formatCurrency(amount: number) {
FILE: next_b2b_starter/components/billing/subscription-alerts.tsx
type SubscriptionAlertVariant (line 12) | type SubscriptionAlertVariant = "info" | "warning" | "critical";
type SubscriptionAlertAction (line 14) | interface SubscriptionAlertAction {
type SubscriptionAlertDescriptor (line 21) | interface SubscriptionAlertDescriptor {
type SubscriptionAlertsProps (line 30) | interface SubscriptionAlertsProps {
function SubscriptionAlerts (line 56) | function SubscriptionAlerts({ alerts, className }: SubscriptionAlertsPro...
FILE: next_b2b_starter/components/billing/subscription-paywall.tsx
type SubscriptionPaywallProps (line 15) | interface SubscriptionPaywallProps {
function SubscriptionPaywall (line 19) | function SubscriptionPaywall({}: SubscriptionPaywallProps = {}) {
type FeatureProps (line 233) | interface FeatureProps {
function Feature (line 238) | function Feature({ title, description }: FeatureProps) {
type UsageItemProps (line 247) | interface UsageItemProps {
function UsageItem (line 253) | function UsageItem({ label, value, total }: UsageItemProps) {
function resolvePlanFromState (line 272) | function resolvePlanFromState(state: SubscriptionGateState, products: Po...
function buildFeatureList (line 297) | function buildFeatureList({
function formatUsd (line 341) | function formatUsd(amount: number) {
FILE: next_b2b_starter/components/common/obfuscated-email.tsx
type Props (line 5) | type Props = {
function ObfuscatedEmail (line 12) | function ObfuscatedEmail({ user, domain, className, children }: Props) {
FILE: next_b2b_starter/components/layout/dashboard-layout.tsx
type DashboardLayoutProps (line 26) | interface DashboardLayoutProps {
function DashboardLayout (line 31) | function DashboardLayout({
function deriveSubscriptionUiState (line 180) | function deriveSubscriptionUiState(
function getInactiveDescription (line 375) | function getInactiveDescription(state: SubscriptionGateState): string {
function formatNumber (line 396) | function formatNumber(value: number): string {
function formatDateString (line 400) | function formatDateString(value: string): string {
function daysUntil (line 413) | function daysUntil(value: string): number | null {
FILE: next_b2b_starter/components/layout/header.tsx
function Header (line 20) | function Header() {
FILE: next_b2b_starter/components/layout/sidebar.tsx
type NavigationItem (line 22) | interface NavigationItem {
type SidebarProps (line 47) | interface SidebarProps {
function Sidebar (line 51) | function Sidebar({
FILE: next_b2b_starter/components/layout/user-menu.tsx
function getInitials (line 20) | function getInitials(name?: string) {
function UserMenu (line 28) | function UserMenu() {
FILE: next_b2b_starter/components/seo/jsonld.tsx
type JsonLdProps (line 3) | type JsonLdProps = {
function JsonLd (line 8) | function JsonLd({ data, id }: JsonLdProps) {
FILE: next_b2b_starter/components/ui/badge.tsx
type BadgeProps (line 26) | interface BadgeProps
function Badge (line 30) | function Badge({ className, variant, ...props }: BadgeProps) {
FILE: next_b2b_starter/components/ui/button.tsx
type ButtonProps (line 37) | interface ButtonProps
FILE: next_b2b_starter/components/ui/calendar.tsx
function Calendar (line 14) | function Calendar({
function CalendarDayButton (line 175) | function CalendarDayButton({
FILE: next_b2b_starter/components/ui/date-picker.tsx
type DatePickerProps (line 17) | interface DatePickerProps {
function DatePicker (line 25) | function DatePicker({
FILE: next_b2b_starter/components/ui/dialog.tsx
type DialogContentProps (line 32) | interface DialogContentProps
FILE: next_b2b_starter/components/ui/form.tsx
type FormFieldContextValue (line 20) | type FormFieldContextValue<
type FormItemContextValue (line 67) | type FormItemContextValue = {
FILE: next_b2b_starter/components/ui/select.tsx
type SelectContentProps (line 70) | interface SelectContentProps
FILE: next_b2b_starter/components/ui/sheet-header.tsx
type SheetHeaderProps (line 7) | interface SheetHeaderProps {
function SheetHeader (line 12) | function SheetHeader({ title, onClose }: SheetHeaderProps) {
FILE: next_b2b_starter/components/ui/sheet.tsx
type SheetContentProps (line 52) | interface SheetContentProps
FILE: next_b2b_starter/components/ui/skeleton.tsx
function Skeleton (line 3) | function Skeleton({
FILE: next_b2b_starter/hooks/use-signup-flow.ts
type SignupStep (line 9) | type SignupStep = "account" | "organization";
type UseSignupFlowState (line 11) | interface UseSignupFlowState {
function useSignupFlow (line 40) | function useSignupFlow(): UseSignupFlowState {
FILE: next_b2b_starter/hooks/use-toast.ts
type ToastProps (line 4) | interface ToastProps {
function useToast (line 10) | function useToast() {
FILE: next_b2b_starter/lib/actions/auth/consume-magic-link.ts
type ConsumeMagicLinkResult (line 20) | interface ConsumeMagicLinkResult {
function consumeMagicLink (line 46) | async function consumeMagicLink(
FILE: next_b2b_starter/lib/actions/auth/logout.ts
function logout (line 19) | async function logout(returnTo?: string): Promise<never> {
function resolveReturnTo (line 61) | function resolveReturnTo(returnTo?: string): string {
FILE: next_b2b_starter/lib/actions/auth/send-magic-link.ts
function sendMagicLink (line 22) | async function sendMagicLink(
FILE: next_b2b_starter/lib/actions/billing/cancel-subscription.ts
constant ALLOWED_REASONS (line 15) | const ALLOWED_REASONS = new Set([
type CancelSubscriptionParams (line 26) | interface CancelSubscriptionParams {
type CancelSubscriptionData (line 32) | interface CancelSubscriptionData {
function cancelSubscription (line 52) | async function cancelSubscription(
FILE: next_b2b_starter/lib/actions/billing/create-checkout.ts
function getAppBaseUrl (line 15) | function getAppBaseUrl(): string {
type CreateCheckoutParams (line 23) | interface CreateCheckoutParams {
type CheckoutData (line 28) | interface CheckoutData {
function createCheckout (line 41) | async function createCheckout(
FILE: next_b2b_starter/lib/actions/billing/get-products.ts
function getProducts (line 19) | async function getProducts(): Promise<ActionResult<PolarPlan[]>> {
FILE: next_b2b_starter/lib/actions/billing/get-subscription-status.ts
function getSubscriptionStatus (line 21) | async function getSubscriptionStatus(): Promise<
FILE: next_b2b_starter/lib/actions/billing/verify-payment.ts
type BillingStatus (line 11) | interface BillingStatus {
function verifyPayment (line 29) | async function verifyPayment(
FILE: next_b2b_starter/lib/api/api/client/api-client.ts
type ApiClientConfig (line 15) | interface ApiClientConfig {
type RequestOptions (line 20) | interface RequestOptions {
class ApiClient (line 25) | class ApiClient {
method constructor (line 28) | constructor(config?: Partial<ApiClientConfig>) {
method get (line 45) | async get<T>(endpoint: string, options?: RequestOptions): Promise<T> {
method post (line 52) | async post<T>(
method put (line 63) | async put<T>(
method delete (line 74) | async delete<T>(endpoint: string, options?: RequestOptions): Promise<T> {
method getBaseUrl (line 81) | getBaseUrl(): string {
method request (line 85) | private async request<T>(
method prepareBody (line 199) | private prepareBody(body: any): BodyInit | undefined {
method applyOptions (line 205) | private applyOptions(
method prepareHeaders (line 218) | private prepareHeaders(
method handleUnauthorizedResponse (line 231) | private async handleUnauthorizedResponse<T>({
method buildApiError (line 273) | private async buildApiError(response: Response): Promise<Error> {
type ResolveAccessTokenOptions (line 292) | type ResolveAccessTokenOptions = {
constant MAX_REFRESH_RETRIES (line 303) | const MAX_REFRESH_RETRIES = 3;
constant REFRESH_RETRY_DELAYS (line 304) | const REFRESH_RETRY_DELAYS = [1000, 2000, 4000];
constant REFRESH_PROMISE_TIMEOUT_MS (line 305) | const REFRESH_PROMISE_TIMEOUT_MS = 10000;
function resolveAccessToken (line 307) | async function resolveAccessToken(
function sleep (line 343) | async function sleep(ms: number): Promise<void> {
function refreshTokenWithRetry (line 348) | async function refreshTokenWithRetry(attempt: number = 0): Promise<strin...
function refreshToken (line 394) | async function refreshToken(): Promise<string | null> {
function performTokenRefresh (line 422) | async function performTokenRefresh(): Promise<string | null> {
function readStoredAccessToken (line 430) | async function readStoredAccessToken(): Promise<string | null> {
function readServerSessionToken (line 444) | async function readServerSessionToken(): Promise<string | null> {
function clearSessionCookies (line 458) | async function clearSessionCookies(): Promise<void> {
function logoutUser (line 482) | async function logoutUser(): Promise<void> {
function deleteBrowserCookie (line 493) | function deleteBrowserCookie(name: string, expiry: string) {
function readBrowserCookie (line 497) | function readBrowserCookie(name: string): string | null {
function escapeRegExp (line 509) | function escapeRegExp(value: string): string {
function updateCachedToken (line 513) | function updateCachedToken(
function resetCachedToken (line 521) | function resetCachedToken() {
function exchangeSessionTokenForJwt (line 529) | async function exchangeSessionTokenForJwt(
function loadStytchB2BClient (line 554) | async function loadStytchB2BClient(): Promise<any | null> {
function createStytchB2BClient (line 569) | async function createStytchB2BClient(): Promise<any | null> {
function tryRefreshServerToken (line 596) | async function tryRefreshServerToken(): Promise<string | null> {
function persistBrowserSessionJwt (line 606) | function persistBrowserSessionJwt(token: string): void {
function fetchSessionJwtFromApi (line 629) | async function fetchSessionJwtFromApi(): Promise<string | null> {
type TokenState (line 659) | type TokenState = "none" | "invalid" | "expired" | "valid";
function classifyTokenState (line 661) | function classifyTokenState(token: string | null): TokenState {
FILE: next_b2b_starter/lib/api/api/dto/auth.dto.ts
type BootstrapOrganizationRequestDto (line 1) | interface BootstrapOrganizationRequestDto {
type SignupMagicLinkRequestDto (line 9) | interface SignupMagicLinkRequestDto {
type SignupMagicLinkResponseDto (line 17) | interface SignupMagicLinkResponseDto {
type BootstrapOrganizationResponseDto (line 27) | interface BootstrapOrganizationResponseDto {
type LoginRequestDto (line 37) | interface LoginRequestDto {
type LoginResponseDto (line 42) | interface LoginResponseDto {
FILE: next_b2b_starter/lib/api/api/dto/cognitive.dto.ts
type ChatRole (line 3) | type ChatRole = "user" | "assistant" | "system";
type ChatSessionDto (line 5) | interface ChatSessionDto {
type ChatMessageDto (line 12) | interface ChatMessageDto {
type SimilarDocumentDto (line 22) | interface SimilarDocumentDto {
type ChatRequestDto (line 29) | interface ChatRequestDto {
type ChatResponseDto (line 37) | interface ChatResponseDto {
type ListSessionsResponseDto (line 44) | interface ListSessionsResponseDto {
type SessionMessagesResponseDto (line 48) | interface SessionMessagesResponseDto {
FILE: next_b2b_starter/lib/api/api/dto/document.dto.ts
type DocumentStatus (line 3) | type DocumentStatus = "pending" | "processing" | "processed" | "failed";
type DocumentDto (line 5) | interface DocumentDto {
type ListDocumentsRequestDto (line 18) | interface ListDocumentsRequestDto {
type ListDocumentsResponseDto (line 24) | interface ListDocumentsResponseDto {
type UploadDocumentResponseDto (line 31) | interface UploadDocumentResponseDto {
FILE: next_b2b_starter/lib/api/api/dto/member.dto.ts
type MemberListRequestDto (line 9) | interface MemberListRequestDto {
type MemberListResponseDto (line 16) | interface MemberListResponseDto {
type MemberDto (line 21) | interface MemberDto {
type InviteMemberRequestDto (line 33) | interface InviteMemberRequestDto {
type InviteMemberResponseDto (line 39) | interface InviteMemberResponseDto {
type RemoveMemberRequestDto (line 47) | interface RemoveMemberRequestDto {
type RemoveMemberResponseDto (line 52) | interface RemoveMemberResponseDto {
type UpdateProfileRequestDto (line 58) | interface UpdateProfileRequestDto {
type UpdateProfileResponseDto (line 63) | interface UpdateProfileResponseDto {
type ResendInvitationRequestDto (line 69) | interface ResendInvitationRequestDto {
type ResendInvitationResponseDto (line 73) | interface ResendInvitationResponseDto {
FILE: next_b2b_starter/lib/api/api/dto/organization.dto.ts
type CreateOrganizationRequestDto (line 1) | interface CreateOrganizationRequestDto {
type CreateOrganizationResponseDto (line 6) | interface CreateOrganizationResponseDto {
FILE: next_b2b_starter/lib/api/api/dto/profile.dto.ts
type ProfileOrganizationDto (line 5) | interface ProfileOrganizationDto {
type ProfileResponseDto (line 12) | interface ProfileResponseDto {
FILE: next_b2b_starter/lib/api/api/dto/rbac.dto.ts
type RbacPermissionDto (line 3) | interface RbacPermissionDto {
type RbacRoleDto (line 12) | interface RbacRoleDto {
type RbacRolesResponseDto (line 20) | interface RbacRolesResponseDto {
FILE: next_b2b_starter/lib/api/api/repositories/cognitive-repository.ts
class CognitiveRepository (line 22) | class CognitiveRepository {
method chat (line 26) | async chat(request: ChatRequest): Promise<ChatResponse> {
method listSessions (line 62) | async listSessions(): Promise<ChatSession[]> {
method getSessionMessages (line 87) | async getSessionMessages(sessionId: number): Promise<ChatMessage[]> {
method toSession (line 105) | private toSession(dto: ChatSessionDto): ChatSession {
method toMessage (line 117) | private toMessage(dto: ChatMessageDto): ChatMessage {
method toSimilarDocument (line 132) | private toSimilarDocument(dto: SimilarDocumentDto): SimilarDocument {
FILE: next_b2b_starter/lib/api/api/repositories/document-repository.ts
class DocumentRepository (line 16) | class DocumentRepository {
method uploadDocument (line 20) | async uploadDocument(file: File, title: string): Promise<Document> {
method listDocuments (line 36) | async listDocuments(options?: DocumentListFilter): Promise<DocumentLis...
method deleteDocument (line 92) | async deleteDocument(id: number): Promise<boolean> {
method toDocument (line 100) | private toDocument(dto: DocumentDto | UploadDocumentResponseDto): Docu...
FILE: next_b2b_starter/lib/api/api/repositories/member-repository.ts
class MemberRepository (line 27) | class MemberRepository {
method getProfile (line 31) | async getProfile(): Promise<UserProfile> {
method updateProfile (line 61) | async updateProfile(request: UpdateProfileRequest): Promise<UserProfil...
method getMembers (line 93) | async getMembers(options?: {
method inviteMember (line 147) | async inviteMember(
method removeMember (line 173) | async removeMember(memberId: string): Promise<boolean> {
method resendInvitation (line 184) | async resendInvitation(memberId: string): Promise<boolean> {
method toUserProfile (line 197) | private toUserProfile(dto: ProfileResponseDto): UserProfile {
method toOrganizationMember (line 232) | private toOrganizationMember(dto: MemberDto): OrganizationMember {
FILE: next_b2b_starter/lib/api/api/repositories/profile-repository.ts
class ProfileRepository (line 8) | class ProfileRepository {
method getProfile (line 19) | async getProfile(sessionToken?: string): Promise<ProfileResponseDto> {
FILE: next_b2b_starter/lib/api/api/repositories/rbac-repository.ts
type RbacPermission (line 10) | interface RbacPermission {
type RbacRole (line 19) | interface RbacRole {
class RbacRepository (line 27) | class RbacRepository {
method getRoles (line 34) | async getRoles(forceRefresh = false): Promise<RbacRole[]> {
method toRbacRole (line 48) | private toRbacRole(dto: RbacRoleDto): RbacRole {
method toRbacPermission (line 60) | private toRbacPermission(dto: RbacPermissionDto): RbacPermission {
FILE: next_b2b_starter/lib/api/api/repositories/signup-repository.ts
class SignupRepository (line 15) | class SignupRepository {
method bootstrapOrganization (line 17) | async bootstrapOrganization(
method createOrganizationWithMagicLink (line 38) | async createOrganizationWithMagicLink(
method toSignupResult (line 69) | private toSignupResult(dto: BootstrapOrganizationResponseDto): SignupR...
method toMagicLinkResult (line 81) | private toMagicLinkResult(dto
Condensed preview — 479 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,104K chars).
[
{
"path": ".editorconfig",
"chars": 225,
"preview": "root = true\n\n[*]\nindent_style = space\nindent_size = 4\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newli"
},
{
"path": ".gitignore",
"chars": 2111,
"preview": "# --- Global OS Files ---\n.DS_Store\nThumbs.db\n\n# --- Global Editor Files ---\n.idea/\n.vscode/\n*.swp\n*.swo\n\n# --- Secrets "
},
{
"path": "CLAUDE.md",
"chars": 2538,
"preview": "# CLAUDE.md\n\nGuidance for Claude Code when working with this monorepo.\n\n## Monorepo Structure\n\nProduction SaaS Starter -"
},
{
"path": "Caddyfile",
"chars": 1657,
"preview": "# Caddyfile - Production reverse proxy configuration\n#\n# Routes traffic between Next.js frontend and Go backend:\n# - Nex"
},
{
"path": "DEVELOPMENT.md",
"chars": 10695,
"preview": "# 🛠️ Local Development Setup\n\nComplete guide to running the Production SaaS Starter Kit locally.\n\n---\n\n## 📋 Prerequisite"
},
{
"path": "LICENSE",
"chars": 1071,
"preview": "MIT License\n\nCopyright (c) 2025 Mohammed Salim\n\nPermission is hereby granted, free of charge, to any person obtaining a "
},
{
"path": "README.md",
"chars": 4966,
"preview": "# ⭐ Production SaaS Starter Kit\n\nThe Enterprise-Grade SaaS boilerplate for serious founders. Built with **Next.js 16** a"
},
{
"path": "SECURITY.md",
"chars": 450,
"preview": "# Security Policy\n\n## Supported Versions\n\nUse this section to tell people about which versions of your project are\ncurre"
},
{
"path": "SETUP.md",
"chars": 1273,
"preview": "# 🛠️ Setup Guide\n\n> **Looking for detailed setup?** See **[DEVELOPMENT.md](./DEVELOPMENT.md)** for comprehensive guidanc"
},
{
"path": "docker-compose.production.yml",
"chars": 4028,
"preview": "# Production Docker Compose\n# Copy to docker-compose.yml and configure with your .env file\n#\n# Required environment vari"
},
{
"path": "go-b2b-starter/.air.toml",
"chars": 865,
"preview": "root = \".\"\ntestdata_dir = \"testdata\"\ntmp_dir = \"tmp\"\n\n[build]\n args_bin = []\n bin = \"./tmp/main\"\n cmd = \"go build -o "
},
{
"path": "go-b2b-starter/.claude/CLAUDE.md",
"chars": 22233,
"preview": "# CLAUDE.md\n\nAI instructions for working with this Go B2B SaaS Starter Kit codebase.\n\n## Project Overview\n\nGo B2B SaaS S"
},
{
"path": "go-b2b-starter/.dockerignore",
"chars": 509,
"preview": "# Environment and configuration files\napp.env\n.env\n.air.toml\nexample.env\n\n# Version control\n.git\n.gitignore\n.gitlab-ci.y"
},
{
"path": "go-b2b-starter/.gitignore",
"chars": 5,
"preview": "/api\n"
},
{
"path": "go-b2b-starter/.gitlab-ci.yml",
"chars": 830,
"preview": "stages:\n - test\n - build\n\nrun-tests:\n stage: test\n image: golang:1.22.4\n script:\n - mkdir -p coverage\n - bash"
},
{
"path": "go-b2b-starter/Dockerfile",
"chars": 1386,
"preview": "# Builder stage\nFROM golang:1.25-alpine3.20 AS builder\n\nWORKDIR /app\n\n# Install build dependencies\nRUN apk add --no-cach"
},
{
"path": "go-b2b-starter/Makefile",
"chars": 2923,
"preview": "COMPOSE_FILE := deps/docker-compose.yml\nMIGRATION_PATH ?= schema/migration\nPOSTGRES_HOST ?= localhost\nPOSTGRES_PORT ?= 5"
},
{
"path": "go-b2b-starter/README.md",
"chars": 3105,
"preview": "# Go B2B Starter Backend\n\nProfessional Modular Monolith backend for B2B SaaS using idiomatic Go project layout.\n\n## ⚡️ Q"
},
{
"path": "go-b2b-starter/cmd/api/main.go",
"chars": 737,
"preview": "// Package main provides the entry point for the B2B SaaS Starter\n//\n//\t@title\t\t\tB2B SaaS Starter API\n//\t@version\t\t1.0\n/"
},
{
"path": "go-b2b-starter/deps/Dockerfile",
"chars": 413,
"preview": "FROM golang:1.25.5-alpine\n\nWORKDIR /workspace\n\n# Install system dependencies\nRUN apk add --no-cache git make bash curl\n\n"
},
{
"path": "go-b2b-starter/deps/docker-compose.yml",
"chars": 1036,
"preview": "services:\n postgres:\n image: pgvector/pgvector:pg17\n environment:\n POSTGRES_DB: mydatabase\n POSTGRES_US"
},
{
"path": "go-b2b-starter/docs/README.md",
"chars": 3169,
"preview": "# Go B2B SaaS Starter Kit\n\nA production-ready Go backend for B2B SaaS applications with multi-tenant architecture, authe"
},
{
"path": "go-b2b-starter/docs/adding-a-module.md",
"chars": 19662,
"preview": "# Adding a New Module\n\nThis guide shows how to create a new feature module following Clean Architecture and the idiomati"
},
{
"path": "go-b2b-starter/docs/api-development.md",
"chars": 8953,
"preview": "# API Development Guide\n\nStep-by-step guide to building new API endpoints following Clean Architecture patterns.\n\n## Ove"
},
{
"path": "go-b2b-starter/docs/architecture.md",
"chars": 12699,
"preview": "# Backend Architecture\n\nThe backend is a **Modular Monolith** using **idiomatic Go project layout** with Clear separatio"
},
{
"path": "go-b2b-starter/docs/authentication.md",
"chars": 7027,
"preview": "# Authentication Guide\n\nThe authentication system uses Stytch B2B for identity management with JWT verification, RBAC, a"
},
{
"path": "go-b2b-starter/docs/billing.md",
"chars": 5508,
"preview": "# Billing Guide\n\nThe billing system integrates with Polar.sh for subscription management, usage-based billing, and payme"
},
{
"path": "go-b2b-starter/docs/database.md",
"chars": 14653,
"preview": "# Database Guide\n\nThe database layer uses PostgreSQL with SQLC for type-safe SQL operations. Domain modules define repos"
},
{
"path": "go-b2b-starter/docs/event-bus.md",
"chars": 5010,
"preview": "# Event Bus Guide\n\nThe event bus enables event-driven architecture for loose coupling between modules using an in-memory"
},
{
"path": "go-b2b-starter/docs/file-manager.md",
"chars": 4997,
"preview": "# File Manager Guide\n\nThe file manager provides file storage using Cloudflare R2 (object storage) with PostgreSQL for se"
},
{
"path": "go-b2b-starter/example.env",
"chars": 2405,
"preview": "# Go B2B SaaS Starter Kit - Environment Configuration Template\n# Copy this file to app.env and fill in your actual value"
},
{
"path": "go-b2b-starter/go.mod",
"chars": 5052,
"preview": "module github.com/moasq/go-b2b-starter\n\ngo 1.25\n\nrequire (\n\tgithub.com/KyleBanks/depth v1.2.1\n\tgithub.com/MicahParks/key"
},
{
"path": "go-b2b-starter/go.sum",
"chars": 32552,
"preview": "entgo.io/ent v0.14.3 h1:wokAV/kIlH9TeklJWGGS7AYJdVckr0DloWjIcO9iIIQ=\nentgo.io/ent v0.14.3/go.mod h1:aDPE/OziPEu8+OWbzy4U"
},
{
"path": "go-b2b-starter/internal/api/provider.go",
"chars": 3297,
"preview": "package api\n\nimport (\n\t\"go.uber.org/dig\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/auth\"\n\t\"github.com/moasq/go"
},
{
"path": "go-b2b-starter/internal/bootstrap/init_mods.go",
"chars": 4891,
"preview": "package bootstrap\n\nimport (\n\t\"context\"\n\n\t\"go.uber.org/dig\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/api\"\n\t\"github.com"
},
{
"path": "go-b2b-starter/internal/bootstrap/root.go",
"chars": 477,
"preview": "package bootstrap\n\nimport (\n\t\"log\"\n\n\t\"github.com/joho/godotenv\"\n\t\"go.uber.org/dig\"\n\n\tserver \"github.com/moasq/go-b2b-sta"
},
{
"path": "go-b2b-starter/internal/db/README.md",
"chars": 6836,
"preview": "# Database Layer Guide\n\nThis guide shows you how to work with the database layer using our adapter pattern. It's designe"
},
{
"path": "go-b2b-starter/internal/db/adapters/cognitive_store.go",
"chars": 2250,
"preview": "package adapters\n\nimport (\n\t\"context\"\n\n\tdb \"github.com/moasq/go-b2b-starter/internal/db/postgres/sqlc/gen\"\n\t\"github.com/"
},
{
"path": "go-b2b-starter/internal/db/adapters/document_store.go",
"chars": 1332,
"preview": "package adapters\n\nimport (\n\t\"context\"\n\n\tdb \"github.com/moasq/go-b2b-starter/internal/db/postgres/sqlc/gen\"\n)\n\n// Documen"
},
{
"path": "go-b2b-starter/internal/db/adapters/file_asset_store.go",
"chars": 1620,
"preview": "package adapters\n\nimport (\n\t\"context\"\n\t\n\tdb \"github.com/moasq/go-b2b-starter/internal/db/postgres/sqlc/gen\"\n)\n\n// FileAs"
},
{
"path": "go-b2b-starter/internal/db/adapters/organization_store.go",
"chars": 2449,
"preview": "package adapters\n\nimport (\n\t\"context\"\n\n\tdb \"github.com/moasq/go-b2b-starter/internal/db/postgres/sqlc/gen\"\n\t\"github.com/"
},
{
"path": "go-b2b-starter/internal/db/adapters/subscription_store.go",
"chars": 1435,
"preview": "package adapters\n\nimport (\n\t\"context\"\n\n\tdb \"github.com/moasq/go-b2b-starter/internal/db/postgres/sqlc/gen\"\n)\n\n// Subscri"
},
{
"path": "go-b2b-starter/internal/db/cmd/init.go",
"chars": 117,
"preview": "package cmd\n\nimport (\n\t\"go.uber.org/dig\"\n)\n\nfunc Init(container *dig.Container) {\n\tProvideDependencies(container)\n\n}\n"
},
{
"path": "go-b2b-starter/internal/db/cmd/providers.go",
"chars": 558,
"preview": "package cmd\n\nimport (\n\t\"github.com/moasq/go-b2b-starter/internal/db\"\n\t\"go.uber.org/dig\"\n)\n\n// ProvideDependencies regist"
},
{
"path": "go-b2b-starter/internal/db/core/connection.go",
"chars": 1813,
"preview": "package core\n\nimport (\n\t\"context\"\n\t\"time\"\n)\n\n// Connection represents a database connection interface\ntype Connection in"
},
{
"path": "go-b2b-starter/internal/db/core/errors.go",
"chars": 2121,
"preview": "package core\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n)\n\n// Common database errors\nvar (\n\t// ErrNoRows is returned when a query return"
},
{
"path": "go-b2b-starter/internal/db/core/transaction.go",
"chars": 1056,
"preview": "package core\n\nimport \"context\"\n\n// Transaction represents a database transaction\ntype Transaction interface {\n\tConnectio"
},
{
"path": "go-b2b-starter/internal/db/helpers/helpers.go",
"chars": 2500,
"preview": "// Package helpers provides utility functions for converting between Go types\n// and PostgreSQL types (pgtype, pgvector)"
},
{
"path": "go-b2b-starter/internal/db/inject.go",
"chars": 9320,
"preview": "package db\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\n\t\"github.com/jackc/pgx/v5/pgxpool\"\n\t\"github.com/jackc/pgx/v5/std"
},
{
"path": "go-b2b-starter/internal/db/postgres/adapter_impl/cognitive_store.go",
"chars": 3557,
"preview": "package adapterimpl\n\nimport (\n\t\"context\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/db/adapters\"\n\tsqlc \"github.com/moas"
},
{
"path": "go-b2b-starter/internal/db/postgres/adapter_impl/document_store.go",
"chars": 2382,
"preview": "package adapterimpl\n\nimport (\n\t\"context\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/db/adapters\"\n\tsqlc \"github.com/moas"
},
{
"path": "go-b2b-starter/internal/db/postgres/adapter_impl/file_asset_store.go",
"chars": 2858,
"preview": "package adapterimpl\n\nimport (\n\t\"context\"\n\n\tsqlc \"github.com/moasq/go-b2b-starter/internal/db/postgres/sqlc/gen\"\n\t\"github"
},
{
"path": "go-b2b-starter/internal/db/postgres/adapter_impl/organization_store.go",
"chars": 4414,
"preview": "package adapterimpl\n\nimport (\n\t\"context\"\n\n\tsqlc \"github.com/moasq/go-b2b-starter/internal/db/postgres/sqlc/gen\"\n\t\"github"
},
{
"path": "go-b2b-starter/internal/db/postgres/adapter_impl/subscription_store.go",
"chars": 2563,
"preview": "package adapterimpl\n\nimport (\n\t\"context\"\n\n\tsqlc \"github.com/moasq/go-b2b-starter/internal/db/postgres/sqlc/gen\"\n\t\"github"
},
{
"path": "go-b2b-starter/internal/db/postgres/connection.go",
"chars": 1405,
"preview": "package postgres\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/jackc/pgx/v5\"\n\t\"github.com/jackc/pgx/v5/pgxpool\"\n)\n\nfu"
},
{
"path": "go-b2b-starter/internal/db/postgres/db_config.go",
"chars": 2509,
"preview": "package postgres\n\nimport (\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/spf13/viper\"\n)\n\ntype Config struct {\n\tHost string `mapst"
},
{
"path": "go-b2b-starter/internal/db/postgres/init.go",
"chars": 1099,
"preview": "package postgres\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/jackc/pgx/v5/pgxpool\"\n)\n\n// InitDB initializes and re"
},
{
"path": "go-b2b-starter/internal/db/postgres/postgres_manager.go",
"chars": 4071,
"preview": "package postgres\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"sort\"\n\n\t\"github.com/jackc/pgx/v5/pgxpool\"\n\n\t\"context\"\n\n\t\"path/filepath\""
},
{
"path": "go-b2b-starter/internal/db/postgres/retry.go",
"chars": 1324,
"preview": "package postgres\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"log\"\n\t\"time\"\n)\n\nconst (\n\tmaxRetries = 3\n\tretryDelay = 100 * time"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/gen/cognitive.sql.go",
"chars": 13850,
"preview": "// Code generated by sqlc. DO NOT EDIT.\n// versions:\n// sqlc v1.26.0\n// source: cognitive.sql\n\npackage postgres\n\nimpor"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/gen/db.go",
"chars": 570,
"preview": "// Code generated by sqlc. DO NOT EDIT.\n// versions:\n// sqlc v1.26.0\n\npackage postgres\n\nimport (\n\t\"context\"\n\n\t\"github."
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/gen/documents.sql.go",
"chars": 10304,
"preview": "// Code generated by sqlc. DO NOT EDIT.\n// versions:\n// sqlc v1.26.0\n// source: documents.sql\n\npackage postgres\n\nimpor"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/gen/error.go",
"chars": 410,
"preview": "package postgres\n\nimport (\n\t\"errors\"\n\n\t\"github.com/jackc/pgx/v5\"\n\t\"github.com/jackc/pgx/v5/pgconn\"\n)\n\nconst (\n\tForeignKe"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/gen/example_resource.sql.go",
"chars": 22288,
"preview": "// Code generated by sqlc. DO NOT EDIT.\n// versions:\n// sqlc v1.26.0\n// source: example_resource.sql\n\npackage postgres"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/gen/exec.go",
"chars": 460,
"preview": "package postgres\n\nimport (\n\t\"context\"\n\t\"fmt\"\n)\n\n// ExecTx executes a function within a database transaction\nfunc (store "
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/gen/file_manager.sql.go",
"chars": 15781,
"preview": "// Code generated by sqlc. DO NOT EDIT.\n// versions:\n// sqlc v1.26.0\n// source: files.sql\n\npackage postgres\n\nimport (\n"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/gen/models.go",
"chars": 10257,
"preview": "// Code generated by sqlc. DO NOT EDIT.\n// versions:\n// sqlc v1.26.0\n\npackage postgres\n\nimport (\n\t\"github.com/jackc/pg"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/gen/organizations.sql.go",
"chars": 22311,
"preview": "// Code generated by sqlc. DO NOT EDIT.\n// versions:\n// sqlc v1.26.0\n// source: organizations.sql\n\npackage postgres\n\ni"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/gen/querier.go",
"chars": 10342,
"preview": "// Code generated by sqlc. DO NOT EDIT.\n// versions:\n// sqlc v1.26.0\n\npackage postgres\n\nimport (\n\t\"context\"\n\n\t\"github."
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/gen/resource_embeddings.sql.go",
"chars": 19589,
"preview": "// Code generated by sqlc. DO NOT EDIT.\n// versions:\n// sqlc v1.26.0\n// source: resource_embeddings.sql\n\npackage postg"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/gen/store.go",
"chars": 628,
"preview": "// Code generated by sqlc. DO NOT EDIT.\n// versions:\n// sqlc v1.26.0\n\npackage postgres\n\nimport (\n\t\"context\"\n\n\t\"github."
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/gen/subscription_billing.sql.go",
"chars": 14414,
"preview": "// Code generated by sqlc. DO NOT EDIT.\n// versions:\n// sqlc v1.26.0\n// source: subscription_billing.sql\n\npackage post"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000001_create_file_manager_schema.down.sql",
"chars": 513,
"preview": "BEGIN;\n\n-- Drop indexes\nDROP INDEX IF EXISTS file_manager.idx_file_assets_entity;\nDROP INDEX IF EXISTS file_manager.idx_"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000001_create_file_manager_schema.up.sql",
"chars": 2197,
"preview": "CREATE SCHEMA IF NOT EXISTS file_manager;\n\n-- Create file categories table (similar to asset_types)\nCREATE TABLE file_ma"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000002_create_organizations_schema.down.sql",
"chars": 1001,
"preview": "-- Drop triggers\nDROP TRIGGER IF EXISTS trigger_accounts_updated_at ON organizations.accounts;\nDROP TRIGGER IF EXISTS tr"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000002_create_organizations_schema.up.sql",
"chars": 4735,
"preview": "-- Create organizations schema\nCREATE SCHEMA IF NOT EXISTS organizations;\n\n-- Organizations table (top-level tenant)\nCRE"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000003_enforce_role_enum.down.sql",
"chars": 177,
"preview": "-- Rollback: Remove RBAC roles enum constraint\n\n-- Drop the check constraint that enforces valid role values\nALTER TABLE"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000003_enforce_role_enum.up.sql",
"chars": 1051,
"preview": "-- Enforce RBAC roles enum according to PERMISSIONS.md specification\n-- Valid roles: member, approver, admin (plus legac"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000004_create_subscription_billing_schema.down.sql",
"chars": 238,
"preview": "-- Drop subscription billing schema and all its tables\nDROP TABLE IF EXISTS subscription_billing.quota_tracking CASCADE;"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000004_create_subscription_billing_schema.up.sql",
"chars": 3598,
"preview": "-- Create subscription_billing schema for local subscription and quota tracking\nCREATE SCHEMA IF NOT EXISTS subscription"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000005_update_quota_tracking_schema.down.sql",
"chars": 1093,
"preview": "-- Rollback quota_tracking schema changes\n-- Restore invoice_count_max and invoice_count_current\n\n-- Step 1: Add back ol"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000005_update_quota_tracking_schema.up.sql",
"chars": 1026,
"preview": "-- Update quota_tracking schema to use count-down system\n-- Remove invoice_count_max, rename invoice_count_current to in"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000006_create_example_resources.down.sql",
"chars": 714,
"preview": "-- Rollback example_resources table\n\n-- Drop trigger first\nDROP TRIGGER IF EXISTS trigger_update_example_resources_updat"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000006_create_example_resources.up.sql",
"chars": 3361,
"preview": "-- Create example_resources table\n-- This table demonstrates the full architecture pattern with:\n-- - File attachments\n-"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000007_create_resource_embeddings.down.sql",
"chars": 679,
"preview": "-- Drop triggers\nDROP TRIGGER IF EXISTS duplicate_candidates_updated_at ON duplicate_candidates;\nDROP TRIGGER IF EXISTS "
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000007_create_resource_embeddings.up.sql",
"chars": 5142,
"preview": "-- Enable pgvector extension for vector similarity search\nCREATE EXTENSION IF NOT EXISTS vector;\n\n-- Resource embeddings"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000008_create_documents_schema.down.sql",
"chars": 233,
"preview": "-- Drop documents schema\nDROP TRIGGER IF EXISTS documents_updated_at ON documents.documents;\nDROP FUNCTION IF EXISTS doc"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000008_create_documents_schema.up.sql",
"chars": 1846,
"preview": "-- Documents schema for PDF upload and text extraction\nCREATE SCHEMA IF NOT EXISTS documents;\n\n-- Documents table\nCREATE"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000009_create_cognitive_schema.down.sql",
"chars": 491,
"preview": "-- Drop cognitive schema\nDROP TRIGGER IF EXISTS chat_sessions_updated_at ON cognitive.chat_sessions;\nDROP TRIGGER IF EXI"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/migrations/000009_create_cognitive_schema.up.sql",
"chars": 3816,
"preview": "-- Cognitive Agent schema for RAG and AI-powered features\nCREATE SCHEMA IF NOT EXISTS cognitive;\n\n-- Ensure pgvector ext"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/query/cognitive.sql",
"chars": 2639,
"preview": "-- Cognitive Agent queries\n\n-- Document Embeddings\n\n-- name: CreateDocumentEmbedding :one\nINSERT INTO cognitive.document"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/query/documents.sql",
"chars": 1720,
"preview": "-- Documents queries\n\n-- name: CreateDocument :one\nINSERT INTO documents.documents (\n organization_id,\n file_asset"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/query/example_resource.sql",
"chars": 5905,
"preview": "-- Example Resource Queries\n-- Demonstrates Clean Architecture patterns with CRUD operations,\n-- file attachments, OCR/L"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/query/file_manager.sql",
"chars": 2092,
"preview": "-- name: CreateFileAsset :one\nINSERT INTO file_manager.file_assets (\n file_name,\n original_file_name,\n storage_"
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/query/organizations.sql",
"chars": 7231,
"preview": "-- name: CreateOrganization :one\nINSERT INTO organizations.organizations (\n slug,\n name,\n status\n) VALUES (\n "
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/query/subscription_billing.sql",
"chars": 4116,
"preview": "-- name: GetSubscriptionByOrgID :one\n-- Get subscription details for an organization\nSELECT * FROM subscription_billing."
},
{
"path": "go-b2b-starter/internal/db/postgres/sqlc/sqlc.yml",
"chars": 508,
"preview": "version: \"2\"\nsql:\n - schema: \"./migrations\"\n queries: \"./query\"\n engine: \"postgresql\"\n gen:\n go:\n "
},
{
"path": "go-b2b-starter/internal/db/postgres/types_transform.go",
"chars": 8860,
"preview": "package postgres\n\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/jackc/pgx/v"
},
{
"path": "go-b2b-starter/internal/docs/api/handler.go",
"chars": 88,
"preview": "package api\n\ntype Handler struct {\n}\n\nfunc NewHandler() *Handler {\n\treturn &Handler{}\n}\n"
},
{
"path": "go-b2b-starter/internal/docs/api/routes.go",
"chars": 574,
"preview": "package api\n\nimport (\n\tdocs \"github.com/moasq/go-b2b-starter/internal/docs/gen\"\n\t\"github.com/moasq/go-b2b-starter/intern"
},
{
"path": "go-b2b-starter/internal/docs/cmd/init.go",
"chars": 415,
"preview": "package cmd\n\nimport (\n\t\"log\"\n\n\t\"go.uber.org/dig\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/docs/api\"\n\tserver \"github.c"
},
{
"path": "go-b2b-starter/internal/docs/gen/docs.go",
"chars": 55982,
"preview": "// Package gen Code generated by swaggo/swag. DO NOT EDIT\npackage gen\n\nimport \"github.com/swaggo/swag\"\n\nconst docTemplat"
},
{
"path": "go-b2b-starter/internal/docs/gen/swagger.json",
"chars": 55317,
"preview": "{\n \"swagger\": \"2.0\",\n \"info\": {\n \"description\": \"This is the API server for B2B SaaS Starter.\",\n \"ti"
},
{
"path": "go-b2b-starter/internal/docs/gen/swagger.yaml",
"chars": 29838,
"preview": "basePath: /api\ndefinitions:\n github_com_moasq_go-b2b-starter_internal_modules_billing_domain.BillingStatus:\n propert"
},
{
"path": "go-b2b-starter/internal/modules/auth/README.md",
"chars": 9339,
"preview": "# Auth Package\n\nProvider-agnostic authentication and authorization with type-safe middleware. Supports JWT verification,"
},
{
"path": "go-b2b-starter/internal/modules/auth/adapters/stytch/adapter.go",
"chars": 5334,
"preview": "// Package stytch provides Stytch B2B authentication integration.\n//\n// This package implements the auth.AuthProvider in"
},
{
"path": "go-b2b-starter/internal/modules/auth/adapters/stytch/config.go",
"chars": 4880,
"preview": "package stytch\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/spf13/viper\"\n)\n\n// Environment constants supported by t"
},
{
"path": "go-b2b-starter/internal/modules/auth/adapters/stytch/jwks_cache.go",
"chars": 6322,
"preview": "package stytch\n\nimport (\n\t\"context\"\n\t\"crypto/rsa\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math/big\"\n\t\"net/http\"\n\t\"t"
},
{
"path": "go-b2b-starter/internal/modules/auth/adapters/stytch/jwt_parser.go",
"chars": 2326,
"preview": "package stytch\n\nimport (\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n)\n\n// JWTParser provides JWT token parsin"
},
{
"path": "go-b2b-starter/internal/modules/auth/adapters/stytch/mock_adapter.go",
"chars": 2669,
"preview": "package stytch\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/auth\"\n\t\"github.co"
},
{
"path": "go-b2b-starter/internal/modules/auth/adapters/stytch/rbac_policy.go",
"chars": 5894,
"preview": "package stytch\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/moasq/go-b2b-starter/intern"
},
{
"path": "go-b2b-starter/internal/modules/auth/adapters/stytch/token_verifier.go",
"chars": 12961,
"preview": "package stytch\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/golang-jwt/jwt/v5\"\n\t\"github.com/mo"
},
{
"path": "go-b2b-starter/internal/modules/auth/auth.go",
"chars": 7634,
"preview": "// Package auth provides a unified authentication and authorization layer.\n//\n// This package abstracts away the authent"
},
{
"path": "go-b2b-starter/internal/modules/auth/cmd/init.go",
"chars": 3041,
"preview": "// Package cmd provides initialization for the auth module.\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/moasq/"
},
{
"path": "go-b2b-starter/internal/modules/auth/context.go",
"chars": 5243,
"preview": "package auth\n\nimport (\n\t\"context\"\n\n\t\"github.com/gin-gonic/gin\"\n)\n\n// Context keys for storing auth data.\n// Using unexpo"
},
{
"path": "go-b2b-starter/internal/modules/auth/errors.go",
"chars": 3199,
"preview": "package auth\n\nimport \"errors\"\n\n// Authentication and authorization errors.\n//\n// These errors are returned by the auth p"
},
{
"path": "go-b2b-starter/internal/modules/auth/handler.go",
"chars": 5016,
"preview": "package auth\n\nimport (\n\t\"net/http\"\n\n\t\"github.com/gin-gonic/gin\"\n\n\t\"github.com/moasq/go-b2b-starter/pkg/response\"\n)\n\n// H"
},
{
"path": "go-b2b-starter/internal/modules/auth/middleware.go",
"chars": 13352,
"preview": "package auth\n\nimport (\n\t\"context\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/gin-gonic/gin\"\n)\n\n// OrganizationResolver looks u"
},
{
"path": "go-b2b-starter/internal/modules/auth/permissions.go",
"chars": 5391,
"preview": "package auth\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// Permission represents an authorization permission in \"resource:action\" fo"
},
{
"path": "go-b2b-starter/internal/modules/auth/provider.go",
"chars": 3955,
"preview": "package auth\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/gin-gonic/gin\"\n\t\"go.uber.org/dig\"\n)\n\n// ServerMiddlewareRegistrar is the int"
},
{
"path": "go-b2b-starter/internal/modules/auth/rbac.go",
"chars": 13876,
"preview": "package auth\n\n// =============================================================================\n// RBAC DEFINITIONS - Rol"
},
{
"path": "go-b2b-starter/internal/modules/auth/resolvers.go",
"chars": 3483,
"preview": "package auth\n\nimport (\n\t\"context\"\n\t\"fmt\"\n)\n\n// OrganizationLookup is the minimal interface needed to resolve organizatio"
},
{
"path": "go-b2b-starter/internal/modules/auth/roles.go",
"chars": 4051,
"preview": "package auth\n\n// Role represents a user role in the system.\n//\n// Roles are assigned to users and determine their base p"
},
{
"path": "go-b2b-starter/internal/modules/auth/routes.go",
"chars": 1938,
"preview": "package auth\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\n\tserverDomain \"github.com/moasq/go-b2b-starter/internal/platform/ser"
},
{
"path": "go-b2b-starter/internal/modules/billing/README.md",
"chars": 17592,
"preview": "# Billing Module\n\nHybrid subscription lifecycle management for B2B SaaS applications. This module combines **event-drive"
},
{
"path": "go-b2b-starter/internal/modules/billing/app/services/check_quota_availability_service.go",
"chars": 2554,
"preview": "package services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/billing/domain\""
},
{
"path": "go-b2b-starter/internal/modules/billing/app/services/consume_invoice_quota_service.go",
"chars": 3927,
"preview": "package services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/billing/domain\""
},
{
"path": "go-b2b-starter/internal/modules/billing/app/services/get_billing_status_service.go",
"chars": 1350,
"preview": "package services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/billing/domain\""
},
{
"path": "go-b2b-starter/internal/modules/billing/app/services/module.go",
"chars": 1632,
"preview": "package services\n\nimport (\n\t\"go.uber.org/dig\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/billing/domain\"\n\t\"gith"
},
{
"path": "go-b2b-starter/internal/modules/billing/app/services/process_webhook_event_service.go",
"chars": 26488,
"preview": "package services\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/moasq/go-b2b-"
},
{
"path": "go-b2b-starter/internal/modules/billing/app/services/refresh_subscription_status_service.go",
"chars": 2027,
"preview": "package services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/billing/domain\""
},
{
"path": "go-b2b-starter/internal/modules/billing/app/services/subscription_service_dec.go",
"chars": 4470,
"preview": "package services\n\nimport (\n\t\"context\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/billing/domain\"\n\tlogger \"githu"
},
{
"path": "go-b2b-starter/internal/modules/billing/app/services/sync_subscription_service.go",
"chars": 2208,
"preview": "package services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/bill"
},
{
"path": "go-b2b-starter/internal/modules/billing/app/services/verify_and_consume_quota_service.go",
"chars": 2733,
"preview": "package services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/billing/domain\""
},
{
"path": "go-b2b-starter/internal/modules/billing/app/services/verify_payment_service.go",
"chars": 3838,
"preview": "package services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"time\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/bill"
},
{
"path": "go-b2b-starter/internal/modules/billing/cmd/init.go",
"chars": 584,
"preview": "package cmd\n\nimport (\n\t\"go.uber.org/dig\"\n)\n\n//\n// The billing module handles subscription lifecycle management with Pola"
},
{
"path": "go-b2b-starter/internal/modules/billing/cmd/provider.go",
"chars": 1091,
"preview": "package cmd\n\nimport (\n\t\"fmt\"\n\n\t\"go.uber.org/dig\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/billing/app/service"
},
{
"path": "go-b2b-starter/internal/modules/billing/domain/errors.go",
"chars": 1183,
"preview": "package domain\n\nimport \"errors\"\n\nvar (\n\t// ErrSubscriptionNotFound is returned when a subscription cannot be found\n\tErrS"
},
{
"path": "go-b2b-starter/internal/modules/billing/domain/repository.go",
"chars": 1663,
"preview": "package domain\n\nimport \"context\"\n\n// SubscriptionRepository provides database operations for subscriptions and quotas\nty"
},
{
"path": "go-b2b-starter/internal/modules/billing/domain/types.go",
"chars": 2690,
"preview": "package domain\n\nimport \"time\"\n\n// Subscription represents a billing subscription from Polar\ntype Subscription struct {\n\t"
},
{
"path": "go-b2b-starter/internal/modules/billing/handler.go",
"chars": 6481,
"preview": "package billing\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/gin-gonic/gin\"\n\n\t\"github.com/moasq/go-b2b-s"
},
{
"path": "go-b2b-starter/internal/modules/billing/infra/adapters/status_provider.go",
"chars": 4090,
"preview": "// Package adapters provides adapter implementations for external interfaces.\npackage adapters\n\nimport (\n\t\"context\"\n\n\t\"g"
},
{
"path": "go-b2b-starter/internal/modules/billing/infra/polar/polar_adapter.go",
"chars": 11778,
"preview": "package polar\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/moasq/go-b2"
},
{
"path": "go-b2b-starter/internal/modules/billing/infra/repositories/organization_adapter.go",
"chars": 1245,
"preview": "package repositories\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/billing/domain\"\n\t\"g"
},
{
"path": "go-b2b-starter/internal/modules/billing/infra/repositories/subscription_repository.go",
"chars": 6938,
"preview": "package repositories\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/jackc/"
},
{
"path": "go-b2b-starter/internal/modules/billing/provider.go",
"chars": 425,
"preview": "package billing\n\nimport (\n\t\"go.uber.org/dig\"\n)\n\n// RegisterHandlers registers subscription API handlers in the DI contai"
},
{
"path": "go-b2b-starter/internal/modules/billing/routes.go",
"chars": 984,
"preview": "package billing\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/auth\"\n\tserverD"
},
{
"path": "go-b2b-starter/internal/modules/cognitive/app/services/document_listener.go",
"chars": 655,
"preview": "package services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n)\n\ntype documentListener struct {\n\tembeddingService EmbeddingService\n}\n\nfun"
},
{
"path": "go-b2b-starter/internal/modules/cognitive/app/services/embedding_service.go",
"chars": 3183,
"preview": "package services\n\nimport (\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\n\t\"github.com/moasq/go-b2b-starter/interna"
},
{
"path": "go-b2b-starter/internal/modules/cognitive/app/services/interface.go",
"chars": 2279,
"preview": "package services\n\nimport (\n\t\"context\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/cognitive/domain\"\n)\n\n// Embedd"
},
{
"path": "go-b2b-starter/internal/modules/cognitive/app/services/rag_service.go",
"chars": 7017,
"preview": "package services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/cognitive/do"
},
{
"path": "go-b2b-starter/internal/modules/cognitive/cmd/init.go",
"chars": 1309,
"preview": "package cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"go.uber.org/dig\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/cognitiv"
},
{
"path": "go-b2b-starter/internal/modules/cognitive/domain/ai_provider.go",
"chars": 1057,
"preview": "package domain\n\nimport \"context\"\n\n// TextVectorizer creates searchable vector representations of text content.\n// This e"
},
{
"path": "go-b2b-starter/internal/modules/cognitive/domain/entity.go",
"chars": 3869,
"preview": "package domain\n\nimport (\n\t\"time\"\n)\n\n// ChatRole represents the role of a message sender\ntype ChatRole string\n\nconst (\n\tC"
},
{
"path": "go-b2b-starter/internal/modules/cognitive/domain/errors.go",
"chars": 1334,
"preview": "package domain\n\nimport \"errors\"\n\n// Domain errors for cognitive module\nvar (\n\t// Embedding errors\n\tErrEmbeddingNotFound "
},
{
"path": "go-b2b-starter/internal/modules/cognitive/domain/repository.go",
"chars": 1947,
"preview": "package domain\n\nimport \"context\"\n\n// EmbeddingRepository defines the interface for embedding data operations\ntype Embedd"
},
{
"path": "go-b2b-starter/internal/modules/cognitive/handler.go",
"chars": 5060,
"preview": "package cognitive\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/moasq/go-b2b-starter"
},
{
"path": "go-b2b-starter/internal/modules/cognitive/infra/ai/assistant_provider.go",
"chars": 823,
"preview": "package ai\n\nimport (\n\t\"context\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/cognitive/domain\"\n\tllmdomain \"github"
},
{
"path": "go-b2b-starter/internal/modules/cognitive/infra/ai/text_vectorizer.go",
"chars": 593,
"preview": "package ai\n\nimport (\n\t\"context\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/cognitive/domain\"\n\tllmdomain \"github"
},
{
"path": "go-b2b-starter/internal/modules/cognitive/infra/repositories/chat_repository.go",
"chars": 5988,
"preview": "package repositories\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/db/helpers\"\n\tsqlc \"github.c"
},
{
"path": "go-b2b-starter/internal/modules/cognitive/infra/repositories/embedding_repository.go",
"chars": 4706,
"preview": "package repositories\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/db/helpers\"\n\tsqlc \"github.c"
},
{
"path": "go-b2b-starter/internal/modules/cognitive/infra/repositories/helpers.go",
"chars": 551,
"preview": "package repositories\n\nimport \"github.com/jackc/pgx/v5/pgtype\"\n\n// Helper functions for type conversion\n\nfunc toPgText(s "
},
{
"path": "go-b2b-starter/internal/modules/cognitive/module.go",
"chars": 2035,
"preview": "package cognitive\n\nimport (\n\t\"go.uber.org/dig\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/cognitive/app/service"
},
{
"path": "go-b2b-starter/internal/modules/cognitive/provider.go",
"chars": 452,
"preview": "package cognitive\n\nimport (\n\t\"go.uber.org/dig\"\n)\n\ntype Provider struct {\n\tcontainer *dig.Container\n}\n\nfunc NewProvider(c"
},
{
"path": "go-b2b-starter/internal/modules/cognitive/routes.go",
"chars": 1244,
"preview": "package cognitive\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/auth\"\n\tserve"
},
{
"path": "go-b2b-starter/internal/modules/documents/app/services/document_service.go",
"chars": 9293,
"preview": "package services\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/moasq/go-b2b-star"
},
{
"path": "go-b2b-starter/internal/modules/documents/app/services/interface.go",
"chars": 2392,
"preview": "package services\n\nimport (\n\t\"context\"\n\t\"io\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/documents/domain\"\n)\n\n// "
},
{
"path": "go-b2b-starter/internal/modules/documents/cmd/init.go",
"chars": 233,
"preview": "package cmd\n\nimport (\n\t\"go.uber.org/dig\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/documents\"\n)\n\nfunc Init(con"
},
{
"path": "go-b2b-starter/internal/modules/documents/domain/entity.go",
"chars": 2673,
"preview": "package domain\n\nimport (\n\t\"time\"\n)\n\n// DocumentStatus represents the processing status of a document\ntype DocumentStatus"
},
{
"path": "go-b2b-starter/internal/modules/documents/domain/errors.go",
"chars": 1065,
"preview": "package domain\n\nimport \"errors\"\n\n// Domain errors for documents\nvar (\n\t// Validation errors\n\tErrDocumentOrganizationRequ"
},
{
"path": "go-b2b-starter/internal/modules/documents/domain/events/document_events.go",
"chars": 2443,
"preview": "package events\n\nimport (\n\t\"time\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/moasq/go-b2b-starter/internal/platform/eventbus"
},
{
"path": "go-b2b-starter/internal/modules/documents/domain/repository.go",
"chars": 1589,
"preview": "package domain\n\nimport \"context\"\n\n// DocumentRepository defines the interface for document data operations\ntype Document"
},
{
"path": "go-b2b-starter/internal/modules/documents/handler.go",
"chars": 4781,
"preview": "package documents\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strconv\"\n\n\t\"github.com/gin-gonic/gin\"\n\n\t\"github.com/moasq/go-b2b-starte"
},
{
"path": "go-b2b-starter/internal/modules/documents/infra/repositories/document_repository.go",
"chars": 6339,
"preview": "package repositories\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/db/helpers\"\n\tsqlc \"github.c"
},
{
"path": "go-b2b-starter/internal/modules/documents/module.go",
"chars": 1255,
"preview": "package documents\n\nimport (\n\t\"go.uber.org/dig\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/documents/app/service"
},
{
"path": "go-b2b-starter/internal/modules/documents/provider.go",
"chars": 452,
"preview": "package documents\n\nimport (\n\t\"go.uber.org/dig\"\n)\n\ntype Provider struct {\n\tcontainer *dig.Container\n}\n\nfunc NewProvider(c"
},
{
"path": "go-b2b-starter/internal/modules/documents/routes.go",
"chars": 1184,
"preview": "package documents\n\nimport (\n\t\"github.com/gin-gonic/gin\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/auth\"\n\tserve"
},
{
"path": "go-b2b-starter/internal/modules/files/README.md",
"chars": 7102,
"preview": "# File Manager Guide\n\nSimple guide for uploading and managing files with Cloudflare R2 (S3-compatible storage).\n\n## Setu"
},
{
"path": "go-b2b-starter/internal/modules/files/cmd/init.go",
"chars": 317,
"preview": "package cmd\n\nimport (\n\t\"log\"\n\n\t\"go.uber.org/dig\"\n\t\"github.com/moasq/go-b2b-starter/internal/modules/files/config\"\n)\n\nfun"
},
{
"path": "go-b2b-starter/internal/modules/files/cmd/provider.go",
"chars": 1956,
"preview": "package cmd\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"go.uber.org/dig\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/files/co"
},
{
"path": "go-b2b-starter/internal/modules/files/config/config.go",
"chars": 1371,
"preview": "package config\n\nimport (\n\t\"github.com/spf13/viper\"\n)\n\ntype Config struct {\n\tR2 R2Config\n}\n\ntype R2Config struct {\n\tAccou"
},
{
"path": "go-b2b-starter/internal/modules/files/constants.go",
"chars": 2759,
"preview": "package files\n\nimport (\n\t\"strings\"\n)\n\n// File Type Categories\ntype FileCategory string\n\nconst (\n\tCategoryDocument FileCa"
},
{
"path": "go-b2b-starter/internal/modules/files/domain/entity.go",
"chars": 2116,
"preview": "package domain\n\nimport (\n\t\"time\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/files\"\n\t\"github.com/google/uuid\"\n)\n"
},
{
"path": "go-b2b-starter/internal/modules/files/domain/helpers.go",
"chars": 1512,
"preview": "package domain\n\nimport (\n\t\"context\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"io\"\n)\n\n// ConvertFileToBase64 reads a file from storage "
},
{
"path": "go-b2b-starter/internal/modules/files/domain/repository.go",
"chars": 2258,
"preview": "package domain\n\nimport (\n\t\"context\"\n\t\"io\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/files\"\n)\n\ntype FileReposit"
},
{
"path": "go-b2b-starter/internal/modules/files/domain/service.go",
"chars": 5919,
"preview": "package domain\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/fi"
},
{
"path": "go-b2b-starter/internal/modules/files/domain/validator.go",
"chars": 3530,
"preview": "package domain\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/gabriel-vasile/mimetype\"\n)\n\n//"
},
{
"path": "go-b2b-starter/internal/modules/files/infra/file_metadata_repository.go",
"chars": 10967,
"preview": "package infra\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/jackc/pgx/v5/pgtype\"\n"
},
{
"path": "go-b2b-starter/internal/modules/files/internal/infra/composite_repository.go",
"chars": 10792,
"preview": "package infra\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/files/config"
},
{
"path": "go-b2b-starter/internal/modules/files/internal/infra/db_repository.go",
"chars": 12821,
"preview": "package infra\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\n\t\"github.com/google/uuid\"\n\t\"github.com/jackc/pgx/v5/pgtype\"\n"
},
{
"path": "go-b2b-starter/internal/modules/files/internal/infra/mock_r2_repository.go",
"chars": 2085,
"preview": "package infra\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/files/dom"
},
{
"path": "go-b2b-starter/internal/modules/files/internal/infra/r2_repository.go",
"chars": 4481,
"preview": "package infra\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"time\"\n\n\t\"github.com/aws/aws-sdk-go-v2/aws\"\n\t\"github.com/aws/"
},
{
"path": "go-b2b-starter/internal/modules/organizations/account_handler.go",
"chars": 10852,
"preview": "package organizations\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/gin-gonic/gin\"\n\n\t\"github.com/moasq/go-b2b-starter/inter"
},
{
"path": "go-b2b-starter/internal/modules/organizations/app/services/member_service.go",
"chars": 6076,
"preview": "package services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"strings\"\n)\n\n// MemberService defines the core authentication and member m"
},
{
"path": "go-b2b-starter/internal/modules/organizations/app/services/member_service_impl.go",
"chars": 17618,
"preview": "package services\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/or"
},
{
"path": "go-b2b-starter/internal/modules/organizations/app/services/organization_service.go",
"chars": 6513,
"preview": "package services\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/organizations/domain\"\n)"
},
{
"path": "go-b2b-starter/internal/modules/organizations/app/services/organization_service_interface.go",
"chars": 4536,
"preview": "package services\n\nimport (\n\t\"context\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/organizations/domain\"\n)\n\n// Or"
},
{
"path": "go-b2b-starter/internal/modules/organizations/cmd/init.go",
"chars": 240,
"preview": "package cmd\n\nimport (\n\t\"go.uber.org/dig\"\n\n\t\"github.com/moasq/go-b2b-starter/internal/modules/organizations\"\n)\n\nfunc Init"
},
{
"path": "go-b2b-starter/internal/modules/organizations/domain/auth_provider.go",
"chars": 6498,
"preview": "package domain\n\nimport (\n\t\"context\"\n\t\"net/mail\"\n\t\"time\"\n)\n\n// AuthMember represents an authenticated member from the aut"
},
{
"path": "go-b2b-starter/internal/modules/organizations/domain/entity.go",
"chars": 2799,
"preview": "package domain\n\nimport \"time\"\n\n// Organization represents an organization (tenant) in the system\ntype Organization struc"
}
]
// ... and 279 more files (download for full content)
About this extraction
This page contains the full source code of the moasq/production-saas-starter GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 479 files (1.8 MB), approximately 487.3k tokens, and a symbol index with 2205 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.