File size: 5,366 Bytes
288c936
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
-- ThaΓ€t β€” Supabase schema
-- Run once in Supabase SQL editor.

create table if not exists users (
  id                    uuid primary key,
  display_name          text not null,
  autism_level          text not null check (autism_level in ('Level 1', 'Level 2', 'Level 3')),
  age_range             text not null check (age_range in ('child', 'teen', 'adult')),
  primary_goal          text not null check (primary_goal in ('understand_others', 'express_myself', 'both')),
  hardest_emotions      text[] not null default '{}',
  caregiver_name        text,
  caregiver_email       text,
  notifications_enabled boolean not null default false,
  created_at            timestamptz not null default now(),
  updated_at            timestamptz not null default now()
);

create or replace function update_updated_at()
returns trigger language plpgsql as $$
begin
  new.updated_at = now();
  return new;
end;
$$;

drop trigger if exists users_updated_at on users;
create trigger users_updated_at
before update on users
for each row execute procedure update_updated_at();

create table if not exists sessions (
  id               uuid primary key default gen_random_uuid(),
  user_id          uuid not null references users(id) on delete cascade,
  mode             text not null check (mode in ('live', 'test', 'training')),
  overall_emotion  text,
  duration_seconds int not null default 0,
  created_at       timestamptz not null default now()
);

create index if not exists sessions_user_id_idx on sessions(user_id);
create index if not exists sessions_created_at_idx on sessions(created_at desc);

create table if not exists emotion_records (
  id               uuid primary key default gen_random_uuid(),
  user_id          uuid not null references users(id) on delete cascade,
  session_id       uuid references sessions(id) on delete cascade,
  spoken_text      text,
  text_emotion     text,
  face_emotion     text,
  body_emotion     text,
  fusion_emotion   text,
  conflict_type    text,
  insight          text,
  created_at       timestamptz not null default now()
);

create index if not exists emotion_records_user_id_idx on emotion_records(user_id);

create table if not exists training_logs (
  id                uuid primary key default gen_random_uuid(),
  user_id           uuid not null references users(id) on delete cascade,
  target_emotion    text not null,
  detected_emotion  text not null,
  score             int not null check (score >= 0 and score <= 100),
  success           boolean not null,
  feedback          text,
  created_at        timestamptz not null default now()
);

create index if not exists training_logs_user_id_idx  on training_logs(user_id);
create index if not exists training_logs_emotion_idx  on training_logs(target_emotion);
create index if not exists training_logs_created_idx  on training_logs(created_at desc);

-- ── Row Level Security ──────────────────────────────────────────────────────
-- IMPORTANT: The backend uses the SERVICE ROLE key (SUPABASE_SERVICE_KEY).
-- Service role bypasses RLS entirely β€” no policy needed for backend writes.
-- RLS here protects against direct client-side access ONLY.
-- Since the Flutter app writes through the backend (not direct Supabase SDK),
-- we only need RLS if you ever add direct Supabase client access from Flutter.
-- For now: enable RLS but add a permissive policy so backend writes work.
-- When you add Supabase Auth to Flutter, replace these with auth.uid() policies.

alter table users enable row level security;
alter table sessions enable row level security;
alter table emotion_records enable row level security;
alter table training_logs enable row level security;

-- Temporary open policies β€” backend service role bypasses RLS anyway.
-- Replace with auth.uid() = user_id once you add Supabase Auth to Flutter.
drop policy if exists "users: service write" on users;
create policy "users: service write" on users
  for all using (true) with check (true);

drop policy if exists "sessions: service write" on sessions;
create policy "sessions: service write" on sessions
  for all using (true) with check (true);

drop policy if exists "emotion_records: service write" on emotion_records;
create policy "emotion_records: service write" on emotion_records
  for all using (true) with check (true);

drop policy if exists "training_logs: service write" on training_logs;
create policy "training_logs: service write" on training_logs
  for all using (true) with check (true);

-- ── When you add Supabase Auth, replace the above with: ───────────────────
-- drop policy if exists "users: own row" on users;
-- create policy "users: own row" on users
--   for all using (auth.uid() = id) with check (auth.uid() = id);
-- (same pattern for sessions, emotion_records, training_logs)

create or replace view emotion_progress_monthly as
select
  user_id,
  target_emotion,
  date_trunc('month', created_at) as month,
  round(avg(score))               as avg_score,
  count(*)                        as attempts,
  sum(case when success then 1 else 0 end) as successes
from training_logs
group by user_id, target_emotion, date_trunc('month', created_at)
order by user_id, month desc, target_emotion;