Stable production ready v1.1 - #4
Conversation
… links on home page
… authoritative role resolution
…ure documentation PDFs
…any helpers to postgres module
… across all endpoints
There was a problem hiding this comment.
🟡 Changes recommended
It introduces several release-blocking issues (notably committed credential-like values in frontend examples/source and a correctness bug in cache single-flight cleanup) that should be resolved before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR aims to make the “v1.1” prototype more production-like by tightening authentication/RBAC, adding a public root status endpoint, introducing a multi-tier caching layer (L1 in-memory + optional L2 Zoho Catalyst Cache), and updating frontend infrastructure to use Supabase sessions consistently.
Changes:
- Frontend: add Supabase client +
AuthContext, update API client to pull Bearer JWT from Supabase session, and refine login/forgot-password flows. - Backend: add public
GET /status endpoint, expand caching to multi-tier with stampede protection, and tighten RBAC role-claim trust model (dropuser_metadata.role). - Infra/docs: add Supabase
user_profilesmigration + RLS policies, update README/API docs, and add deployment configuration for Catalyst/AppSail.
File summaries
| File | Description |
|---|---|
| README.md | Updates deployment links, architecture, security, API and setup documentation. |
| frontend/src/utils/documentationPdf.js | Adds asset URL resolution and “open in new tab” doc handling with jsPDF fallback. |
| frontend/src/services/supabase.js | Introduces a shared Supabase client and configuration detection. |
| frontend/src/services/api.js | Switches auth header retrieval to Supabase session-based JWT. |
| frontend/src/modules/dashboard/Workflow.jsx | Updates documentation button behavior to open a static PDF. |
| frontend/src/modules/dashboard/Hero.jsx | Updates documentation button behavior to open a static PDF. |
| frontend/src/modules/dashboard/components/TopNavbar.jsx | Updates branding text to use i18n portal name. |
| frontend/src/modules/dashboard/components/Sidebar.jsx | Updates subtitle to use i18n portal name. |
| frontend/src/modules/dashboard/components/AnalystTopNav.jsx | Updates subtitle to use i18n portal name. |
| frontend/src/modules/authentication/Login.jsx | Moves login flow to Supabase-backed auth + role resolution. |
| frontend/src/modules/authentication/ForgotPassword.jsx | Implements Supabase-backed password reset + toast/error UX. |
| frontend/src/i18n/locales/kn.js | Updates Kannada auth strings for portal naming and placeholders. |
| frontend/src/i18n/locales/en.js | Updates English auth strings for portal naming and placeholders. |
| frontend/src/context/AuthContext.jsx | Adds app-wide auth provider with session/profile/role resolution and reset/logout helpers. |
| frontend/src/components/shared/navigation/Footer.jsx | Updates portal naming and KSP title defaults. |
| frontend/src/App.jsx | Wraps app in AuthProvider, adds session-based route protection and URL/hash navigation tweaks. |
| frontend/package.json | Adds @supabase/supabase-js dependency. |
| frontend/package-lock.json | Locks Supabase dependency tree (including engine constraints). |
| frontend/.env.example | Adds example frontend env vars for API, Maps, and Supabase. |
| backend/tests/test_rbac.py | Ensures user_metadata.role cannot elevate privileges; confirms app_metadata/top-level role behavior. |
| backend/tests/test_health.py | Adds tests for new public root endpoint. |
| backend/tests/test_catalyst_cache.py | Expands cache tests for L1/L2 behavior, invalidation, stampede protection, and request propagation. |
| backend/tests/test_auth.py | Adds explicit tests for public root and protected route behavior. |
| backend/supabase/migrations/006_user_profiles.sql | Adds user_profiles table, RLS, triggers, and provisioning logic for official accounts. |
| backend/requirements.txt | Adds cryptography dependency for JWT/JWKS key handling. |
| backend/docs/RBAC_AUTHORIZATION.md | Updates role claim path order to remove user_metadata.role. |
| backend/docs/AUTHENTICATION.md | Updates role resolution documentation to remove user_metadata.role. |
| backend/app/schemas/auth.py | Extends /auth/me schema to include server-resolved role. |
| backend/app/main.py | Adds / to public paths, adds GET /, adds cache stats to /health, and enforces production auth guard. |
| backend/app/database/postgres/init.py | Adds small query helper functions (execute_query/one/write/many). |
| backend/app/database/ingest/init.py | Invalidates cache prefixes after successful ingestion commit. |
| backend/app/core/rbac.py | Updates role-claim source documentation to server-trusted paths only. |
| backend/app/core/rate_limit.py | Exempts / from rate limiting. |
| backend/app/core/jwt_auth.py | Updates JWKS key handling logic (PyJWK + fallbacks). |
| backend/app/core/config.py | Adds L2 cache env aliases and ignores unknown env vars. |
| backend/app/core/cache.py | Implements multi-tier cache (L1 LRU + optional L2 Catalyst) and single-flight coordination. |
| backend/app/api/stations.py | Propagates request context into cache get/put calls. |
| backend/app/api/intelligence_map.py | Propagates request context into cache get/put calls. |
| backend/app/api/districts.py | Propagates request context into cache get/put calls. |
| backend/app/api/auth.py | Returns role in /api/v1/auth/me. |
| backend/app/api/auth_deps.py | Adds production guard preventing auth-disabled mode in production. |
| backend/app/api/analytics.py | Adds RBAC permission checks and propagates request context into cache get/put calls. |
| backend/app-config.json | Sets AppSail env variables for production-mode auth + cache + Supabase JWT configuration. |
| backend/.env.example | Updates RBAC role claim paths example to remove user_metadata.role. |
| .agents/rules/changes-blocked.md | Adds always-on agent rule file restricting navbar/footer/doc changes. |
Review details
Files not reviewed (1)
- frontend/package-lock.json: Generated file
- Files reviewed: 44/48 changed files
- Comments generated: 9
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| - Git | ||
| - Access to the configured Supabase project for live database/auth testing | ||
| - **Python 3.10+** | ||
| - **Node.js 18+ and npm** |
| export const DEMO_PREFILL_CREDENTIALS = { | ||
| officer: { | ||
| email: 'crimeintel.officer@gmail.com', | ||
| password: 'Officer@Pass2026', | ||
| name: 'Field Officer', | ||
| badge: 'KSP-FO-4892' | ||
| password: 'Techfortune@123', | ||
| }, | ||
| analyst: { | ||
| email: 'crimeintel.analystt@gmail.com', | ||
| password: 'Analyst@Pass2026', | ||
| name: 'Intelligence Analyst', | ||
| badge: 'KSP-IA-1044' | ||
| password: 'Techfortune@123', | ||
| }, | ||
| admin: { | ||
| email: 'crimeintel.admin@gmail.com', | ||
| password: 'Admin@Pass2026', | ||
| name: 'System Administrator', | ||
| badge: 'KSP-ADM-001' | ||
| } | ||
| password: 'Techfortune@123', | ||
| }, |
| if hasattr(segment, "put"): | ||
| try: | ||
| # Pass ttl if supported by SDK implementation | ||
| segment.put(key, value, expiry_in_hours=max(1, ttl // 3600)) |
| def single_flight(self, key: str) -> Generator[bool, None, None]: | ||
| """Context manager coordinating single-flight execution for identical concurrent keys.""" | ||
| with self._flight_meta_lock: | ||
| if key not in self._flight_locks: | ||
| self._flight_locks[key] = threading.Lock() | ||
| key_lock = self._flight_locks[key] | ||
|
|
||
| with key_lock: | ||
| try: | ||
| # If value is now in cache, computation is not needed | ||
| if self.get(key) is not None: | ||
| with self._l1._lock: | ||
| self._l1._stampede_prevented += 1 | ||
| logger.info("CACHE STAMPEDE PREVENTED: %s", key) | ||
| yield False | ||
| else: | ||
| yield True | ||
| finally: | ||
| with self._flight_meta_lock: | ||
| if key in self._flight_locks and not key_lock.locked(): | ||
| self._flight_locks.pop(key, None) | ||
|
|
| # CrimeIntel Frontend Environment Configuration Reference | ||
| VITE_API_BASE_URL=http://localhost:8000/api/v1 | ||
| VITE_GOOGLE_MAPS_API_KEY=AIzaSyDNBYOp5ScuCCQrrtkulY1k0IJZ49nKo40 | ||
|
|
||
| # Supabase Auth Public Configuration (Safe for client-side browser exposure) | ||
| VITE_SUPABASE_URL=https://gcxppkdtbvmleynrzqao.supabase.co | ||
| VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdjeHBwa2R0YnZtbGV5bnJ6cWFvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODQ5NjY5MDYsImV4cCI6MjEwMDU0MjkwNn0.iO6ORQCWe7_zHUAtvW1Rl7rN5YebvMIGAAsLs2oy7tA |
| import vidhanSoudha from '../../assets/vidhan-soudha-exact.webp'; | ||
| import { useTranslation } from '../../i18n'; | ||
| import { downloadArchitectureDocumentation } from '../../utils/documentationPdf'; | ||
| import { downloadArchitectureDocumentation, openDocumentInNewTab } from '../../utils/documentationPdf'; |
| import workflowBg from '../../assets/workflow-bg.webp'; | ||
| import { useTranslation } from '../../i18n'; | ||
| import { downloadArchitectureDocumentation } from '../../utils/documentationPdf'; | ||
| import { downloadArchitectureDocumentation, openDocumentInNewTab } from '../../utils/documentationPdf'; |
| try { | ||
| // 1. Attempt to fetch static file from public asset root | ||
| const response = await fetch('./crimeintel-architecture-documentation.pdf', { method: 'GET' }); | ||
| const contentType = response.headers.get('content-type') || ''; | ||
|
|
||
| if (response.ok && contentType.includes('pdf')) { | ||
| const response = await fetch(resolvedUrl, { method: 'GET' }); | ||
| if (response.ok && response.status === 200) { | ||
| const blob = await response.blob(); | ||
| const blobUrl = URL.createObjectURL(blob); | ||
| const link = document.createElement('a'); | ||
| link.href = blobUrl; | ||
| link.download = filename; | ||
| document.body.appendChild(link); | ||
| link.click(); | ||
| document.body.removeChild(link); | ||
| setTimeout(() => URL.revokeObjectURL(blobUrl), 1000); | ||
| return; | ||
| if (blob.size > 1000) { |
| 1. Do not change the nav bar and footer until i request you to change. | ||
| 2. Do not replace the documents in frontend home page unless i tell you to change. |
Final Ready prototype for round 2