main 701bff660c62 cached
479 files
1.8 MB
487.3k tokens
2205 symbols
1 requests
Download .txt
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**.

[![Go Report Card](https://goreportcard.com/badge/github.com/moasq/production-saas-starter)](https://goreportcard.com/report/github.com/moasq/production-saas-starter)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)

![Dashboard Preview](docs/dashboard.png)

## 🛠️ 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
Download .txt
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
Download .txt
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.

Copied to clipboard!