This repository was archived by the owner on Aug 14, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
Staging #347
Closed
Closed
Staging #347
Changes from all commits
Commits
Show all changes
67 commits
Select commit
Hold shift + click to select a range
9fc858c
sync dev to staging (#118)
ukemeikot 6bcf9e2
Chore/merge dev to staging (#122)
Taterbro 7a0abe1
syncing dev branch to staging (#128)
ukemeikot d7f60ab
sync dev to staging (#130)
ukemeikot 3c799b2
sync dev to staging (#131)
ukemeikot 5ce86a0
Mergin-dev-to-staging (#132)
Gospelmairo f692b4f
chore: sync dev to staging (catches YAML duplicate-tags fix) (#133)
ukemeikot d4d6156
fix(api): remove duplicate 'tags' keys breaking Swagger UI (#129) (#134)
ukemeikot 19350e5
Merge remote-tracking branch 'origin/dev' into chore/sync-dev-to-stag…
2a7d0ac
Merge pull request #136 from hngprojects/chore/sync-dev-to-staging-tr…
ukemeikot 537a13a
chore: add observability setup to project - with relevant documentati…
ukemeikot 52c5774
Merge branch 'dev' into staging
cafbdd7
Merge pull request #139 from hngprojects/chore/sync-dev-to-staging-ot…
ukemeikot d757816
Feat/add dev scripts (#125) (#142)
ukemeikot 1b15312
Chore/sync dev to staging admin trainer (#146)
ukemeikot 68b3d82
Chore/sync dev to staging 2 (#150)
ukemeikot 1d90c68
Chore/sync dev to staging 2 (#151)
ukemeikot 47304db
fix(server): remove erroneous seed-script env check from cmd/server
9a46a57
Merge pull request #152 from hngprojects/hotfix/remove-bogus-cmd-serv…
ukemeikot e310e43
Merge pull request #155 from hngprojects/dev
ukemeikot bd6d322
syncing dev to staging (#159)
ukemeikot 49cf1c4
sync dev to staging for uuid fix (#162)
ukemeikot 721e63f
sync dev to staging (#164)
ukemeikot eca6e4e
sync dev to staging (#166)
ukemeikot 28776ef
Syncing Dev to Staging (#171)
Gospelmairo 19253a0
Merge branch 'dev' into staging
b124308
Merge pull request #173 from hngprojects/chore/sync-dev-to-staging-bo…
ukemeikot ce63800
Merge pull request #175 from hngprojects/dev
ukemeikot 0cb80bc
Merge pull request #179 from hngprojects/dev
ukemeikot 26a26ee
syncing dev to staging (#187)
ukemeikot d3f2f81
Chore/sync dev to staging trainer setup (#191)
ukemeikot 3b52753
Merge dev to staging (#193)
Gospelmairo e3bba79
Chore/sync dev to staging validate token (#198)
ukemeikot f66f4d2
Chore/sync dev to staging availability bulk (#200)
ukemeikot 46f6712
Chore/sync dev to staging admin list clients (#203)
ukemeikot 9053eae
sync dev to staging
231bb0a
Merge pull request #206 from hngprojects/chore/sync-dev-to-staging-lo…
ukemeikot f0698b3
sync dev to staging (#211)
ukemeikot 35c93fe
sync dev to staging (#213)
ukemeikot 2cc28ef
Chore/sync dev to staging trainers me (#215)
ukemeikot cc5d3a7
syncing dev to staging (#217)
ukemeikot 4a0f947
Merge pull request #218 from hngprojects/dev
ukemeikot cbccdfe
feat(trainers): add POST /trainers/resend-setup for re-issuing the in…
ukemeikot 12d05af
sync dev to staging (#223)
ukemeikot 2a9bfe8
Merge dev to stagging (#225)
Gospelmairo 1742221
Chore/sync dev to staging media (#235)
ukemeikot 740bb12
Chore/sync dev to staging zoom activities (#250)
ukemeikot ed85616
Chore/sync dev to staging notifications iap fix (#256)
ukemeikot 7f41990
Chore/sync dev to staging notifications reminders (#268)
ukemeikot bd62dff
Merge pull request #269 from hngprojects/dev
ukemeikot 2e607d2
Merge pull request #271 from hngprojects/dev
ukemeikot 611522b
feat(settings): admin Settings page endpoints + client /categories (#…
ukemeikot ea89790
Sync dev to stagging (#275)
Gospelmairo 9837598
Merge dev to stagging 2 (#277)
Gospelmairo 4a57b2b
Merge remote-tracking branch 'origin/dev' into chore/sync-dev-to-stag…
1d2b538
Merge pull request #281 from hngprojects/chore/sync-dev-to-staging-se…
ukemeikot f593889
sync dev to staging (#284)
ukemeikot 43af8ba
Chore/sync dev to staging 2 (#288)
Gospelmairo eb05fea
Sync dev to stagging (#289)
Gospelmairo 5b556a6
Chore/sync dev to staging trainer admin actions (#295)
ukemeikot 32de3d4
Sync dev to stagging (#298)
Gospelmairo d86f426
Chore/sync dev to staging auth hotfix (#302)
ukemeikot f1eedcd
sync dev to staging (#303)
ukemeikot 3c03e5c
Chore/sync dev to staging (#325)
Taterbro dd8fcea
Chore/sync dev to staging meet accounts (#332)
ukemeikot 99db521
Chore/synnc dev to staging (#339)
Taterbro af6df8d
Chore/dev to staging (#345)
Gospelmairo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,128 +1,214 @@ | ||
| # ── Runtime ────────────────────────────────────────────────────────────────── | ||
| APP_ENV=development | ||
| PORT=8080 | ||
| LOG_LEVEL=info | ||
|
|
||
| # DevOps(observability setup) | ||
| SERVICE_NAME=personal-trainer-be | ||
| OTEL_ENABLED=true | ||
| OTEL_EXPORTER_OTLP_ENDPOINT=<observability-server-private-ip-or-dns>:4317 | ||
| LOG_FORMAT=json | ||
|
|
||
| # Frontend URL for CORS (e.g., http://localhost:3000) | ||
| FRONTEND_URL=http://localhost:3000 | ||
| API_BASE_URL= | ||
|
|
||
| # ── Observability ──────────────────────────────────────────────────────────── | ||
| OTEL_ENABLED=true | ||
| OTEL_EXPORTER_OTLP_ENDPOINT=<observability-server-private-ip-or-dns>:4317 | ||
| LOG_FORMAT=json | ||
|
|
||
| # ── Data stores ────────────────────────────────────────────────────────────── | ||
| # Postgres connection string | ||
| # Example: postgres://user:pass@localhost:5432/personal_trainer?sslmode=disable | ||
| DATABASE_URL=postgres://postgres:postgres@localhost:5432/personal_trainer?sslmode=disable | ||
|
|
||
| # SMTP email settings (leave empty in development — emails are logged to console instead) | ||
| # Redis connection string | ||
| REDIS_URL=redis://localhost:6379 | ||
|
|
||
| # ── Core auth ──────────────────────────────────────────────────────────────── | ||
| # Server-side signing key for OUR JWTs (access + refresh tokens). Generate | ||
| # any 32-byte random string. NEVER share between environments. | ||
| JWT_SECRET= | ||
|
|
||
| # ── Email ──────────────────────────────────────────────────────────────────── | ||
| # SMTP — leave empty in development; emails are logged to console instead. | ||
| SMTP_HOST= | ||
| SMTP_PORT=587 | ||
| SMTP_USER= | ||
| SMTP_PASSWORD= | ||
| SMTP_FROM= | ||
|
|
||
| # Resend transactional email (preferred over SMTP when both are set). | ||
| # Leave empty in development — emails are logged to console instead. | ||
| # Get an API key from https://resend.com/api-keys | ||
| RESEND_API_KEY= | ||
| RESEND_FROM=fitcal@hng14.com | ||
| RESEND_FROM=fitcall@hng14.com | ||
|
|
||
|
|
||
| # Google OAuth2 credentials | ||
| # Get these from https://console.cloud.google.com → APIs & Services → Credentials | ||
| # ── Social sign-in: Google ─────────────────────────────────────────────────── | ||
| # Web OAuth credentials from https://console.cloud.google.com → APIs & Services → Credentials | ||
| GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com | ||
| GOOGLE_CLIENT_SECRET=your-google-client-secret | ||
| GOOGLE_REDIRECT_URL=http://localhost:8080/api/v1/auth/google/callback | ||
|
|
||
| # Google mobile sign-in (POST /auth/google/mobile). | ||
| # Each native client registers its own OAuth client ID in Google Cloud Console. | ||
| # The backend accepts ID tokens whose `aud` matches any of these IDs (plus the | ||
| # web GOOGLE_CLIENT_ID above). Leave empty if you don't support that platform. | ||
| # Mobile sign-in (POST /auth/google/mobile). Each native client registers | ||
| # its own OAuth client ID in Google Cloud Console. The backend accepts ID | ||
| # tokens whose `aud` matches any of these IDs (plus the web GOOGLE_CLIENT_ID | ||
| # above). Leave empty if you don't support that platform. | ||
| GOOGLE_ANDROID_CLIENT_ID= | ||
| GOOGLE_IOS_CLIENT_ID= | ||
|
|
||
| # Redis connection string | ||
| REDIS_URL=redis://localhost:6379 | ||
|
|
||
| JWT_SECRET= | ||
|
|
||
| # Zoom Server-to-Server OAuth credentials (for auto-generating meeting links). | ||
| # Used when ZOOM_MEETING_HOST=org (default) and as the fallback for trainers | ||
| # who haven't connected their own Zoom yet under ZOOM_MEETING_HOST=trainer. | ||
| # Get these from https://marketplace.zoom.us → Develop → Build App → Server-to-Server OAuth | ||
| # ── Social sign-in: Apple ──────────────────────────────────────────────────── | ||
| # Sign in with Apple (POST /auth/apple). Single endpoint serves iOS native | ||
| # (AuthenticationServices), Android REST, and web "Sign in with Apple JS". | ||
| # | ||
| # Comma-separated list of bundle IDs / Apple Services IDs accepted as the | ||
| # `aud` claim on Apple's identity token: | ||
| # - iOS native flow → your iOS app bundle id (e.g. com.fitcal.app) | ||
| # - Web flow → the Services ID from Apple Developer → Identifiers | ||
| # - Android REST → uses the Services ID | ||
| # | ||
| # Leave empty to fall back to APPLE_BUNDLE_ID below (the IAP one). For a | ||
| # single-platform deploy that's all you need. | ||
| # | ||
| # Apple's public keys (JWKS) are fetched automatically from | ||
| # https://appleid.apple.com/auth/keys — there is no client secret to set | ||
| # on the server side. | ||
| APPLE_SIGN_IN_BUNDLE_IDS= | ||
|
|
||
| # ── Zoom ───────────────────────────────────────────────────────────────────── | ||
| # Server-to-Server OAuth (auto-generates meeting links). Used when | ||
| # ZOOM_MEETING_HOST=org (default) and as the fallback for trainers who | ||
| # haven't connected their own Zoom under ZOOM_MEETING_HOST=trainer. | ||
| # Source: https://marketplace.zoom.us → Develop → Build App → Server-to-Server OAuth | ||
| ZOOM_ACCOUNT_ID= | ||
| ZOOM_CLIENT_ID= | ||
| ZOOM_CLIENT_SECRET= | ||
|
|
||
| # Per-trainer Zoom OAuth (Marketplace app type: "OAuth"). When set, trainers | ||
| # can connect their own Zoom account at /trainers/me/zoom/connect and meetings | ||
| # are hosted under their account instead of the org one. Required scopes on | ||
| # the Zoom app: meeting:write, meeting:read, user:read. | ||
| # Per-trainer Zoom OAuth (Marketplace app type "OAuth"). When set, trainers | ||
| # can connect their own Zoom account at /trainers/me/zoom/connect and | ||
| # meetings are hosted under their account instead of the org one. | ||
| # Required scopes on the Zoom app: meeting:write, meeting:read, user:read. | ||
| ZOOM_OAUTH_CLIENT_ID= | ||
| ZOOM_OAUTH_CLIENT_SECRET= | ||
| ZOOM_OAUTH_REDIRECT_URL=http://localhost:8080/api/v1/trainers/me/zoom/callback | ||
|
|
||
| # Base64-encoded 32-byte AES-256 key used to encrypt the trainers' OAuth | ||
| # tokens at rest. Generate with: openssl rand -base64 32 | ||
| # Required iff you set ZOOM_OAUTH_CLIENT_ID — without it the OAuth pipeline | ||
| # Required iff ZOOM_OAUTH_CLIENT_ID is set — without it the OAuth pipeline | ||
| # stays disabled and the selector silently falls back to the org account. | ||
| ZOOM_TOKEN_ENCRYPTION_KEY= | ||
|
|
||
| # Zoom Meeting SDK credentials (Marketplace app type: "Meeting SDK"). Used to | ||
| # Meeting SDK credentials (Marketplace app type "Meeting SDK"). Used to | ||
| # sign the short-lived JWT the mobile/web Zoom SDK needs to join a call | ||
| # in-app via GET /sessions/{id}/join-info. Without these the endpoint 503s | ||
| # and clients fall back to the raw join_url. | ||
| ZOOM_SDK_KEY= | ||
| ZOOM_SDK_SECRET= | ||
|
|
||
| # Feature flags for the rollout. Default values keep the previous behaviour. | ||
| # Feature flags for the rollout. Defaults keep the existing behaviour. | ||
| # org | link → existing flow: org account hosts, email link opens Zoom | ||
| # trainer | link → trainer hosts (org fallback), email link opens Zoom | ||
| # org | sdk → org hosts, email link opens FitCall app and joins via SDK | ||
| # trainer | sdk → trainer hosts, in-app SDK joins end-to-end | ||
| ZOOM_MEETING_HOST=org | ||
| ZOOM_JOIN_MODE=link | ||
|
|
||
| # Universal-link domain used in the email "Join" URL when ZOOM_JOIN_MODE=sdk. | ||
| # Must match the Associated Domains entry on iOS + the intent-filter host on | ||
| # Android. The backend serves the AASA + assetlinks.json files generated from | ||
| # the IOS_*/ANDROID_* vars below. | ||
| # ── Google Meet (org-account only) ─────────────────────────────────────────── | ||
| # Meet rooms are minted by a single Workspace user (e.g. meet-bot@yourdomain) | ||
| # rather than per-trainer OAuth. One refresh token in env, many bookings per | ||
| # day — Google's `spaces.create` API has no per-creator concurrency cap. | ||
| # | ||
| # Setup is a one-time operation per environment; see docs/MEET_INTEGRATION.md | ||
| # for the full walkthrough. Quick version: | ||
| # | ||
| # 1. Sign up for Google Workspace (any tier; Business Starter is enough). | ||
| # Create a dedicated user, e.g. meet-bot@yourdomain. | ||
| # 2. In console.cloud.google.com: | ||
| # - Enable the Google Meet REST API | ||
| # - Create an OAuth Client ID (type: Web application) | ||
| # - Add `http://localhost:8765/callback` to Authorized redirect URIs | ||
| # - On the OAuth consent screen, add the scope | ||
| # https://www.googleapis.com/auth/meetings.space.created | ||
| # 3. Run the bootstrap helper to get the refresh token: | ||
| # MEET_OAUTH_CLIENT_ID=<id> MEET_OAUTH_CLIENT_SECRET=<secret> \ | ||
| # go run ./cmd/meet-bootstrap | ||
| # Sign in as meet-bot@yourdomain in the browser, paste the printed | ||
| # refresh token into MEET_REFRESH_TOKEN below. | ||
| # 4. Flip MEET_ENABLED=true and restart. | ||
| # | ||
| # Until MEET_ENABLED=true, the FE hides the Meet platform option and any | ||
| # inbound booking with session_platform=google_meet returns 503. | ||
|
|
||
| # Master switch. Keep false until the refresh token below is provisioned. | ||
| MEET_ENABLED=false | ||
|
|
||
| # OAuth client credentials from Google Cloud Console → Credentials. | ||
| MEET_OAUTH_CLIENT_ID= | ||
| MEET_OAUTH_CLIENT_SECRET= | ||
|
|
||
| # Long-lived refresh token for the Workspace user. Generated via the | ||
| # bootstrap helper (see above). Treat as a secret — leaking it lets | ||
| # anyone mint Meet rooms on your org account until you revoke it from | ||
| # https://myaccount.google.com/permissions on the meet-bot account. | ||
| MEET_REFRESH_TOKEN= | ||
|
|
||
| # Email of the Workspace user the refresh token belongs to. Only used | ||
| # for log lines so operators chasing "why are Meet rooms failing" can | ||
| # tell which mailbox to re-auth. | ||
| MEET_HOST_EMAIL=meet-bot@yourdomain | ||
|
|
||
| # ── Universal links (mobile deep linking) ──────────────────────────────────── | ||
| # Used in the email "Join" URL when ZOOM_JOIN_MODE=sdk. Must match the | ||
| # Associated Domains entry on iOS + the intent-filter host on Android. The | ||
| # backend serves the AASA + assetlinks.json files generated from the | ||
| # IOS_*/ANDROID_* vars below. | ||
| UNIVERSAL_LINK_DOMAIN= | ||
| IOS_APP_BUNDLE_ID= | ||
| IOS_APP_TEAM_ID= | ||
| ANDROID_APP_PACKAGE= | ||
| ANDROID_APP_SHA256= | ||
|
|
||
| # MinIO (S3-compatible) for avatar storage. | ||
| # - Local dev: docker compose brings up a MinIO at localhost:9000 with the | ||
| # credentials below as defaults. The bucket is created at startup if missing. | ||
| # - Production: MINIO_ENDPOINT to your managed S3/MinIO host, set | ||
| # ── Storage (MinIO / S3) ───────────────────────────────────────────────────── | ||
| # - Local dev: docker compose brings up a MinIO at localhost:9000 with these | ||
| # credentials. The bucket is created at startup if missing. | ||
| # - Production: point MINIO_ENDPOINT at your managed S3/MinIO host, set | ||
| # MINIO_USE_SSL=true, and MINIO_PUBLIC_BASE_URL to whatever CDN/host serves | ||
| # the bucket publicly (e.g. https://cdn.fitcall.me/fitcall-avatars). | ||
| # Leave MINIO_ENDPOINT blank in environments where avatar upload is not needed — | ||
| # the endpoint will return 503 instead of panicking. | ||
| # Leave MINIO_ENDPOINT blank where avatar upload isn't needed — the | ||
| # endpoint returns 503 instead of panicking. | ||
| MINIO_ENDPOINT=localhost:9000 | ||
| MINIO_ACCESS_KEY=minioadmin | ||
| MINIO_SECRET_KEY=minioadmin | ||
| MINIO_BUCKET=fitcall-avatars | ||
| MINIO_USE_SSL=false | ||
| MINIO_PUBLIC_BASE_URL=http://localhost:9000/fitcall-avatars | ||
|
|
||
| # ── Push notifications (Firebase Cloud Messaging) ──────────────────────────── | ||
| FCM_CREDENTIALS_JSON= | ||
| FCM_PROJECT_ID= | ||
|
|
||
| # ── In-App Purchases (Apple + Google) ──────────────────────────────────────── | ||
| # Set to true in development to skip real Apple/Google verification calls. | ||
| # ── In-App Purchases (Apple App Store + Google Play) ───────────────────────── | ||
| # Set to true in development to skip real Apple/Google receipt verification. | ||
| # MUST be false in staging and production. | ||
| IAP_SKIP_VERIFICATION=true | ||
|
|
||
| # Apple App Store — get from App Store Connect → Apps → App Information → Shared Secret | ||
| APPLE_SHARED_SECRET= | ||
| APPLE_BUNDLE_ID=com.fitcal.app | ||
|
|
||
| # Google Play — service account JSON from Google Play Console → Setup → API access | ||
| # Paste the entire contents of the service account key JSON file here (single line), | ||
| # or set to the path of the JSON file. | ||
| # ── Sign in with Apple ─────────────────────────────────────────────────────── | ||
| # Comma-separated list of bundle IDs / Apple Services IDs accepted as the | ||
| # `aud` claim on the identity token. iOS native flow → iOS app bundle id; | ||
| # web "Sign in with Apple JS" → the Services ID configured in the Apple | ||
| # Developer portal. Leave empty to fall back to APPLE_BUNDLE_ID above. | ||
| # Server endpoint: POST /auth/apple. | ||
| APPLE_SIGN_IN_BUNDLE_IDS= | ||
|
|
||
| # Google Play — service account JSON from Google Play Console → Setup → API access. | ||
| # Accepts EITHER format (auto-detected by the leading character): | ||
| # - Raw JSON (one line, starts with `{`). Flatten with: | ||
| # jq -c . service-account.json | ||
| # - Base64-encoded JSON (anything else). Convenient for Docker Compose, | ||
| # k8s ConfigMaps, or anywhere quoting raw JSON is awkward. Encode with: | ||
| # PowerShell: [Convert]::ToBase64String([IO.File]::ReadAllBytes("service-account.json")) | ||
| # Bash: base64 -w0 service-account.json | ||
| # | ||
| # Whichever you choose, the server needs the embedded RSA private key live — | ||
| # it cannot work from a file path or a hash. | ||
| GOOGLE_PACKAGE_NAME=com.fitcal.app | ||
| GOOGLE_SERVICE_ACCOUNT_JSON= | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # Fingerprints of historical findings that have been reviewed and | ||
| # confirmed non-secret. Format: one fingerprint per line, as emitted | ||
| # by `gitleaks git . --verbose`. Add a comment above each entry | ||
| # explaining WHY the value is safe so a future reader doesn't have to | ||
| # re-investigate. | ||
| # | ||
| # Adding a fingerprint here suppresses the warning permanently — | ||
| # only use this for genuine false positives (test fixtures, OpenAPI | ||
| # example values, etc.). For real leaked secrets, rotate first. | ||
|
|
||
| # Test-only JWT secret used to satisfy auth.GenerateJWTToken's | ||
| # JWT_SECRET-must-be-set check inside the Apple Sign In handler unit | ||
| # tests. Never reaches production; the test file shortens it to | ||
| # "test-secret" on later commits, matching other auth tests. | ||
| b32b79c2b3b771512416267fe562665c2f6c1aec:internal/auth/apple_test.go:generic-api-key:112 |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove duplicated
APPLE_SIGN_IN_BUNDLE_IDSto avoid silent override.APPLE_SIGN_IN_BUNDLE_IDSis declared twice (Line 71 and Line 200). In.envparsing, the later key wins, so a value set in the first occurrence can be unintentionally overridden by the second (often blank), breaking Apple sign-in audience validation. Keep exactly one declaration and one canonical section.Also applies to: 200-200
🤖 Prompt for AI Agents