Session Audit Roadmap — 2026-05-10¶
Origin: Items surfaced during the 2026-05-09/10 working session covering prod docs 502, signup-credit fix, LAN-access setup, and full payment audit. This document is the punch list to work through; each item is applied in its own commit (or a clearly-bounded series of commits in the same area).
Repos involved: both indoxhub-backend (this repo) and
indoxhub-frontend (sibling). Items note which repo to edit in.
Progress (2026-05-19)¶
All backend items DONE except the deployment-config check #10. Per-item commits:
- #2 docs container Dockerfile — f0642f3 (shipped earlier)
- #7 partial unique index on signup_credit — 13528ef
- #8 payment-flow tests (23 tests, mocked Stripe) — 2d04875
- #9 CI Node 20 bump — already on v4+ (no-op)
- #11 mask Stripe-secret previews in ValueError — 5dc7be1
- #12 consolidate session-breakdown shape — af173c4
- #13 lazy-init Stripe API key — c0772e0
- #17 watchdog IDLE_HOURS env-overridable (default 4h) — 1628336
Remaining: #10 (prod env check, no code), #18 (refresh 3-month plan),
19/#21 (architecture/DX, low). Frontend items #1, #3, #4, #5, #6, #14,¶
15, #16, #20 live in the sibling repo.¶
🔴 URGENT¶
1. Google OAuth client secret leak in frontend bundle¶
- Severity: Security — credential exposed to every browser
- Repo: indoxhub-frontend
- Symptom:
frontend/.envline 4 setsNEXT_PUBLIC_CLIENT_SECRET=GOCSPX-.... Any var withNEXT_PUBLIC_prefix is baked into the JS bundle shipped to browsers. - What to do:
- Rotate the secret in Google Cloud Console (deauth the leaked one)
- Remove
NEXT_PUBLIC_CLIENT_SECRETfromfrontend/.envand any.env.example/ docs - Grep frontend
src/forNEXT_PUBLIC_CLIENT_SECRET— if any code reads it, the flow is broken-by-design (secrets must live server-side); refactor that flow to call backend instead - If the flow currently posts the secret to backend, that's fine — backend can hold the secret as a non-public env
🟠 High-priority¶
2. Production docs container is fragile — DONE f0642f3¶
- Repo: indoxhub-backend
- Symptom:
docker/production/docker-compose.yml:208-214runsapk add + pip install + mkdocs serveon every container restart. Slow recovery (~2-5 min after CI deploy) andmkdocs serveis a single-threaded dev server, not built for prod traffic. - What to do:
- Create
docker/docs/Dockerfilethat pre-installs deps (mkdocs-material, cairosvg, pillow, mkdocs-git-revision-date-localized-plugin) - Run
mkdocs buildonce at image build time - Final stage:
nginx:alpineserving the static/site/directory - Update prod compose to build from this Dockerfile, drop the inline
apk add ...command - Verify in local first (mirror in
docker/local/), then push prod compose change - Effort: ~30-60 min
- Risk: Low — falls back to current behavior if rebuild fails
3. Frontend signup-credit UI incomplete (Phase 1 of 6)¶
- Repo: indoxhub-frontend
- Symptom:
frontend/docs/plans/2026-05-02-signup-credit-frontend.mdsays Phase 1 in progress; only types + 3 React Query hooks exist (useSignupCreditStatus,useCreateSetupIntent,useGrantWithExistingCard). No UI page. Users can't actually claim the $1. - What to do: implement Phases 2-5 from that plan
- Phase 2:
StripeElementsProvider(client_secret + publishable_key) - Phase 3:
/signup-creditpage route + status-driven render branches - Phase 4:
<PaymentElement>form callingconfirmSetup, success state polling - Phase 5: i18n + a11y polish
- Phase 6: smoke test against live Stripe test mode
- Effort: 1-2 days per the plan's own estimate
- Depends on: B1+B2 backend fix (already done locally, not yet pushed)
4. Crypto UI lies to users¶
- Repo: indoxhub-frontend
- Symptom:
src/components/pages/landing/intro/components/CryptoLabel.tsxclaims "we use crypto for payment" — zero crypto backend exists. Misleads users. - What to do: decide
- (a) Remove the label — 30s edit, ship today
- (b) Implement Stripe Crypto Onramp — 1-2 days
- Recommendation: (a) until you have actual demand for crypto
5. Refresh token bug¶
- Repo: indoxhub-frontend (probably)
- Symptom: Tracked in 3-month plan as item 2.27. No reproduction yet this session.
- What to do: reproduce → identify cause → fix
- Effort: 2hr per plan estimate
🟡 Medium-priority¶
6. SSR fragility on home page (already planned, partially done)¶
- Repo: indoxhub-frontend
- Plan:
frontend/docs/plans/2026-04-28-home-page-ssr-hardening.md - Status: Phase 1 audit done; Phases 2-5 fixes pending
- 3 components with known unhardened API calls:
WhatsNewStrip— no fallback when API misshapesTrending— partial guard, doesn't catch non-arrayTrendingCard— numeric fields not coerced- Effort: half-day
7. Webhook grant idempotency hardening — DONE 13528ef¶
- Repo: indoxhub-backend
- Symptom:
app/db/billing_modules/grant_signup_credit.pydoes 3 separate idempotency checks (email, already-granted, setup-intent) — sequential, not atomic. Webhook retries are usually serial so race risk is small, but the right fix is at the DB layer. - What to do:
- Migration: add unique partial index
CREATE UNIQUE INDEX ON billing_transactions (user_id) WHERE payment_method='signup_credit' - Remove the now-redundant Python check (just rely on the DB constraint + transaction handling)
- Effort: ~1 hour including migration
8. No payment-flow tests — DONE 2d04875¶
- Repo: indoxhub-backend
- Symptom:
tests/test_billing_fixes.pycovers credit math only. No tests for Stripe checkout, SetupIntent, or grant flow. - What to do: integration tests with mocked Stripe API for happy paths of each flow:
POST /payments/create-checkout-sessionPOST /payments/signup-credit/setup-intentGET /payments/signup-credit/status(with and without saved card)POST /payments/signup-credit/grant-with-existing-card- Webhook handler for
checkout.session.completedandsetup_intent.succeeded - Effort: half-day
9. CI/CD Node 20 deprecation — DONE (no-op; all actions already at v4+)¶
- Repo: indoxhub-backend (.github/workflows)
- Symptom:
docker/setup-buildx-action@v3runs Node 20. Forced to Node 24 by 2026-06-02; removed entirely 2026-09-16. - What to do: bump action versions where pinned to v3 → v4 (or current latest). Test with
actor a draft workflow run. - Effort: 30 min
10. Verify prod cookie domain¶
- Repo: indoxhub-backend (deployment, not code)
- Symptom: Local has
COOKIE_DOMAIN=empty; prod should haveCOOKIE_DOMAIN=.indoxhub.comso cookies span api/admin/main subdomains. Misconfiguration here causes silent auth failures across subdomains. - What to do: check prod env, set if missing.
🟢 Cleanups (low-priority)¶
| # | Issue | Repo | File / Detail |
|---|---|---|---|
| 11 | Stripe secrets logged with first-10-char "preview" — DONE 5dc7be1 |
backend | actual leak was in app/core/config.py:172,179 not the files cited; ValueError previews dropped |
| 12 | Pricing logic duplicated — DONE af173c4 |
backend | math wasn't duplicated; the breakdown shape was — extracted build_session_breakdown |
| 13 | Stripe API key set at module-import time — DONE c0772e0 |
backend | new configure_stripe() in startup hook + every entry point; rotation no longer needs restart |
| 14 | Hardcoded URLs in TypeScript types | frontend | We fixed docs/ URL via env var. Audit other type literals like (string & {}) |
| 15 | Frontend Dockerfile mismatch | frontend | docker/local/Dockerfile exists but docker/local/docker-compose.yml builds from docker/development/Dockerfile. Pick one and delete the other. |
| 16 | Commented-out OAuth providers in frontend .env |
frontend | Microsoft and others commented out. Either implement or delete the cruft. |
| 17 | Watchdog auto-down at 1h is aggressive for active dev — DONE 1628336 |
backend | env-overridable, default raised 1→4 |
🟣 Architecture / DX¶
| # | Suggestion |
|---|---|
| 18 | Refresh docs/main_plan/indoxhub_3month_plan.md — current "next task" (3.16 free signup credit) is already shipped. Mark done, pick new next. |
| 19 | Cross-compose external network is fragile if backend goes down. If team grows, consider Compose include (v2) or merging frontend service into backend's compose. |
| 20 | Split frontend .env into role-specific files (.env, .env.docker, .env.local) for cleaner role-specific overrides. |
| 21 | Add a docker compose ps --filter health overview script for the local stack — QoL. |
In-flight from this session (uncommitted)¶
These changes are sitting in the working tree from the same session and are not yet committed:
Backend uncommitted:
- app/api/routers/stripe_checkout_modules/signup_credit.py — added grant-with-existing-card endpoint, populated card fields in status (B1 + B2)
- app/services/checkout_modules/setup_intent.py — added read_stripe_customer_id and get_saved_card helpers
- app/services/stripe_checkout_service.py — wired the helpers
- app/models/schema_modules/billing_schemas.py — added 3 fields + new response schema
- app/models/schema_modules/__init__.py — re-export
- docker/local/docker-compose.yml — LAN CORS additions, COOKIE_DOMAIN= empty
- docker/local/nginx-local.conf — / and /api/proxy/ route to frontend container
Frontend uncommitted:
- 7 files for the option-B configurable-docs-URL refactor
- docker/local/Dockerfile — .env.local → .env
- docker/local/docker-compose.yml — joins external network, drops port 3010
These are functional and tested; just need commits + push when convenient.
Order I'll work through¶
Priority order — finishing one before starting the next, committing after each non-trivial item. Items 1–4 are biggest impact; 11–17 are quick wins that can batch.
-
1 — credential leak (urgent, security)¶
-
4 — crypto label (30s, removes user-facing lie)¶
-
11 — secret logging mask (quick, security adjacent)¶
-
2 — prod docs container Dockerfile (operational stability)¶
-
7 — webhook idempotency DB constraint¶
-
9 — CI Node version bump¶
-
3 — signup-credit UI Phases 2-5 (real product work, long-running)¶
-
6 — SSR hardening Phases 2-5¶
- Remainder of cleanups (#12–#17)
- Refresh 3-month plan (#18)
User decides which items to push to prod after each commit.