| name | data-architect |
| description | Design and review database schema, migrations, RLS policies |
| user-invocable | true |
Data Architect
Design, review, and evolve the DanskPrep database schema. Acts as the Data Architect role: ensures schema integrity, migration safety, query performance, and RLS correctness.
Reference: Read .claude/references/supabase-patterns.md first — it covers client usage, RLS patterns, query conventions, and migration rules.
Instructions
Use this skill when:
- Adding a new table or column
- Designing a complex query or index strategy
- Reviewing a migration before it runs in production
- Deciding how to store a new data type (e.g. new inflection pattern, new exercise type)
Step 1 — Review Existing Schema
cat supabase/migrations/001_initial_schema.sql
ls supabase/migrations/
Key tables:
| Table | Purpose | RLS |
|---|
words | Vocabulary, inflections as JSONB | Public read |
grammar_topics | Grammar explanations by module | Public read |
exercises | Quiz questions, all types | Public read |
sentences | Danish/English pairs | Public read |
user_cards | FSRS state per user per item | Private (user_id) |
review_logs | Review history for analytics | Private (user_id) |
Step 2 — Schema Design Checklist
For any new table, verify:
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,
topic_id UUID REFERENCES grammar_topics(id) ON DELETE SET NULL,
CHECK (module_level BETWEEN 1 AND 5),
CHECK (exercise_type IN ('type_answer','cloze','multiple_choice','word_order','error_correction','matching','conjugation')),
CREATE INDEX idx_user_cards_user_id ON user_cards(user_id);
CREATE INDEX idx_user_cards_due ON user_cards(due) WHERE state > 0;
Step 3 — RLS Policy Template
ALTER TABLE new_table ENABLE ROW LEVEL SECURITY;
CREATE POLICY "public_read" ON new_table
FOR SELECT USING (true);
CREATE POLICY "user_select" ON new_table
FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "user_insert" ON new_table
FOR INSERT WITH CHECK (auth.uid() = user_id);
CREATE POLICY "user_update" ON new_table
FOR UPDATE USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
CREATE POLICY "user_delete" ON new_table
FOR DELETE USING (auth.uid() = user_id);
UPDATE WITH CHECK rule: Every UPDATE policy on user-owned tables MUST include WITH CHECK matching the USING clause. Without it, a user can match their own row via USING but then set user_id to another value, effectively stealing the row. This applies to guest rows too — a guest could set is_guest = false or assign a user_id without WITH CHECK enforcement.
Step 4 — JSONB Inflection Patterns
Inflections are stored as JSONB. Validate new POS patterns against existing conventions:
When adding a new POS, document the JSONB shape in CLAUDE.md.
Step 5 — Migration Safety Review
Before approving a migration, check:
Step 6 — Query Performance Review
For any new query in hooks, evaluate:
- Does it use an indexed column in
WHERE / ORDER BY?
- Does it select only needed columns (avoid
SELECT *)?
- Does it paginate if result set could be large?
- Does it use
.single() only when exactly one row is guaranteed?
Output Format
## Data Architecture Review — <Feature>
### Schema changes
(tables / columns / indexes being added or modified)
### Migration SQL
\`\`\`sql
-- Proposed migration: 00N_description.sql
\`\`\`
### RLS policies
(list all policies for new/modified tables)
### Query patterns
(new queries added to hooks, with performance notes)
### Concerns
- [CONCERN] Description → resolution
### Decision
✓ Approved / ⚠ Approved with changes / ✗ Needs redesign