Review Artifact: RLS Phase 1 & Hardening
Date: 2026-02-16
Cycle: Production DB Hardening
Status: Implementation Complete - Awaiting Verification
1. Modified Files Summary
Database (Relational)
db/bootstrap.sql: Minimal base tables; RLS and policies removed for idempotency.db/migrations/20260216000006_rls_phase_1.sql: Hardened with safe policy creation (DO $$) and explicitENABLE RLS.db/migrations/2026021600000[1-5]*.sql: Added mandatory idempotency headers.
Backend Core
app/core/config.py: AddedSUPABASE_SERVICE_KEY.app/core/auth.py: Implementedget_user_client(token)andget_service_client(). Added JWT token toget_current_userresponse.app/api/router.py: Grouped admin endpoints under/adminprefix.
Services & Agents
app/services/wallet.py: Split client usage. Read/Balance check uses user client; Deductions use service client.app/services/supabase_store.py: Usage logging now uses user client with RLS support.app/services/supabase_references.py: All operations switched toservice_roleclient.app/services/llm.py: Switched translation model togpt-4o-mini.app/services/retrieval.py: Implementedretrieval_languagelogic and enhanced metadata passing.app/services/reranker.py: Updated prompt for semantic cross-lingual matching.app/agents/teacher_agent.py: UpdatedTeacherStateand nodes to flowauth_tokenandretrieval_query.
Documentation & Tools
postman/collection.json: Overwritten with hardened requests, including/admin/test-roleand multilingual tests.
2. Before vs. After: Architecture Shifts
| Feature | Before (Soft) | After (Hardened) |
|---|---|---|
| RLS Status | Disabled | Enabled on core tables. |
| Supabase Client | One client (Anon Key) for all. | Separation of User (RLS) vs Service (Admin). |
| Translation | gpt-4o (Expensive/Slow) |
gpt-4o-mini (Fast/Optimized). |
| Arabic Support | Simple translation | Semantic cross-lingual reranking + English support. |
| Admin Access | x-admin-key only |
Primary: JWT Role admin, Secondary: API Key. |
3. RLS Policies Summary
Policies are defined in 20260216000006_rls_phase_1.sql:
- profiles: auth.uid() = user_id (SELECT).
- wallet: auth.uid() = user_id (SELECT).
- wallet_ledger: auth.uid() = user_id (SELECT).
- usage_logs: auth.uid()::text = user_id (SELECT).
- Writes: Bypassed by service_role in the backend for ledger and wallet updates.
4. Multilingual & Retrieval Logic
- Model:
gpt-4o-mini. - Logic:
- If namespace is English ->
retrieval_language= English. - If Student Language != Retrieval Language -> Translate query.
- Reranker receives both original and translated queries for better semantic context.
5. Manual Supabase Actions Required
- Apply Migration: Run
db/migrations/20260216000006_rls_phase_1.sqlin the SQL Editor. - Environment Variables: Add
SUPABASE_SERVICE_KEYto your.envand Render dashboard. - Admin Setup: Set
{"role": "admin"}inuser_metadatafor admin users.
6. Verification Steps
- Test Admin Role: Run Postman
Admin -> Test Admin Role. - Test Wallet (RLS): Try to
GET /wallet/balance. Confirm it works only with a valid JWT. - Test Multilingual: Run Postman
Chat (RAG) -> Arabic Query. Confirmretrieval_queryin the response body.