Schema & Setup — CA Compliance Tracker (Worked Example)
The two database tables, RLS strategy, and project CLAUDE.md template for the CA compliance tracker. Use this if you chose the CA tracker as your parallel project.
This page is for participants who chose the CA compliance tracker as their parallel project. If you chose a different project, use this as a reference for how to structure your own schema — the patterns (two tables, RLS, soft-delete) are the same for any project.
The most expensive mistake in any software project is discovering the wrong data model after you have already built the UI on top of it. Spend 30 minutes here understanding what you are building and why — it will save you hours of rebuilding later.
The Two Tables
Your entire application lives in two database tables.
Table 1: clients
Stores the CA firms or individuals you manage.
| Column | Type | Notes |
|---|---|---|
id | uuid | Primary key, auto-generated |
created_at | timestamptz | Auto-set on insert |
user_id | uuid | The CA who owns this client — references auth.users(id) |
legal_name | text | Full legal name of the client entity |
gstin | text | 15-character GSTIN (nullable — not all clients are GST-registered) |
entity_type | text | "Private Limited" / "LLP" / "Partnership" / "Proprietorship" / "Individual" |
state_code | text | 2-character state code (e.g. "MH", "DL", "KA") |
contact_email | text | Primary contact email |
contact_phone | text | 10-digit mobile (nullable) |
notes | text | Any general notes about this client |
is_deleted | boolean | Soft-delete — never hard-delete a client |
Table 2: compliance_tasks
Stores one row per compliance obligation per client per period.
| Column | Type | Notes |
|---|---|---|
id | uuid | Primary key, auto-generated |
created_at | timestamptz | Auto-set on insert |
client_id | uuid | References clients(id) |
user_id | uuid | Redundant with client.user_id, but simplifies RLS policies |
task_type | text | "GSTR-1" / "GSTR-3B" / "ITR" / "Tax Audit" / "Statutory Audit" / "ROC Annual Return" / "Other" |
period | text | Human-readable period: "Apr 2026", "FY 2025-26", "Q4 FY2025-26" |
due_date | date | The statutory due date |
status | text | "pending" / "in_progress" / "filed" / "overdue" |
filed_date | date | Actual filing date (null until filed) |
filing_ref | text | ARN / Acknowledgement number / Reference (nullable) |
notes | text | Late fees, notices, special circumstances |
is_deleted | boolean | Soft-delete |
The relationship: One client has many compliance tasks. A compliance task belongs to one client. This is a standard one-to-many relationship.
The RLS Strategy
You are the only user of your own app. The RLS policy is simple: you can only see and edit rows that belong to you.
For the clients table:
For the compliance_tasks table:
No delete policies — you never hard-delete. You update is_deleted = true instead.
The Useful Queries
These are the three main things your app will ask the database for:
1. All my clients (for the client list page):
2. All tasks for one client (for the client detail page):
3. What's due this week (for the dashboard):
You will not write these queries by hand — you will describe them to Claude and it will write the React Query hook. But understanding what the query does before asking Claude helps you verify the output is correct.
Your Project CLAUDE.md Template
When you scaffold your app in Week 3, create a CLAUDE.md at the root of your project with this content. Fill in the [brackets].
Supabase Project Setup
Before Week 5 homework, you need a Supabase project for your app. It is separate from the School ERP project.

[paste from your Supabase dashboard URL].env.localCreate a separate Supabase project for your CA Practice Manager — do not reuse the School ERP project. Each app needs its own project so data stays isolated. The dev/prod split (two separate Supabase projects per app) is something you will learn in the School ERP and can apply to your Practice Manager after Demo Day.