Generated automatically from the linked Supabase database.
Do not edit this file manually. Run npm run db:schema instead.
Scope
- PostgreSQL schema:
tuasesor
- Contains structural metadata only
- Contains no table rows, OAuth tokens, passwords, or customer records
- Database migrations remain the historical record of schema changes
Summary
- Tables: 17
- Functions declared in
tuasesor: 8
- Tables with RLS enabled: 10
Table accounting_accounts
Workspace-scoped accounting account catalog used to classify expense report items.
- Row Level Security: enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | uuid | No | "gen_random_uuid"() | NOT NULL |
workspace_id | uuid | No | - | NOT NULL |
code | text | Yes | - | - |
name | text | No | - | NOT NULL |
account_type | text | No | - | NOT NULL |
is_active | boolean | No | true | NOT NULL |
created_at | timestamp with time zone | No | "now"() | NOT NULL |
updated_at | timestamp with time zone | No | "now"() | NOT NULL |
Constraints
"accounting_accounts_pkey": PRIMARY KEY ("id")
"accounting_accounts_workspace_code_key": UNIQUE ("workspace_id", "code")
"accounting_accounts_workspace_id_fkey": FOREIGN KEY ("workspace_id") REFERENCES "tuasesor"."workspaces"("id") ON DELETE CASCADE
Indexes
"idx_accounting_accounts_workspace_id": USING "btree" ("workspace_id")
RLS policies
"accounting_accounts_select_workspace_members": FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 FROM "tuasesor"."workspace_members" "workspace_member" WHERE (("workspace_member"."workspace_id" = "accounting_accounts"."workspace_id") AND ("workspace_member"."profile_id" = "auth"."uid"())))))
Grants
ALL TO "service_role"
SELECT TO "authenticated"
Triggers
"trigger_accounting_accounts_updated_at": BEFORE UPDATE ON "accounting_accounts" FOR EACH ROW EXECUTE FUNCTION "public"."update_updated_at_column"()
Table business_lines
Workspace-scoped catalog for business lines used in expense reports.
- Row Level Security: enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | uuid | No | "gen_random_uuid"() | NOT NULL |
workspace_id | uuid | No | - | NOT NULL |
code | text | Yes | - | - |
name | text | No | - | NOT NULL |
is_active | boolean | No | true | NOT NULL |
created_at | timestamp with time zone | No | "now"() | NOT NULL |
updated_at | timestamp with time zone | No | "now"() | NOT NULL |
Constraints
"business_lines_pkey": PRIMARY KEY ("id")
"business_lines_workspace_code_key": UNIQUE ("workspace_id", "code")
"business_lines_workspace_id_fkey": FOREIGN KEY ("workspace_id") REFERENCES "tuasesor"."workspaces"("id") ON DELETE CASCADE
Indexes
"idx_business_lines_workspace_id": USING "btree" ("workspace_id")
RLS policies
"business_lines_select_workspace_members": FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 FROM "tuasesor"."workspace_members" "workspace_member" WHERE (("workspace_member"."workspace_id" = "business_lines"."workspace_id") AND ("workspace_member"."profile_id" = "auth"."uid"())))))
Grants
ALL TO "service_role"
SELECT TO "authenticated"
Triggers
"trigger_business_lines_updated_at": BEFORE UPDATE ON "business_lines" FOR EACH ROW EXECUTE FUNCTION "public"."update_updated_at_column"()
Table cost_centers
Workspace-scoped catalog for cost centers used in expense reports.
- Row Level Security: enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | uuid | No | "gen_random_uuid"() | NOT NULL |
workspace_id | uuid | No | - | NOT NULL |
code | text | Yes | - | - |
name | text | No | - | NOT NULL |
is_active | boolean | No | true | NOT NULL |
created_at | timestamp with time zone | No | "now"() | NOT NULL |
updated_at | timestamp with time zone | No | "now"() | NOT NULL |
Constraints
"cost_centers_pkey": PRIMARY KEY ("id")
"cost_centers_workspace_code_key": UNIQUE ("workspace_id", "code")
"cost_centers_workspace_id_fkey": FOREIGN KEY ("workspace_id") REFERENCES "tuasesor"."workspaces"("id") ON DELETE CASCADE
Indexes
"idx_cost_centers_workspace_id": USING "btree" ("workspace_id")
RLS policies
"cost_centers_select_workspace_members": FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 FROM "tuasesor"."workspace_members" "workspace_member" WHERE (("workspace_member"."workspace_id" = "cost_centers"."workspace_id") AND ("workspace_member"."profile_id" = "auth"."uid"())))))
Grants
ALL TO "service_role"
SELECT TO "authenticated"
Triggers
"trigger_cost_centers_updated_at": BEFORE UPDATE ON "cost_centers" FOR EACH ROW EXECUTE FUNCTION "public"."update_updated_at_column"()
Table document_types
- Row Level Security: not enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | integer | No | - | NOT NULL |
code | text | Yes | - | - |
name | text | Yes | - | - |
Constraints
"document_types_code_key": UNIQUE ("code")
"document_types_pkey": PRIMARY KEY ("id")
Grants
ALL TO "anon"
ALL TO "authenticated"
ALL TO "service_role"
Table documents
- Row Level Security: enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | uuid | No | "gen_random_uuid"() | NOT NULL |
name | text | No | - | NOT NULL |
source | text | No | - | NOT NULL |
external_id | text | Yes | - | - |
storage_path | text | Yes | - | - |
web_view_link | text | Yes | - | - |
mime_type | text | Yes | - | - |
size_bytes | bigint | Yes | - | - |
modified_time | timestamp with time zone | Yes | - | - |
document_type_id | integer | Yes | - | - |
created_at | timestamp with time zone | No | "now"() | NOT NULL |
updated_at | timestamp with time zone | No | "now"() | NOT NULL |
drive_file_id | text | Yes | - | - |
modified_at | timestamp with time zone | Yes | - | - |
provider | text | Yes | 'google'::"text" | - |
profile_id | uuid | Yes | - | - |
type | text | Yes | - | - |
drive_parent_id | text | Yes | - | - |
sync_status | text | Yes | 'active'::"text" | - |
sync_batch_id | uuid | Yes | - | - |
web_content_link | text | Yes | - | - |
workspace_id | uuid | Yes | - | - |
workspace_source_id | uuid | Yes | - | - |
entity_type | text | Yes | - | - |
entity_id | text | Yes | - | - |
Constraints
"documents_document_type_id_fkey": FOREIGN KEY ("document_type_id") REFERENCES "tuasesor"."document_types"("id") DEFERRABLE
"documents_pkey": PRIMARY KEY ("id")
"documents_profile_id_fkey": FOREIGN KEY ("profile_id") REFERENCES "tuasesor"."profiles"("id") ON DELETE SET NULL
"documents_workspace_id_fkey": FOREIGN KEY ("workspace_id") REFERENCES "tuasesor"."workspaces"("id") ON DELETE SET NULL
"documents_workspace_source_id_fkey": FOREIGN KEY ("workspace_source_id") REFERENCES "tuasesor"."workspace_sources"("id") ON DELETE SET NULL
"unique_drive_file": UNIQUE ("drive_file_id")
CONSTRAINT "check_source" CHECK (("source" = ANY (ARRAY['google_drive'::"text", 'internal_upload'::"text"])))
CONSTRAINT "documents_sync_status_check" CHECK (("sync_status" = ANY (ARRAY['active'::"text", 'deleted_in_drive'::"text"])))
CONSTRAINT "documents_type_check" CHECK (("type" = ANY (ARRAY['file'::"text", 'folder'::"text"])))
Indexes
"idx_documents_entity": USING "btree" ("entity_type", "entity_id")
"idx_documents_parent": USING "btree" ("drive_parent_id")
"idx_documents_sync_status": USING "btree" ("sync_status")
"idx_documents_type": USING "btree" ("type")
"idx_documents_user_id": USING "btree" ("profile_id")
"idx_documents_workspace_id": USING "btree" ("workspace_id")
"idx_documents_workspace_source_id": USING "btree" ("workspace_source_id")
UNIQUE "idx_documents_drive_file_id": USING "btree" ("drive_file_id") WHERE ("drive_file_id" IS NOT NULL)
UNIQUE "idx_documents_external_id": USING "btree" ("external_id") WHERE ("external_id" IS NOT NULL)
RLS policies
No row-level policies were detected for this table in the exported schema.
Grants
Table expense_report_items
Individual expense lines declared inside an expense report.
- Row Level Security: enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | uuid | No | "gen_random_uuid"() | NOT NULL |
expense_report_id | uuid | No | - | NOT NULL |
business_line_id | uuid | Yes | - | - |
cost_center_id | uuid | Yes | - | - |
accounting_account_id | uuid | Yes | - | - |
expense_date | date | No | - | NOT NULL |
supplier_name | text | Yes | - | - |
document_type_id | integer | Yes | - | - |
document_number | text | Yes | - | - |
total_amount | numeric(14,2) | No | - | NOT NULL |
description | text | Yes | - | - |
additional_notes | text | Yes | - | - |
created_at | timestamp with time zone | No | "now"() | NOT NULL |
updated_at | timestamp with time zone | No | "now"() | NOT NULL |
Constraints
"expense_report_items_accounting_account_id_fkey": FOREIGN KEY ("accounting_account_id") REFERENCES "tuasesor"."accounting_accounts"("id") ON DELETE SET NULL
"expense_report_items_additional_notes_length_check": CHECK ((("additional_notes" IS NULL) OR ("char_length"("additional_notes") <= 500))) NOT VALID
"expense_report_items_business_line_id_fkey": FOREIGN KEY ("business_line_id") REFERENCES "tuasesor"."business_lines"("id") ON DELETE SET NULL
"expense_report_items_cost_center_id_fkey": FOREIGN KEY ("cost_center_id") REFERENCES "tuasesor"."cost_centers"("id") ON DELETE SET NULL
"expense_report_items_description_length_check": CHECK ((("description" IS NULL) OR ("char_length"("description") <= 500))) NOT VALID
"expense_report_items_document_number_length_check": CHECK ((("document_number" IS NULL) OR ("char_length"("document_number") <= 100))) NOT VALID
"expense_report_items_document_type_id_fkey": FOREIGN KEY ("document_type_id") REFERENCES "tuasesor"."document_types"("id") ON DELETE SET NULL
"expense_report_items_expense_report_id_fkey": FOREIGN KEY ("expense_report_id") REFERENCES "tuasesor"."expense_reports"("id") ON DELETE CASCADE
"expense_report_items_pkey": PRIMARY KEY ("id")
"expense_report_items_supplier_name_length_check": CHECK ((("supplier_name" IS NULL) OR ("char_length"("supplier_name") <= 150))) NOT VALID
CONSTRAINT "expense_report_items_total_amount_check" CHECK (("total_amount" > (0)::numeric))
Indexes
"idx_expense_report_items_expense_date": USING "btree" ("expense_date")
"idx_expense_report_items_report_expense_date": USING "btree" ("expense_report_id", "expense_date" DESC)
"idx_expense_report_items_report_id": USING "btree" ("expense_report_id")
RLS policies
"expense_report_items_delete_draft_workspace_writers": FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1 FROM "tuasesor"."expense_reports" "expense_report" WHERE (("expense_report"."id" = "expense_report_items"."expense_report_id") AND ("expense_report"."status" = 'draft'::"text") AND "tuasesor"."can_write_workspace"("expense_report"."workspace_id")))))
"expense_report_items_insert_draft_workspace_writers": FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 FROM "tuasesor"."expense_reports" "expense_report" WHERE (("expense_report"."id" = "expense_report_items"."expense_report_id") AND ("expense_report"."status" = 'draft'::"text") AND "tuasesor"."can_write_workspace"("expense_report"."workspace_id")))))
"expense_report_items_select_workspace_members": FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 FROM ("tuasesor"."expense_reports" "expense_report" JOIN "tuasesor"."workspace_members" "workspace_member" ON (("workspace_member"."workspace_id" = "expense_report"."workspace_id"))) WHERE (("expense_report"."id" = "expense_report_items"."expense_report_id") AND ("workspace_member"."profile_id" = "auth"."uid"())))))
"expense_report_items_update_draft_workspace_writers": FOR UPDATE TO "authenticated" USING ((EXISTS ( SELECT 1 FROM "tuasesor"."expense_reports" "expense_report" WHERE (("expense_report"."id" = "expense_report_items"."expense_report_id") AND ("expense_report"."status" = 'draft'::"text") AND "tuasesor"."can_write_workspace"("expense_report"."workspace_id"))))) WITH CHECK ((EXISTS ( SELECT 1 FROM "tuasesor"."expense_reports" "expense_report" WHERE (("expense_report"."id" = "expense_report_items"."expense_report_id") AND ("expense_report"."status" = 'draft'::"text") AND "tuasesor"."can_write_workspace"("expense_report"."workspace_id")))))
Grants
ALL TO "service_role"
SELECT,INSERT,DELETE,UPDATE TO "authenticated"
Triggers
"trigger_expense_report_items_updated_at": BEFORE UPDATE ON "expense_report_items" FOR EACH ROW EXECUTE FUNCTION "public"."update_updated_at_column"()
"trigger_prevent_expense_report_item_parent_change": BEFORE UPDATE OF "expense_report_id" ON "expense_report_items" FOR EACH ROW EXECUTE FUNCTION "tuasesor"."prevent_expense_report_item_parent_change"()
"trigger_validate_expense_report_item_catalogs": BEFORE INSERT OR UPDATE OF "expense_report_id", "business_line_id", "cost_center_id", "accounting_account_id", "document_type_id" ON "expense_report_items" FOR EACH ROW EXECUTE FUNCTION "tuasesor"."validate_expense_report_item_catalogs"()
Table expense_reports
Business domain table representing complete expense reports submitted within a workspace.
- Row Level Security: enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | uuid | No | "gen_random_uuid"() | NOT NULL |
workspace_id | uuid | No | - | NOT NULL |
report_number | text | No | - | NOT NULL |
report_year | integer | No | - | NOT NULL |
submitted_by_profile_id | uuid | Yes | - | - |
status | text | No | 'draft'::"text" | NOT NULL |
submitted_at | timestamp with time zone | Yes | - | - |
reviewed_at | timestamp with time zone | Yes | - | - |
reimbursed_at | timestamp with time zone | Yes | - | - |
notes | text | Yes | - | - |
created_at | timestamp with time zone | No | "now"() | NOT NULL |
updated_at | timestamp with time zone | No | "now"() | NOT NULL |
Constraints
"expense_reports_pkey": PRIMARY KEY ("id")
"expense_reports_submitted_by_profile_id_fkey": FOREIGN KEY ("submitted_by_profile_id") REFERENCES "tuasesor"."profiles"("id") ON DELETE SET NULL
"expense_reports_workspace_id_fkey": FOREIGN KEY ("workspace_id") REFERENCES "tuasesor"."workspaces"("id") ON DELETE CASCADE
"expense_reports_workspace_year_report_number_key": UNIQUE ("workspace_id", "report_year", "report_number")
CONSTRAINT "expense_reports_report_year_check" CHECK ((("report_year" >= 2000) AND ("report_year" <= 2100)))
CONSTRAINT "expense_reports_status_check" CHECK (("status" = ANY (ARRAY['draft'::"text", 'submitted'::"text", 'under_review'::"text", 'approved'::"text", 'rejected'::"text", 'reimbursed'::"text", 'cancelled'::"text"])))
Indexes
"idx_expense_reports_report_year": USING "btree" ("report_year")
"idx_expense_reports_status": USING "btree" ("status")
"idx_expense_reports_workspace_created_at": USING "btree" ("workspace_id", "created_at" DESC)
"idx_expense_reports_workspace_id": USING "btree" ("workspace_id")
"idx_expense_reports_workspace_profile_created_at": USING "btree" ("workspace_id", "submitted_by_profile_id", "created_at" DESC) WHERE ("submitted_by_profile_id" IS NOT NULL)
"idx_expense_reports_workspace_status_created_at": USING "btree" ("workspace_id", "status", "created_at" DESC)
RLS policies
"expense_reports_insert_workspace_writers": FOR INSERT TO "authenticated" WITH CHECK ("tuasesor"."can_write_workspace"("workspace_id"))
"expense_reports_select_workspace_members": FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 FROM "tuasesor"."workspace_members" "workspace_member" WHERE (("workspace_member"."workspace_id" = "expense_reports"."workspace_id") AND ("workspace_member"."profile_id" = "auth"."uid"())))))
"expense_reports_update_workspace_writers": FOR UPDATE TO "authenticated" USING ("tuasesor"."can_write_workspace"("workspace_id")) WITH CHECK ("tuasesor"."can_write_workspace"("workspace_id"))
Grants
ALL TO "service_role"
SELECT,INSERT,UPDATE TO "authenticated"
Triggers
"trigger_expense_reports_updated_at": BEFORE UPDATE ON "expense_reports" FOR EACH ROW EXECUTE FUNCTION "public"."update_updated_at_column"()
Table integrations
- Row Level Security: enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | uuid | No | "gen_random_uuid"() | NOT NULL |
profile_id | uuid | No | - | NOT NULL |
provider | text | No | - | NOT NULL |
access_token | text | Yes | - | - |
refresh_token | text | Yes | - | - |
expires_at | timestamp with time zone | Yes | - | - |
created_at | timestamp with time zone | No | "now"() | NOT NULL |
metadata | jsonb | Yes | '{}'::"jsonb" | - |
provider_account_id | text | Yes | - | - |
scopes | "text"[] | Yes | '{}'::"text"[] | - |
Constraints
"integrations_pkey": PRIMARY KEY ("id")
"integrations_profile_id_fkey": FOREIGN KEY ("profile_id") REFERENCES "tuasesor"."profiles"("id") ON DELETE CASCADE
"integrations_provider_provider_account_id_key": UNIQUE ("provider", "provider_account_id")
"unique_user_provider": UNIQUE ("profile_id", "provider")
Indexes
"idx_integrations_metadata": USING "gin" ("metadata")
"idx_integrations_provider_account_id": USING "btree" ("provider_account_id")
"idx_integrations_provider_provider_account_id": USING "btree" ("provider", "provider_account_id")
"idx_integrations_scopes": USING "gin" ("scopes")
"idx_integrations_user_id": USING "btree" ("profile_id")
RLS policies
"integrations_delete_own_profile": FOR DELETE TO "authenticated" USING (("auth"."uid"() = "profile_id"))
"integrations_insert_own_profile": FOR INSERT TO "authenticated" WITH CHECK (("auth"."uid"() = "profile_id"))
"integrations_select_own_profile": FOR SELECT TO "authenticated" USING (("auth"."uid"() = "profile_id"))
"integrations_update_own_profile": FOR UPDATE TO "authenticated" USING (("auth"."uid"() = "profile_id")) WITH CHECK (("auth"."uid"() = "profile_id"))
Grants
ALL TO "service_role"
SELECT,INSERT,DELETE,UPDATE TO "authenticated"
Table normalized_documents
Structured knowledge layer used by cortexa-sdk for normalized and persistent document intelligence.
- Row Level Security: enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | uuid | No | "gen_random_uuid"() | NOT NULL |
document_id | uuid | Yes | - | - |
source | text | No | - | NOT NULL |
external_id | text | No | - | NOT NULL |
title | text | Yes | - | - |
filename | text | Yes | - | - |
mime_type | text | Yes | - | - |
content_text | text | Yes | - | - |
metadata_json | jsonb | Yes | - | - |
created_at | timestamp with time zone | No | "now"() | NOT NULL |
updated_at | timestamp with time zone | No | "now"() | NOT NULL |
normalized_at | timestamp with time zone | No | "now"() | NOT NULL |
workspace_id | uuid | Yes | - | - |
Constraints
"normalized_documents_document_id_fkey": FOREIGN KEY ("document_id") REFERENCES "tuasesor"."documents"("id") ON DELETE SET NULL
"normalized_documents_pkey": PRIMARY KEY ("id")
"normalized_documents_workspace_id_fkey": FOREIGN KEY ("workspace_id") REFERENCES "tuasesor"."workspaces"("id") ON DELETE SET NULL
Indexes
"idx_normalized_documents_external_id": USING "btree" ("external_id")
"idx_normalized_documents_mime_type": USING "btree" ("mime_type")
"idx_normalized_documents_source": USING "btree" ("source")
"idx_normalized_documents_workspace_id": USING "btree" ("workspace_id")
RLS policies
No row-level policies were detected for this table in the exported schema.
Grants
ALL TO "anon"
ALL TO "authenticated"
ALL TO "service_role"
Triggers
"trigger_normalized_documents_updated_at": BEFORE UPDATE ON "normalized_documents" FOR EACH ROW EXECUTE FUNCTION "public"."update_updated_at_column"()
Table profile_specialties
Many-to-many relationship between profiles and professional specialties.
- Row Level Security: not enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | uuid | No | "gen_random_uuid"() | NOT NULL |
profile_id | uuid | No | - | NOT NULL |
specialty_id | uuid | No | - | NOT NULL |
is_primary | boolean | No | false | NOT NULL |
years_experience | integer | Yes | - | - |
metadata_json | jsonb | No | '{}'::"jsonb" | NOT NULL |
created_at | timestamp with time zone | No | "now"() | NOT NULL |
Constraints
"profile_specialties_pkey": PRIMARY KEY ("id")
"profile_specialties_profile_id_fkey": FOREIGN KEY ("profile_id") REFERENCES "tuasesor"."profiles"("id") ON DELETE CASCADE
"profile_specialties_profile_id_specialty_id_key": UNIQUE ("profile_id", "specialty_id")
"profile_specialties_specialty_id_fkey": FOREIGN KEY ("specialty_id") REFERENCES "tuasesor"."specialties"("id") ON DELETE CASCADE
Indexes
"idx_profile_specialties_profile_id": USING "btree" ("profile_id")
"idx_profile_specialties_specialty_id": USING "btree" ("specialty_id")
Grants
ALL TO "service_role"
SELECT TO "authenticated"
Table profiles
Application-level user profiles associated 1:1 with auth.users.
- Row Level Security: not enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | uuid | No | - | NOT NULL |
email | text | No | - | NOT NULL |
full_name | text | Yes | - | - |
avatar_url | text | Yes | - | - |
global_role | text | No | 'member'::"text" | NOT NULL |
metadata_json | jsonb | No | '{}'::"jsonb" | NOT NULL |
created_at | timestamp with time zone | No | "now"() | NOT NULL |
updated_at | timestamp with time zone | No | "now"() | NOT NULL |
profile_type | text | No | 'member'::"text" | NOT NULL |
status | text | No | 'pending'::"text" | NOT NULL |
Constraints
"profiles_auth_user_id_fkey": FOREIGN KEY ("id") REFERENCES "auth"."users"("id") ON DELETE CASCADE
"profiles_email_key": UNIQUE ("email")
"profiles_pkey": PRIMARY KEY ("id")
CONSTRAINT "profiles_status_check" CHECK (("status" = ANY (ARRAY['pending'::"text", 'active'::"text", 'disabled'::"text"])))
Indexes
"idx_profiles_status": USING "btree" ("status")
Grants
ALL TO "service_role"
SELECT TO "authenticated"
Table specialties
Professional specialties catalog used for marketplace identity and expertise classification.
- Row Level Security: not enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | uuid | No | "gen_random_uuid"() | NOT NULL |
code | text | No | - | NOT NULL |
name | text | No | - | NOT NULL |
category | text | Yes | - | - |
created_at | timestamp with time zone | No | "now"() | NOT NULL |
Constraints
"specialties_code_key": UNIQUE ("code")
"specialties_pkey": PRIMARY KEY ("id")
Indexes
"idx_specialties_code": USING "btree" ("code")
Grants
ALL TO "service_role"
SELECT TO "authenticated"
Table transactions
- Row Level Security: not enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | uuid | No | "gen_random_uuid"() | NOT NULL |
document_id | uuid | Yes | - | - |
type | text | No | - | NOT NULL |
date | date | No | - | NOT NULL |
amount | numeric(12,2) | No | - | NOT NULL |
description | text | Yes | - | - |
document_number | text | Yes | - | - |
status | text | Yes | 'pending'::"text" | - |
profile_id | uuid | Yes | - | - |
created_at | timestamp with time zone | No | "now"() | NOT NULL |
Constraints
"transactions_document_id_fkey": FOREIGN KEY ("document_id") REFERENCES "tuasesor"."documents"("id") DEFERRABLE
"transactions_pkey": PRIMARY KEY ("id")
"transactions_profile_id_fkey": FOREIGN KEY ("profile_id") REFERENCES "tuasesor"."profiles"("id") ON DELETE SET NULL
CONSTRAINT "check_status" CHECK (("status" = ANY (ARRAY['pending'::"text", 'reviewed'::"text"])))
CONSTRAINT "check_type" CHECK (("type" = ANY (ARRAY['income'::"text", 'expense'::"text"])))
Grants
ALL TO "anon"
ALL TO "authenticated"
ALL TO "service_role"
Table workspace_member_permissions
Granular permissions associated to workspace memberships.
- Row Level Security: not enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | uuid | No | "gen_random_uuid"() | NOT NULL |
workspace_member_id | uuid | No | - | NOT NULL |
permission_key | text | No | - | NOT NULL |
granted | boolean | No | true | NOT NULL |
metadata_json | jsonb | No | '{}'::"jsonb" | NOT NULL |
created_at | timestamp with time zone | No | "now"() | NOT NULL |
Constraints
"workspace_member_permissions_pkey": PRIMARY KEY ("id")
"workspace_member_permissions_workspace_member_id_fkey": FOREIGN KEY ("workspace_member_id") REFERENCES "tuasesor"."workspace_members"("id") ON DELETE CASCADE
"workspace_member_permissions_workspace_member_id_permission_key": UNIQUE ("workspace_member_id", "permission_key")
Grants
ALL TO "service_role"
SELECT TO "authenticated"
Table workspace_members
Workspace-scoped memberships and permissions associated to profiles.
- Row Level Security: enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | uuid | No | "gen_random_uuid"() | NOT NULL |
workspace_id | uuid | No | - | NOT NULL |
profile_id | uuid | No | - | NOT NULL |
role | text | No | - | NOT NULL |
created_at | timestamp with time zone | No | "now"() | NOT NULL |
Constraints
"unique_workspace_user": UNIQUE ("workspace_id", "profile_id")
"workspace_members_profile_id_fkey": FOREIGN KEY ("profile_id") REFERENCES "tuasesor"."profiles"("id") ON DELETE CASCADE
"workspace_users_pkey": PRIMARY KEY ("id")
"workspace_users_workspace_id_fkey": FOREIGN KEY ("workspace_id") REFERENCES "tuasesor"."workspaces"("id") ON DELETE CASCADE
CONSTRAINT "check_workspace_user_role" CHECK (("role" = ANY (ARRAY['owner'::"text", 'admin'::"text", 'member'::"text", 'viewer'::"text", 'client'::"text"])))
Indexes
"idx_workspace_users_role": USING "btree" ("role")
"idx_workspace_users_user_id": USING "btree" ("profile_id")
"idx_workspace_users_workspace_id": USING "btree" ("workspace_id")
RLS policies
"workspace_members_select_own_profile": FOR SELECT TO "authenticated" USING (("profile_id" = "auth"."uid"()))
Grants
ALL TO "service_role"
SELECT TO "authenticated"
Table workspace_sources
Provider-specific documentary integrations associated to a workspace.
- Row Level Security: not enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | uuid | No | "gen_random_uuid"() | NOT NULL |
workspace_id | uuid | No | - | NOT NULL |
provider | text | No | - | NOT NULL |
external_id | text | No | - | NOT NULL |
root_path | text | Yes | - | - |
metadata_json | jsonb | Yes | - | - |
is_active | boolean | No | true | NOT NULL |
last_synced_at | timestamp with time zone | Yes | - | - |
profile_id | uuid | Yes | - | - |
created_at | timestamp with time zone | No | "now"() | NOT NULL |
updated_at | timestamp with time zone | No | "now"() | NOT NULL |
Constraints
"unique_workspace_provider_external": UNIQUE ("workspace_id", "provider", "external_id")
"workspace_sources_pkey": PRIMARY KEY ("id")
"workspace_sources_profile_id_fkey": FOREIGN KEY ("profile_id") REFERENCES "tuasesor"."profiles"("id") ON DELETE SET NULL
"workspace_sources_workspace_id_fkey": FOREIGN KEY ("workspace_id") REFERENCES "tuasesor"."workspaces"("id") ON DELETE CASCADE
Indexes
"idx_workspace_sources_external_id": USING "btree" ("external_id")
"idx_workspace_sources_is_active": USING "btree" ("is_active")
"idx_workspace_sources_provider": USING "btree" ("provider")
"idx_workspace_sources_workspace_id": USING "btree" ("workspace_id")
Grants
ALL TO "anon"
ALL TO "authenticated"
ALL TO "service_role"
Triggers
"trigger_workspace_sources_updated_at": BEFORE UPDATE ON "workspace_sources" FOR EACH ROW EXECUTE FUNCTION "public"."update_updated_at_column"()
Table workspaces
Operational documentary context authorized within TUASESOR.
- Row Level Security: enabled
Columns
| Name | Type | Nullable | Default | Additional definition |
|---|
id | uuid | No | "gen_random_uuid"() | NOT NULL |
name | text | No | - | NOT NULL |
description | text | Yes | - | - |
created_by | uuid | Yes | - | - |
created_at | timestamp with time zone | No | "now"() | NOT NULL |
updated_at | timestamp with time zone | No | "now"() | NOT NULL |
Constraints
"workspaces_pkey": PRIMARY KEY ("id")
Indexes
"idx_workspaces_created_by": USING "btree" ("created_by")
RLS policies
"workspaces_select_for_members": FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 FROM "tuasesor"."workspace_members" "workspace_member" WHERE (("workspace_member"."workspace_id" = "workspaces"."id") AND ("workspace_member"."profile_id" = "auth"."uid"())))))
Grants
ALL TO "anon"
ALL TO "authenticated"
ALL TO "service_role"
Triggers
"trigger_workspaces_updated_at": BEFORE UPDATE ON "workspaces" FOR EACH ROW EXECUTE FUNCTION "public"."update_updated_at_column"()
Functions
"can_write_workspace"("p_workspace_id" "uuid") RETURNS boolean LANGUAGE "sql" STABLE SECURITY DEFINER SET "search_path" TO 'pg_catalog', 'tuasesor' AS $$ SELECT auth.uid() IS NOT NULL AND p_workspace_id IS NOT NULL AND EXISTS ( SELECT 1 FROM tuasesor.workspace_members AS workspace_member WHERE workspace_member.workspace_id = p_workspace_id AND workspace_member.profile_id = auth.uid() AND workspace_member.role IN ( 'owner', 'admin', 'member' ) ); $$
"create_expense_report"("p_workspace_id" "uuid", "p_report_number" "text", "p_report_year" integer, "p_notes" "text", "p_items" "jsonb") RETURNS "tuasesor"."expense_reports" LANGUAGE "plpgsql" SET "search_path" TO 'pg_catalog', 'tuasesor' AS $$ DECLARE v_profile_id uuid; v_report tuasesor.expense_reports; v_item jsonb; v_business_line_id uuid; v_cost_center_id uuid; v_accounting_account_id uuid; v_document_type_id integer; BEGIN v_profile_id := auth.uid(); IF v_profile_id IS NULL THEN RAISE EXCEPTION 'Authentication is required' USING ERRCODE = '42501'; END IF; IF p_workspace_id IS NULL THEN RAISE EXCEPTION 'workspace_id is required' USING ERRCODE = '22023'; END IF; IF NOT tuasesor.can_write_workspace(p_workspace_id) THEN RAISE EXCEPTION 'Not authorized to write in this workspace' USING ERRCODE = '42501'; END IF; IF p_report_number IS NULL OR btrim(p_report_number) = '' THEN RAISE EXCEPTION 'report_number is required' USING ERRCODE = '22023'; END IF; IF p_report_year < 2000 OR p_report_year > 2100 THEN RAISE EXCEPTION 'report_year must be between 2000 and 2100' USING ERRCODE = '22023'; END IF; IF p_items IS NULL OR jsonb_typeof(p_items) <> 'array' THEN RAISE EXCEPTION 'items must be a JSON array' USING ERRCODE = '22023'; END IF; INSERT INTO tuasesor.expense_reports ( workspace_id, report_number, report_year, submitted_by_profile_id, status, notes ) VALUES ( p_workspace_id, btrim(p_report_number), p_report_year, v_profile_id, 'draft', nullif(btrim(p_notes), '') ) RETURNING * INTO v_report; FOR v_item IN SELECT value FROM jsonb_array_elements(p_items) LOOP v_business_line_id := nullif(v_item ->> 'business_line_id', '')::uuid; v_cost_center_id := nullif(v_item ->> 'cost_center_id', '')::uuid; v_accounting_account_id := nullif(v_item ->> 'accounting_account_id', '')::uuid; v_document_type_id := nullif(v_item ->> 'document_type_id', '')::integer; IF v_business_line_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tuasesor.business_lines AS business_line WHERE business_line.id = v_business_line_id AND business_line.workspace_id = p_workspace_id ) THEN RAISE EXCEPTION 'Business line does not belong to the workspace' USING ERRCODE = '23503'; END IF; IF v_cost_center_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tuasesor.cost_centers AS cost_center WHERE cost_center.id = v_cost_center_id AND cost_center.workspace_id = p_workspace_id ) THEN RAISE EXCEPTION 'Cost center does not belong to the workspace' USING ERRCODE = '23503'; END IF; IF v_accounting_account_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tuasesor.accounting_accounts AS accounting_account WHERE accounting_account.id = v_accounting_account_id AND accounting_account.workspace_id = p_workspace_id ) THEN RAISE EXCEPTION 'Accounting account does not belong to the workspace' USING ERRCODE = '23503'; END IF; IF v_document_type_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tuasesor.document_types AS document_type WHERE document_type.id = v_document_type_id ) THEN RAISE EXCEPTION 'Document type does not exist' USING ERRCODE = '23503'; END IF; INSERT INTO tuasesor.expense_report_items ( expense_report_id, business_line_id, cost_center_id, accounting_account_id, expense_date, supplier_name, document_type_id, document_number, total_amount, description, additional_notes ) VALUES ( v_report.id, v_business_line_id, v_cost_center_id, v_accounting_account_id, (v_item ->> 'expense_date')::date, nullif(btrim(v_item ->> 'supplier_name'), ''), v_document_type_id, nullif(btrim(v_item ->> 'document_number'), ''), (v_item ->> 'total_amount')::numeric, nullif(btrim(v_item ->> 'description'), ''), nullif(btrim(v_item ->> 'additional_notes'), '') ); END LOOP; RETURN v_report; END; $$
"create_expense_report_item"("p_workspace_id" "uuid", "p_expense_report_id" "uuid", "p_expense_date" "date", "p_total_amount" numeric, "p_supplier_name" "text", "p_document_type_id" integer, "p_document_number" "text", "p_description" "text", "p_business_line_id" "uuid", "p_cost_center_id" "uuid", "p_accounting_account_id" "uuid", "p_additional_notes" "text") RETURNS "tuasesor"."expense_report_items" LANGUAGE "plpgsql" SET "search_path" TO 'pg_catalog', 'tuasesor' AS $$ DECLARE v_report tuasesor.expense_reports; v_item tuasesor.expense_report_items; BEGIN IF auth.uid() IS NULL THEN RAISE EXCEPTION 'Authentication is required' USING ERRCODE = '42501'; END IF; IF p_workspace_id IS NULL OR p_expense_report_id IS NULL THEN RAISE EXCEPTION 'Workspace and expense report are required' USING ERRCODE = '22023'; END IF; SELECT expense_report.* INTO v_report FROM tuasesor.expense_reports AS expense_report WHERE expense_report.id = p_expense_report_id AND expense_report.workspace_id = p_workspace_id; IF NOT FOUND THEN RAISE EXCEPTION 'Expense report was not found' USING ERRCODE = 'P0002'; END IF; IF NOT tuasesor.can_write_workspace(p_workspace_id) THEN RAISE EXCEPTION 'Not authorized to write in this workspace' USING ERRCODE = '42501'; END IF; IF v_report.status <> 'draft' THEN RAISE EXCEPTION 'Expense report is not editable' USING ERRCODE = '55000'; END IF; IF p_expense_date IS NULL THEN RAISE EXCEPTION 'expense_date is required' USING ERRCODE = '22023'; END IF; IF p_total_amount IS NULL OR p_total_amount <= 0 OR p_total_amount > 999999999999.99 OR p_total_amount <> round(p_total_amount, 2) THEN RAISE EXCEPTION 'total_amount is invalid' USING ERRCODE = '22023'; END IF; IF p_business_line_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tuasesor.business_lines AS business_line WHERE business_line.id = p_business_line_id AND business_line.workspace_id = p_workspace_id ) THEN RAISE EXCEPTION 'Business line does not belong to the workspace' USING ERRCODE = '23503'; END IF; IF p_cost_center_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tuasesor.cost_centers AS cost_center WHERE cost_center.id = p_cost_center_id AND cost_center.workspace_id = p_workspace_id ) THEN RAISE EXCEPTION 'Cost center does not belong to the workspace' USING ERRCODE = '23503'; END IF; IF p_accounting_account_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tuasesor.accounting_accounts AS accounting_account WHERE accounting_account.id = p_accounting_account_id AND accounting_account.workspace_id = p_workspace_id ) THEN RAISE EXCEPTION 'Accounting account does not belong to the workspace' USING ERRCODE = '23503'; END IF; IF p_document_type_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tuasesor.document_types AS document_type WHERE document_type.id = p_document_type_id ) THEN RAISE EXCEPTION 'Document type does not exist' USING ERRCODE = '23503'; END IF; INSERT INTO tuasesor.expense_report_items ( expense_report_id, business_line_id, cost_center_id, accounting_account_id, expense_date, supplier_name, document_type_id, document_number, total_amount, description, additional_notes ) VALUES ( p_expense_report_id, p_business_line_id, p_cost_center_id, p_accounting_account_id, p_expense_date, nullif(btrim(p_supplier_name), ''), p_document_type_id, nullif(btrim(p_document_number), ''), p_total_amount, nullif(btrim(p_description), ''), nullif(btrim(p_additional_notes), '') ) RETURNING * INTO v_item; RETURN v_item; END; $$
"delete_expense_report_item"("p_workspace_id" "uuid", "p_expense_report_id" "uuid", "p_item_id" "uuid") RETURNS "uuid" LANGUAGE "plpgsql" SET "search_path" TO 'pg_catalog', 'tuasesor' AS $$ DECLARE v_report tuasesor.expense_reports; v_deleted_item_id uuid; BEGIN IF auth.uid() IS NULL THEN RAISE EXCEPTION 'Authentication is required' USING ERRCODE = '42501'; END IF; IF p_workspace_id IS NULL OR p_expense_report_id IS NULL OR p_item_id IS NULL THEN RAISE EXCEPTION 'Workspace, expense report and item are required' USING ERRCODE = '22023'; END IF; SELECT expense_report.* INTO v_report FROM tuasesor.expense_reports AS expense_report WHERE expense_report.id = p_expense_report_id AND expense_report.workspace_id = p_workspace_id; IF NOT FOUND THEN RAISE EXCEPTION 'Expense report was not found' USING ERRCODE = 'P0002'; END IF; IF NOT tuasesor.can_write_workspace(p_workspace_id) THEN RAISE EXCEPTION 'Not authorized to write in this workspace' USING ERRCODE = '42501'; END IF; IF v_report.status <> 'draft' THEN RAISE EXCEPTION 'Expense report is not editable' USING ERRCODE = '55000'; END IF; DELETE FROM tuasesor.expense_report_items WHERE id = p_item_id AND expense_report_id = p_expense_report_id RETURNING id INTO v_deleted_item_id; IF NOT FOUND THEN RAISE EXCEPTION 'Expense report item was not found' USING ERRCODE = 'P0002'; END IF; RETURN v_deleted_item_id; END; $$
"handle_auth_user_created"() RETURNS "trigger" LANGUAGE "plpgsql" SECURITY DEFINER SET "search_path" TO 'public' AS $$ DECLARE resolved_full_name text; resolved_avatar_url text; resolved_auth_metadata jsonb; BEGIN IF new.email IS NULL OR btrim(new.email) = '' THEN RAISE EXCEPTION 'Cannot synchronize auth user % without an email address', new.id; END IF; resolved_full_name := coalesce( nullif(new.raw_user_meta_data ->> 'full_name', ''), nullif(new.raw_user_meta_data ->> 'name', '') ); resolved_avatar_url := coalesce( nullif(new.raw_user_meta_data ->> 'avatar_url', ''), nullif(new.raw_user_meta_data ->> 'picture', '') ); resolved_auth_metadata := jsonb_build_object( 'auth', jsonb_build_object( 'provider', new.raw_app_meta_data ->> 'provider', 'providers', coalesce( new.raw_app_meta_data -> 'providers', '[]'::jsonb ), 'provider_id', new.raw_user_meta_data ->> 'provider_id', 'email_verified', coalesce( (new.raw_user_meta_data ->> 'email_verified')::boolean, false ) ) ); INSERT INTO tuasesor.profiles ( id, email, full_name, avatar_url, metadata_json ) VALUES ( new.id, new.email, resolved_full_name, resolved_avatar_url, resolved_auth_metadata ) ON CONFLICT (id) DO UPDATE SET email = excluded.email, full_name = coalesce( excluded.full_name, tuasesor.profiles.full_name ), avatar_url = coalesce( excluded.avatar_url, tuasesor.profiles.avatar_url ), metadata_json = coalesce(tuasesor.profiles.metadata_json, '{}'::jsonb) \|\| excluded.metadata_json, updated_at = now(); RETURN new; END; $$
"prevent_expense_report_item_parent_change"() RETURNS "trigger" LANGUAGE "plpgsql" SET "search_path" TO 'pg_catalog', 'tuasesor' AS $$ BEGIN IF NEW.expense_report_id IS DISTINCT FROM OLD.expense_report_id THEN RAISE EXCEPTION 'expense_report_id cannot be changed' USING ERRCODE = '22023'; END IF; RETURN NEW; END; $$
"update_expense_report_item"("p_workspace_id" "uuid", "p_expense_report_id" "uuid", "p_item_id" "uuid", "p_expense_date" "date", "p_total_amount" numeric, "p_supplier_name" "text", "p_document_type_id" integer, "p_document_number" "text", "p_description" "text", "p_business_line_id" "uuid", "p_cost_center_id" "uuid", "p_accounting_account_id" "uuid", "p_additional_notes" "text") RETURNS "tuasesor"."expense_report_items" LANGUAGE "plpgsql" SET "search_path" TO 'pg_catalog', 'tuasesor' AS $$ DECLARE v_report tuasesor.expense_reports; v_item tuasesor.expense_report_items; BEGIN IF auth.uid() IS NULL THEN RAISE EXCEPTION 'Authentication is required' USING ERRCODE = '42501'; END IF; IF p_workspace_id IS NULL OR p_expense_report_id IS NULL OR p_item_id IS NULL THEN RAISE EXCEPTION 'Workspace, expense report and item are required' USING ERRCODE = '22023'; END IF; SELECT expense_report.* INTO v_report FROM tuasesor.expense_reports AS expense_report WHERE expense_report.id = p_expense_report_id AND expense_report.workspace_id = p_workspace_id; IF NOT FOUND THEN RAISE EXCEPTION 'Expense report was not found' USING ERRCODE = 'P0002'; END IF; IF NOT tuasesor.can_write_workspace(p_workspace_id) THEN RAISE EXCEPTION 'Not authorized to write in this workspace' USING ERRCODE = '42501'; END IF; IF v_report.status <> 'draft' THEN RAISE EXCEPTION 'Expense report is not editable' USING ERRCODE = '55000'; END IF; IF p_expense_date IS NULL THEN RAISE EXCEPTION 'expense_date is required' USING ERRCODE = '22023'; END IF; IF p_total_amount IS NULL OR p_total_amount <= 0 OR p_total_amount > 999999999999.99 OR p_total_amount <> round(p_total_amount, 2) THEN RAISE EXCEPTION 'total_amount is invalid' USING ERRCODE = '22023'; END IF; IF p_business_line_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tuasesor.business_lines AS business_line WHERE business_line.id = p_business_line_id AND business_line.workspace_id = p_workspace_id ) THEN RAISE EXCEPTION 'Business line does not belong to the workspace' USING ERRCODE = '23503'; END IF; IF p_cost_center_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tuasesor.cost_centers AS cost_center WHERE cost_center.id = p_cost_center_id AND cost_center.workspace_id = p_workspace_id ) THEN RAISE EXCEPTION 'Cost center does not belong to the workspace' USING ERRCODE = '23503'; END IF; IF p_accounting_account_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tuasesor.accounting_accounts AS accounting_account WHERE accounting_account.id = p_accounting_account_id AND accounting_account.workspace_id = p_workspace_id ) THEN RAISE EXCEPTION 'Accounting account does not belong to the workspace' USING ERRCODE = '23503'; END IF; IF p_document_type_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tuasesor.document_types AS document_type WHERE document_type.id = p_document_type_id ) THEN RAISE EXCEPTION 'Document type does not exist' USING ERRCODE = '23503'; END IF; UPDATE tuasesor.expense_report_items SET business_line_id = p_business_line_id, cost_center_id = p_cost_center_id, accounting_account_id = p_accounting_account_id, expense_date = p_expense_date, supplier_name = nullif(btrim(p_supplier_name), ''), document_type_id = p_document_type_id, document_number = nullif(btrim(p_document_number), ''), total_amount = p_total_amount, description = nullif(btrim(p_description), ''), additional_notes = nullif(btrim(p_additional_notes), '') WHERE id = p_item_id AND expense_report_id = p_expense_report_id RETURNING * INTO v_item; IF NOT FOUND THEN RAISE EXCEPTION 'Expense report item was not found' USING ERRCODE = 'P0002'; END IF; RETURN v_item; END; $$
"validate_expense_report_item_catalogs"() RETURNS "trigger" LANGUAGE "plpgsql" SET "search_path" TO 'pg_catalog', 'tuasesor' AS $$ DECLARE v_workspace_id uuid; BEGIN SELECT expense_report.workspace_id INTO v_workspace_id FROM tuasesor.expense_reports AS expense_report WHERE expense_report.id = NEW.expense_report_id; IF NOT FOUND THEN RAISE EXCEPTION 'Expense report was not found' USING ERRCODE = '23503'; END IF; IF NEW.business_line_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tuasesor.business_lines AS business_line WHERE business_line.id = NEW.business_line_id AND business_line.workspace_id = v_workspace_id ) THEN RAISE EXCEPTION 'Business line does not belong to the expense report workspace' USING ERRCODE = '23503'; END IF; IF NEW.cost_center_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tuasesor.cost_centers AS cost_center WHERE cost_center.id = NEW.cost_center_id AND cost_center.workspace_id = v_workspace_id ) THEN RAISE EXCEPTION 'Cost center does not belong to the expense report workspace' USING ERRCODE = '23503'; END IF; IF NEW.accounting_account_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tuasesor.accounting_accounts AS accounting_account WHERE accounting_account.id = NEW.accounting_account_id AND accounting_account.workspace_id = v_workspace_id ) THEN RAISE EXCEPTION 'Accounting account does not belong to the expense report workspace' USING ERRCODE = '23503'; END IF; IF NEW.document_type_id IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM tuasesor.document_types AS document_type WHERE document_type.id = NEW.document_type_id ) THEN RAISE EXCEPTION 'Document type does not exist' USING ERRCODE = '23503'; END IF; RETURN NEW; END; $$
Schema grants
USAGE ON SCHEMA "tuasesor" TO "anon"
USAGE ON SCHEMA "tuasesor" TO "authenticated"
USAGE ON SCHEMA "tuasesor" TO "service_role"