Optimized agents rules subfolders, dependencies updates (#355)

* Update AGENTS.md and CLAUDE.md for improved clarity and structure
* Added MCP Server
* Added missing triggers to tables that should have used them
* Updated all dependencies
* Fixed rare bug in React present in the Admin layout which prevents navigating to pages (sometimes...)
This commit is contained in:
Giancarlo Buomprisco
2025-09-17 11:36:02 +08:00
committed by GitHub
parent 9fae142f2d
commit 533dfba5b9
83 changed files with 9223 additions and 2974 deletions

292
apps/web/supabase/AGENTS.md Normal file
View File

@@ -0,0 +1,292 @@
# Supabase Database Schema Management
This file contains guidance for working with database schemas, migrations, and Supabase development workflows.
## Schema Organization
Schemas are organized in numbered files in the `schemas/` directory. Numbers are used to sort dependencies.
## Schema Development Workflow
### 1. Creating New Schema Files
```bash
# Create new schema file
touch schemas/15-my-new-feature.sql
# Apply changes and create migration
pnpm --filter web run supabase:db:diff -f my-new-feature
# Restart Supabase with fresh schema
pnpm supabase:web:reset
# Generate TypeScript types
pnpm supabase:web:typegen
```
### 2. Modifying Existing Schemas
```bash
# Edit schema file (e.g., schemas/03-accounts.sql)
# Make your changes...
# Create migration for changes
pnpm --filter web run supabase:db:diff -f update-accounts
# Apply and test
pnpm supabase:web:reset
pnpm supabase:web:typegen
```
## Security First Patterns
## Add permissions (if any)
```sql
ALTER TYPE public.app_permissions ADD VALUE 'notes.manage';
COMMIT;
```
### Table Creation with RLS
```sql
-- Create table
create table if not exists public.notes (
id uuid unique not null default extensions.uuid_generate_v4(),
account_id uuid references public.accounts(id) on delete cascade not null,
-- ...
primary key (id)
);
-- CRITICAL: Always enable RLS
alter table "public"."notes" enable row level security;
-- Revoke default permissions
revoke all on public.notes from authenticated, service_role;
-- Grant specific permissions
grant select, insert, update, delete on table public.notes to authenticated;
-- Add RLS policies
create policy "notes_read" on public.notes for select
to authenticated using (
account_id = (select auth.uid()) or
public.has_role_on_account(account_id)
);
create policy "notes_write" on public.notes for insert
to authenticated with check (
public.has_permission(auth.uid(), account_id, 'notes.manage'::app_permissions)
);
create policy "notes_update" on public.notes for update
to authenticated using (
public.has_permission(auth.uid(), account_id, 'notes.manage'::app_permissions)
)
with check (
public.has_permission(auth.uid(), account_id, 'notes.manage'::app_permissions)
);
create policy "notes_delete" on public.notes for delete
to authenticated using (
public.has_permission(auth.uid(), account_id, 'notes.manage'::app_permissions)
);
```
### Storage Bucket Policies
```sql
-- Create storage bucket
insert into storage.buckets (id, name, public)
values ('documents', 'documents', false);
-- RLS policy for storage
create policy documents_policy on storage.objects for all using (
bucket_id = 'documents'
and (
-- File belongs to user's account
kit.get_storage_filename_as_uuid(name) = auth.uid()
or
-- User has access to the account
public.has_role_on_account(kit.get_storage_filename_as_uuid(name))
)
)
with check (
bucket_id = 'documents'
and (
kit.get_storage_filename_as_uuid(name) = auth.uid()
or
public.has_permission(
auth.uid(),
kit.get_storage_filename_as_uuid(name),
'files.upload'::app_permissions
)
)
);
```
## Function Creation Patterns
### Safe Security Definer Functions
```sql
-- NEVER create security definer functions without explicit access controls
create or replace function public.create_team_account(account_name text)
returns public.accounts
language plpgsql
security definer -- Elevated privileges
set search_path = '' -- Prevent SQL injection
as $$
declare
new_account public.accounts;
begin
-- CRITICAL: Validate permissions first
if not public.is_set('enable_team_accounts') then
raise exception 'Team accounts are not enabled';
end if;
-- Additional validation can go here
if length(account_name) < 3 then
raise exception 'Account name must be at least 3 characters';
end if;
-- Now safe to proceed with elevated privileges
insert into public.accounts (name, is_personal_account)
values (account_name, false)
returning * into new_account;
return new_account;
end;
$$;
-- Grant to authenticated users only
grant execute on function public.create_team_account(text) to authenticated;
```
### Security Invoker Functions (Safer)
```sql
-- Preferred: Functions that inherit RLS policies
create or replace function public.get_account_notes(target_account_id uuid)
returns setof public.notes
language plpgsql
security invoker -- Inherits caller's permissions (RLS applies)
set search_path = ''
as $$
begin
-- RLS policies will automatically restrict results
return query
select * from public.notes
where account_id = target_account_id
order by created_at desc;
end;
$$;
grant execute on function public.get_account_notes(uuid) to authenticated;
```
### Safe Column Additions
```sql
-- Safe: Add nullable columns
alter table public.accounts
add column if not exists description text;
-- Safe: Add columns with defaults
alter table public.accounts
add column if not exists is_verified boolean default false not null;
-- Unsafe: Adding non-null columns without defaults
-- alter table public.accounts add column required_field text not null; -- DON'T DO THIS
```
### Index Management
```sql
-- Create indexes concurrently for large tables
create index concurrently if not exists ix_accounts_created_at
on public.accounts (created_at desc);
-- Drop unused indexes
drop index if exists ix_old_unused_index;
```
## Testing Database Changes
### Local Testing
```bash
# Test with fresh database
pnpm supabase:web:reset
# Test your changes
pnpm run supabase:web:test
```
## Type Generation
### After Schema Changes
```bash
# Generate types after any schema changes
pnpm supabase:web:typegen
# Types are generated to src/lib/supabase/database.types.ts
# Reset DB
pnpm supabase:web:reset
```
### Using Generated Types
```typescript
import { Enums, Tables } from '@kit/supabase/database';
// Table types
type Account = Tables<'accounts'>;
type Note = Tables<'notes'>;
// Enum types
type AppPermission = Enums<'app_permissions'>;
// Insert types
type AccountInsert = Tables<'accounts'>['Insert'];
type AccountUpdate = Tables<'accounts'>['Update'];
// Use in functions
async function createNote(data: Tables<'notes'>['Insert']) {
const { data: note, error } = await supabase
.from('notes')
.insert(data)
.select()
.single();
return note;
}
```
## Common Schema Patterns
### Audit Trail
Add triggers if the properties exist and are appropriate:
- `public.trigger_set_timestamps()` - for tables with `created_at` and `updated_at`
columns
- `public.trigger_set_user_tracking()` - for tables with `created_by` and `updated_by`
columns
### Useful Commands
```bash
# View migration status
pnpm --filter web supabase migration list
# Reset database completely
pnpm supabase:web:reset
# Generate migration from schema diff
pnpm --filter web run supabase:db:diff -f migration-name
# Apply specific migration
pnpm --filter web supabase migration up --include-schemas public
```