Skip to main content

Documentation Index

Fetch the complete documentation index at: https://grantmaster.dev/llms.txt

Use this file to discover all available pages before exploring further.

FAQ & Troubleshooting

Centralized guide for common issues, errors, and questions. See also: Common Gotchas for enforced rules and known pitfalls.

Local Development

Emulators won’t start / port conflicts

The Firebase Emulator Suite requires specific ports. If any are occupied, emulators will fail to bind.
ServicePort
Vite Dev Server3000
Firebase Emulator UI4000
Functions Emulator5001
Firestore Emulator8080
Auth Emulator9099
Storage Emulator9199
Diagnosis:
# Check which process holds a port
lsof -i :8080

# Kill the process
kill -9 <PID>
Prevention: Never override the Vite port (3000) — it is hardcoded for Firebase integration. Use npm run dev:all to start everything together, or coordinate manually with two terminals (npm run dev:start + npm run dev). Health check: Run npm run health:emulators to verify emulator status.

CORS errors in development

  • Ensure VITE_USE_EMULATORS=true is set in .env.local when running against emulators.
  • The Vite dev server must run on localhost:3000 (the authorized domain configured in Firebase).
  • If hitting production Firebase from localhost, CORS will block requests — always use emulators for local development.

Functions not responding

  • Check functions/firebase-debug.log for execution errors.
  • Ensure the Functions emulator is running on port 5001.
  • Rebuild functions after code changes: cd functions && npm run build.
  • Verify dependencies are installed: cd functions && npm install.

Hot reload not working

  • Ensure you are running npm run dev (Vite), not a production build.
  • Clear the Vite cache: rm -rf node_modules/.vite and restart.
  • Large file changes (new routes, new providers) may require a full restart.

”Module not found” errors

  • Run npm install at the repo root to ensure all workspace dependencies are installed.
  • For functions: cd functions && npm install.

Build & Deploy

Build fails with TypeScript errors

  • Run npx tsc --noEmit to see the full error list.
  • Check that shared types in packages/shared/ are up to date: npm run build in that workspace.
  • ESLint custom rules (palette, component, architecture) will also fail the build — see Common Gotchas for the full list.

Deploy fails with permissions error

  • Run firebase login to re-authenticate.
  • Ensure the correct project is selected: firebase use staging or firebase use production.
  • For production deploys, the production guardrail pattern requires --confirm-project=grantlog. See scripts/README.md for details.

Staging vs production config issues

  • Environment-specific configs are handled via .env.staging / .env.production.
  • Build with the right command: npm run build:staging or npm run build:production.
  • Verify the active Firebase project: firebase use.

Firebase / Firestore

”Permission denied” on Firestore reads

Common causes:
  1. organizationId mismatch — The document’s organizationId doesn’t match the user’s tenant. Firestore security rules enforce tenant isolation.
  2. Missing role or permission — The user lacks the required RBAC permission for the operation. Check PermissionGuard and the user’s assigned roles.
  3. Security rules not deployed — If rules were changed but not deployed, production behavior may differ from expectations.
Debug steps:
  • Check the Firestore Emulator UI (port 4000) for rule evaluation details.
  • Verify the user’s custom claims: firebase auth:export or check in the Auth emulator.
  • Ensure organizationId is consistent across related documents.

TENANT_MISMATCH errors

This is a critical error indicating a cross-tenant data access attempt. The system will immediately terminate the session and log a high-priority event. Causes:
  • A user switched organizations but stale references point to the previous tenant’s data.
  • A service call passes the wrong organizationId.
Resolution:
  • Force a full page reload to clear stale context.
  • Verify that all service calls use useTenant() (not useOrganization, which is deprecated) to get the current organizationId.

Emulator data lost on restart

By default, emulator data is ephemeral. To persist data across restarts:
# Start with persistence (recommended default)
npm run emulators

# Start without persistence (clean slate)
npm run emulators:no-persist

# Start fresh with seed data
npm run dev:all:fresh
The emulators script uses --import/--export flags automatically.

Authentication

Custom claims not updating

Firebase custom claims (roles, permissions, organizationId) are embedded in the ID token and cached until the token refreshes (up to 1 hour). Force a token refresh:
  • Sign out and sign back in.
  • In code, call auth.currentUser?.getIdToken(true) to force a refresh.
  • After running scripts like local:set-superadmin, restart the app or hard-refresh.

MFA issues in development

MFA is not enforced in the Auth emulator. If testing MFA flows:
  • The emulator auto-approves MFA challenges.
  • Production MFA issues may stem from clock skew on the user’s device (TOTP) or expired phone verification codes.
  • Invitation tokens have a TTL. Generate a new invitation from the Team page.
  • Check that the portalTokens collection entry hasn’t expired.

Common Error Messages

The application uses a typed error hierarchy defined in src/errors/AppError.ts. All errors extend AppError and carry a severity, category, and userMessage.
Error CodeTypeCauseFix
VALIDATION_ERRORUserZod schema failure or invalid inputCheck input against the expected schema; inspect field-level errors in the UI
PERMISSION_DENIEDSecurityUser lacks required RBAC role/permissionVerify user roles in the admin panel; check PermissionGuard wrapping
TENANT_MISMATCHCriticalCross-tenant data access attemptVerify organizationId consistency; force reload to clear stale context
NOT_FOUNDDataEntity doesn’t exist in the collectionCheck the collection name and document ID; see collection name gotchas
INTERNAL_ERRORSystemUnexpected backend/infrastructure failureCheck Sentry for stack trace; review functions/firebase-debug.log
RATE_LIMITUserAPI throttling (too many requests)Wait for the retryAfter period; reduce request frequency
BUSINESS_LOGICUserDomain-specific validation failureRead the error message for specifics (e.g., budget exceeded, deadline passed)

Error categories in the codebase

For debugging, errors are also categorized by system area: validation, authentication, authorization, not_found, network, firestore, storage, rate_limit, business_logic, external_api, ai_service, email_service. These categories appear in Sentry and structured logs. Filter by category to narrow down issues.

Performance

Slow Firestore queries

  • Add limit(): All Firestore queries must include an explicit limit() — this is enforced by the require-firestore-limit ESLint rule.
  • Check indexes: Missing composite indexes cause full collection scans. The Firestore emulator logs index suggestions.
  • Use pagination: For large result sets, use cursor-based pagination (startAfter).
  • Review query patterns: Avoid != and not-in operators which bypass indexes.

Large bundle size

  • All routes use React.lazy() for code splitting — check src/routes/lazyComponents.tsx.
  • Verify chunk configuration in vite-chunks.config.ts.
  • Run npm run build and inspect the output for unexpectedly large chunks.
  • Heavy libraries (PDF generation, Excel export) should only load in their respective routes.

Testing

E2E tests failing locally

  • Ensure emulators are running before starting E2E tests.
  • Run npm run test:setup-users to create required test users.
  • Check that shared auth state in tests/.auth/ is not stale — delete it and re-run.
  • Use npm run test:e2e:debug for step-by-step debugging.

Vitest watch mode issues

  • If watch mode doesn’t pick up changes, clear the Vitest cache and restart.
  • Ensure you’re running npm run test (watch mode) or npm run test:run (single run).
  • Tests use jsdom environment — some Node-only APIs may not be available.

Emulator state between tests

  • Tests should be idempotent. Avoid depending on state from previous tests.
  • Use npm run dev:all:fresh to start with a clean emulator state before test runs.
  • For E2E, the test:setup-users script provisions the baseline user data.

Scripts & Tooling

”Permission denied” when running scripts

chmod +x scripts/*.sh

”Firebase project not found”

firebase login
firebase use staging  # or: firebase use production

Production guardrails blocking a script

Production-targeting scripts require explicit confirmation:
# The --confirm-project flag is mandatory
tsx scripts/some-prod-script.ts --confirm-project=grantlog --yes
See the Production Guardrail Pattern for details.

SuperAdmin Troubleshooting

For platform-level diagnostics, SuperAdmins have additional tools:
  • EventBus (/eventbus): Real-time stream of all domain, system, and external events. Filter by tenantId to debug a specific tenant.
  • Audit Logs: Track infrastructure changes, permission grants, and tenant impersonation actions.
  • System Health (/integrations): Check connectivity status of external services (Firebase, Stripe, Postmark, etc.).
See Advanced Troubleshooting for the full guide.

Maintenance

Update this document when new common issues are discovered. If an issue appears more than twice in team discussions or support channels, add it here.