aboutsummaryrefslogtreecommitdiff
path: root/supabase/migrations/20260204000001_initial_schema.sql
blob: 09b028e23a4bb8b148d7636f0ff2c7e78a48ec67 (plain) (blame)
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
create extension if not exists vector;

create table public.users (
    id uuid primary key references auth.users(id) on delete cascade,
    email text not null,
    display_name text,
    created_at timestamptz not null default now(),
    updated_at timestamptz not null default now()
);

create table public.projects (
    id uuid primary key default gen_random_uuid(),
    user_id uuid not null references public.users(id) on delete cascade,
    name text not null,
    description text,
    is_global boolean not null default false,
    created_at timestamptz not null default now(),
    updated_at timestamptz not null default now()
);

create table public.folders (
    id uuid primary key default gen_random_uuid(),
    project_id uuid not null references public.projects(id) on delete cascade,
    name text not null,
    description text,
    created_at timestamptz not null default now(),
    updated_at timestamptz not null default now()
);

create table public.memories (
    id uuid primary key default gen_random_uuid(),
    user_id uuid not null references public.users(id) on delete cascade,
    project_id uuid not null references public.projects(id) on delete cascade,
    folder_id uuid references public.folders(id) on delete set null,
    content text not null,
    tags jsonb not null default '[]'::jsonb,
    metadata jsonb not null default '{}'::jsonb,
    embedding vector(1536),
    created_at timestamptz not null default now(),
    updated_at timestamptz not null default now()
);

create index memories_user_id_idx on public.memories(user_id);
create index memories_project_id_idx on public.memories(project_id);
create index memories_folder_id_idx on public.memories(folder_id);
create index memories_tags_idx on public.memories using gin(tags);
create index memories_embedding_idx on public.memories using ivfflat (embedding vector_cosine_ops) with (lists = 100);

create index projects_user_id_idx on public.projects(user_id);
create index folders_project_id_idx on public.folders(project_id);

create or replace function public.handle_updated_at()
returns trigger as $$
begin
    new.updated_at = now();

    return new;
end;
$$ language plpgsql;

create trigger users_updated_at
    before update on public.users
    for each row execute function public.handle_updated_at();

create trigger projects_updated_at
    before update on public.projects
    for each row execute function public.handle_updated_at();

create trigger folders_updated_at
    before update on public.folders
    for each row execute function public.handle_updated_at();

create trigger memories_updated_at
    before update on public.memories
    for each row execute function public.handle_updated_at();

alter table public.users enable row level security;
alter table public.projects enable row level security;
alter table public.folders enable row level security;
alter table public.memories enable row level security;

create policy "Users can view own profile"
    on public.users for select
    using (auth.uid() = id);

create policy "Users can update own profile"
    on public.users for update
    using (auth.uid() = id);

create policy "Users can view own projects"
    on public.projects for select
    using (auth.uid() = user_id);

create policy "Users can create own projects"
    on public.projects for insert
    with check (auth.uid() = user_id);

create policy "Users can update own projects"
    on public.projects for update
    using (auth.uid() = user_id);

create policy "Users can delete own projects"
    on public.projects for delete
    using (auth.uid() = user_id);

create policy "Users can view folders in own projects"
    on public.folders for select
    using (
        exists (
            select 1 from public.projects
            where projects.id = folders.project_id
            and projects.user_id = auth.uid()
        )
    );

create policy "Users can create folders in own projects"
    on public.folders for insert
    with check (
        exists (
            select 1 from public.projects
            where projects.id = folders.project_id
            and projects.user_id = auth.uid()
        )
    );

create policy "Users can update folders in own projects"
    on public.folders for update
    using (
        exists (
            select 1 from public.projects
            where projects.id = folders.project_id
            and projects.user_id = auth.uid()
        )
    );

create policy "Users can delete folders in own projects"
    on public.folders for delete
    using (
        exists (
            select 1 from public.projects
            where projects.id = folders.project_id
            and projects.user_id = auth.uid()
        )
    );

create policy "Users can view own memories"
    on public.memories for select
    using (auth.uid() = user_id);

create policy "Users can create own memories"
    on public.memories for insert
    with check (auth.uid() = user_id);

create policy "Users can update own memories"
    on public.memories for update
    using (auth.uid() = user_id);

create policy "Users can delete own memories"
    on public.memories for delete
    using (auth.uid() = user_id);

create or replace function public.handle_new_user()
returns trigger as $$
begin
    insert into public.users (id, email)
    values (new.id, new.email);

    return new;
end;
$$ language plpgsql security definer;

create trigger on_auth_user_created
    after insert on auth.users
    for each row execute function public.handle_new_user();

create or replace function public.search_memories(
    query_embedding vector(1536),
    match_threshold float default 0.7,
    match_count int default 10,
    filter_project_id uuid default null,
    filter_folder_id uuid default null
)
returns table (
    id uuid,
    content text,
    project_id uuid,
    folder_id uuid,
    tags jsonb,
    metadata jsonb,
    similarity float,
    created_at timestamptz,
    updated_at timestamptz
)
language plpgsql
security definer
as $$
begin
    return query
    select
        m.id,
        m.content,
        m.project_id,
        m.folder_id,
        m.tags,
        m.metadata,
        1 - (m.embedding <=> query_embedding) as similarity,
        m.created_at,
        m.updated_at
    from public.memories m
    where m.user_id = auth.uid()
        and m.embedding is not null
        and 1 - (m.embedding <=> query_embedding) > match_threshold
        and (filter_project_id is null or m.project_id = filter_project_id)
        and (filter_folder_id is null or m.folder_id = filter_folder_id)
    order by m.embedding <=> query_embedding
    limit match_count;
end;
$$;