-- Keep raw casing on usernames at signup. -- -- `profiles.username` is already `citext` so unique + lookup checks are -- case-insensitive regardless of stored casing. Previously the signup -- trigger force-lowercased via `lower(trim(...))`, losing the user's -- preferred display case. Drop the lower(), widen the validation regex to -- accept A-Z, keep trim() + uniqueness semantics. create or replace function public.handle_new_user() returns trigger language plpgsql security definer set search_path = public as $$ declare v_invite_code text; v_username text; v_display_name text; v_locale text; v_invite public.invites%rowtype; begin v_invite_code := new.raw_user_meta_data->>'invite_code'; v_username := trim(new.raw_user_meta_data->>'username'); v_display_name := nullif(trim(new.raw_user_meta_data->>'display_name'), ''); v_locale := lower(trim(new.raw_user_meta_data->>'locale')); if v_display_name is null then v_display_name := v_username; end if; if v_locale is null or v_locale not in ('en', 'de') then v_locale := 'en'; end if; if v_invite_code is null or length(v_invite_code) = 0 then raise exception 'ERR_INVITE_CODE_REQUIRED'; end if; if v_username is null or v_username !~ '^[A-Za-z0-9_]{3,32}$' then raise exception 'ERR_USERNAME_INVALID'; end if; if not coalesce((select (value)::boolean from public.admin_settings where key = 'invites_enabled'), true) then raise exception 'ERR_INVITES_DISABLED'; end if; select * into v_invite from public.invites where code = v_invite_code for update; if not found then raise exception 'ERR_INVITE_NOT_FOUND'; end if; if v_invite.disabled then raise exception 'ERR_INVITE_DISABLED'; end if; if v_invite.expires_at is not null and v_invite.expires_at < now() then raise exception 'ERR_INVITE_EXPIRED'; end if; if v_invite.uses_limit is not null and v_invite.uses_count >= v_invite.uses_limit then raise exception 'ERR_INVITE_EXHAUSTED'; end if; update public.invites set uses_count = uses_count + 1 where code = v_invite.code; insert into public.profiles (user_id, username, display_name, locale) values (new.id, v_username, v_display_name, v_locale); return new; end; $$;