-- Формы и заявки, редиректы со старых адресов, пользователи админки. CREATE TABLE forms ( id bigserial PRIMARY KEY, code text NOT NULL UNIQUE, -- appointment | callback | service_order | review | resume title text NOT NULL, success_text text NOT NULL DEFAULT '', recipients jsonb NOT NULL DEFAULT '[]'::jsonb, -- куда слать уведомления published boolean NOT NULL DEFAULT true ); CREATE TABLE form_fields ( id bigserial PRIMARY KEY, form_id bigint NOT NULL REFERENCES forms (id) ON DELETE CASCADE, code text NOT NULL, label text NOT NULL, type text NOT NULL DEFAULT 'text' CHECK (type IN ('text', 'textarea', 'phone', 'email', 'date', 'select', 'service', 'doctor', 'rating', 'file')), required boolean NOT NULL DEFAULT false, options jsonb NOT NULL DEFAULT '[]'::jsonb, sort int NOT NULL DEFAULT 100, UNIQUE (form_id, code) ); CREATE TABLE leads ( id bigserial PRIMARY KEY, form_id bigint REFERENCES forms (id) ON DELETE SET NULL, -- разобранные поля, по которым строится поиск и статистика name text NOT NULL DEFAULT '', phone text NOT NULL DEFAULT '', email text NOT NULL DEFAULT '', service_id bigint REFERENCES services (id) ON DELETE SET NULL, doctor_id bigint REFERENCES doctors (id) ON DELETE SET NULL, branch_id bigint REFERENCES branches (id) ON DELETE SET NULL, message text NOT NULL DEFAULT '', -- остальные поля формы как есть payload jsonb NOT NULL DEFAULT '{}'::jsonb, status text NOT NULL DEFAULT 'new' CHECK (status IN ('new', 'in_progress', 'done', 'spam')), comment text NOT NULL DEFAULT '', page_url text NOT NULL DEFAULT '', utm jsonb NOT NULL DEFAULT '{}'::jsonb, ip inet, user_agent text NOT NULL DEFAULT '', -- согласие на обработку персональных данных фиксируется явно consent_at timestamptz NOT NULL, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now() ); CREATE INDEX leads_created_idx ON leads (created_at DESC); CREATE INDEX leads_status_idx ON leads (status, created_at DESC); CREATE INDEX leads_phone_idx ON leads (phone); -- Старые адреса Bitrix, чтобы не потерять позиции в поиске. CREATE TABLE redirects ( id bigserial PRIMARY KEY, from_path text NOT NULL UNIQUE, to_path text NOT NULL, code int NOT NULL DEFAULT 301 CHECK (code IN (301, 302)), hits bigint NOT NULL DEFAULT 0, created_at timestamptz NOT NULL DEFAULT now() ); -- Журнал ненайденных адресов: подсказывает, какие редиректы ещё нужны. CREATE TABLE not_found_log ( path text PRIMARY KEY, hits bigint NOT NULL DEFAULT 1, last_seen timestamptz NOT NULL DEFAULT now(), referer text NOT NULL DEFAULT '' ); CREATE TABLE admin_users ( id bigserial PRIMARY KEY, email text NOT NULL UNIQUE, password_hash text NOT NULL, name text NOT NULL DEFAULT '', role text NOT NULL DEFAULT 'editor' CHECK (role IN ('owner', 'admin', 'editor', 'registrar')), active boolean NOT NULL DEFAULT true, last_login_at timestamptz, created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE admin_sessions ( token text PRIMARY KEY, user_id bigint NOT NULL REFERENCES admin_users (id) ON DELETE CASCADE, expires_at timestamptz NOT NULL, ip inet, user_agent text NOT NULL DEFAULT '', created_at timestamptz NOT NULL DEFAULT now() ); CREATE INDEX admin_sessions_user_idx ON admin_sessions (user_id); -- Кто что менял: нужно и для разбора ошибок, и по требованиям к медданным. CREATE TABLE audit_log ( id bigserial PRIMARY KEY, user_id bigint REFERENCES admin_users (id) ON DELETE SET NULL, action text NOT NULL, -- create | update | delete | login | view_leads entity text NOT NULL DEFAULT '', entity_id bigint, diff jsonb NOT NULL DEFAULT '{}'::jsonb, ip inet, created_at timestamptz NOT NULL DEFAULT now() ); CREATE INDEX audit_log_created_idx ON audit_log (created_at DESC);