Initial state for GitNexus analysis

This commit is contained in:
Zaid Marzguioui
2026-03-29 19:44:57 +02:00
parent 9d7c7f8030
commit 61ff48cb73
155 changed files with 23483 additions and 1722 deletions

View File

@@ -0,0 +1,211 @@
/*
* -------------------------------------------------------
* Member Management Schema
* Phase 4: members, membership_applications, dues_categories, member_cards
* -------------------------------------------------------
*/
-- =====================================================
-- 1. Enums
-- =====================================================
create type public.membership_status as enum(
'active', 'inactive', 'pending', 'resigned', 'excluded', 'deceased'
);
create type public.sepa_mandate_status as enum(
'active', 'pending', 'revoked', 'expired'
);
create type public.application_status as enum(
'submitted', 'review', 'approved', 'rejected'
);
-- =====================================================
-- 2. members
-- =====================================================
create table if not exists public.members (
id uuid primary key default gen_random_uuid(),
account_id uuid not null references public.accounts(id) on delete cascade,
member_number text,
-- Personal
first_name text not null,
last_name text not null,
date_of_birth date,
gender text check (gender in ('male', 'female', 'diverse', null)),
title text, -- Dr., Prof., etc.
-- Contact
email text,
phone text,
mobile text,
-- Address
street text,
house_number text,
postal_code text,
city text,
country text default 'DE',
-- Membership
status public.membership_status not null default 'active',
entry_date date not null default current_date,
exit_date date,
exit_reason text,
dues_category_id uuid,
-- SEPA
sepa_mandate_id text,
sepa_mandate_date date,
sepa_mandate_status public.sepa_mandate_status default 'pending',
iban text,
bic text,
account_holder text,
-- GDPR
gdpr_consent boolean not null default false,
gdpr_consent_date timestamptz,
gdpr_data_source text,
-- Meta
notes text,
custom_data jsonb not null default '{}'::jsonb,
created_by uuid references auth.users(id) on delete set null,
updated_by uuid references auth.users(id) on delete set null,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
unique(account_id, member_number)
);
comment on table public.members is 'Club/association members — replaces legacy ve_mitglieder';
create index ix_members_account on public.members(account_id);
create index ix_members_status on public.members(account_id, status);
create index ix_members_name on public.members(account_id, last_name, first_name);
create index ix_members_email on public.members(account_id, email);
alter table public.members enable row level security;
revoke all on public.members from authenticated, service_role;
grant select, insert, update, delete on public.members to authenticated;
grant all on public.members to service_role;
create policy members_select on public.members for select to authenticated
using (public.has_role_on_account(account_id));
create policy members_insert on public.members for insert to authenticated
with check (public.has_permission(auth.uid(), account_id, 'members.write'::public.app_permissions));
create policy members_update on public.members for update to authenticated
using (public.has_permission(auth.uid(), account_id, 'members.write'::public.app_permissions));
create policy members_delete on public.members for delete to authenticated
using (public.has_permission(auth.uid(), account_id, 'members.write'::public.app_permissions));
create trigger trg_members_updated_at
before update on public.members
for each row execute function public.update_account_settings_timestamp();
-- =====================================================
-- 3. dues_categories — tiered pricing
-- =====================================================
create table if not exists public.dues_categories (
id uuid primary key default gen_random_uuid(),
account_id uuid not null references public.accounts(id) on delete cascade,
name text not null,
description text,
amount numeric(10,2) not null default 0,
interval text not null default 'yearly' check (interval in ('monthly', 'quarterly', 'half_yearly', 'yearly')),
is_default boolean not null default false,
sort_order integer not null default 0,
created_at timestamptz not null default now()
);
comment on table public.dues_categories is 'Membership dues/fee categories';
create index ix_dues_categories_account on public.dues_categories(account_id);
alter table public.dues_categories enable row level security;
revoke all on public.dues_categories from authenticated, service_role;
grant select, insert, update, delete on public.dues_categories to authenticated;
grant all on public.dues_categories to service_role;
create policy dues_categories_select on public.dues_categories for select to authenticated
using (public.has_role_on_account(account_id));
create policy dues_categories_mutate on public.dues_categories for all to authenticated
using (public.has_permission(auth.uid(), account_id, 'members.write'::public.app_permissions));
-- Add FK from members to dues_categories
alter table public.members
add constraint fk_members_dues_category
foreign key (dues_category_id) references public.dues_categories(id) on delete set null;
-- =====================================================
-- 4. membership_applications — workflow
-- =====================================================
create table if not exists public.membership_applications (
id uuid primary key default gen_random_uuid(),
account_id uuid not null references public.accounts(id) on delete cascade,
first_name text not null,
last_name text not null,
email text,
phone text,
street text,
postal_code text,
city text,
date_of_birth date,
message text,
status public.application_status not null default 'submitted',
reviewed_by uuid references auth.users(id) on delete set null,
reviewed_at timestamptz,
review_notes text,
member_id uuid references public.members(id) on delete set null,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
comment on table public.membership_applications is 'Online membership applications with approval workflow';
create index ix_applications_account on public.membership_applications(account_id);
create index ix_applications_status on public.membership_applications(account_id, status);
alter table public.membership_applications enable row level security;
revoke all on public.membership_applications from authenticated, service_role;
grant select, insert, update, delete on public.membership_applications to authenticated;
grant all on public.membership_applications to service_role;
create policy applications_select on public.membership_applications for select to authenticated
using (public.has_role_on_account(account_id));
create policy applications_mutate on public.membership_applications for all to authenticated
using (public.has_permission(auth.uid(), account_id, 'members.write'::public.app_permissions));
-- =====================================================
-- 5. member_cards — ID cards
-- =====================================================
create table if not exists public.member_cards (
id uuid primary key default gen_random_uuid(),
member_id uuid not null references public.members(id) on delete cascade,
account_id uuid not null references public.accounts(id) on delete cascade,
card_number text,
valid_from date not null default current_date,
valid_until date,
pdf_storage_path text,
created_at timestamptz not null default now()
);
comment on table public.member_cards is 'Member ID cards with generated PDFs';
create index ix_member_cards_member on public.member_cards(member_id);
alter table public.member_cards enable row level security;
revoke all on public.member_cards from authenticated, service_role;
grant select, insert, update, delete on public.member_cards to authenticated;
grant all on public.member_cards to service_role;
create policy member_cards_select on public.member_cards for select to authenticated
using (public.has_role_on_account(account_id));
create policy member_cards_mutate on public.member_cards for all to authenticated
using (public.has_permission(auth.uid(), account_id, 'members.write'::public.app_permissions));