Start with ownership
For each child row, identify the parent it belongs to and the user or organisation allowed to access it. Use a foreign key for the database relationship and row level security for the access rule. One does not replace the other.
- Name the parent and child tables.
- Add a non-null foreign key where every child must have a parent.
- Choose safe delete and update behavior.
- Add indexes for common filters and joins.
- Write and test policies for owner, member and signed-out cases.
- Load the relationship in the UI with explicit empty and error states.
Schema review checklist
Before making changes, work through the points below. Each one covers a different part of the picture, so treat them as a set rather than picking favourites.
- Every foreign key has an explicit ON DELETE behaviour, not the default.
- Indexes exist on columns used in joins and RLS policy checks.
- Nullable foreign keys are genuinely optional, not an oversight.
- Cascading deletes are tested against real data before going live.
- Junction tables used for many-to-many relationships have composite keys.
Warning signs of a relationship problem
A few moving parts are involved here. The points below cover each of them, so you can see the full scope before deciding where to start.
- Orphaned rows appearing after a parent record is deleted.
- Queries slowing down as a joined table grows without an index.
- Policies that pass in testing but expose data through an unexpected join.