Add page-view analytics, product counters, SSL expiry, and business renewal.
Auto-count storefront page views with 6-month event retention and lifetime counters, track product visit/cart/sale stats, persist SSL cert expiry with daily probes, and support owner titles plus annual contract renewal. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
6cd0b009ef
commit
92601ae729
@@ -0,0 +1,76 @@
|
||||
-- Expand page-view kinds, rename events table, add lifetime counters.
|
||||
-- Events retained max 6 months (purged by Nest cron). Counters kept forever.
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'website_page_kind') THEN
|
||||
CREATE TYPE website_page_kind AS ENUM (
|
||||
'home',
|
||||
'portfolio_list',
|
||||
'portfolio_detail',
|
||||
'product_list',
|
||||
'product_detail',
|
||||
'store_item_list',
|
||||
'store_item_detail',
|
||||
'blog_list',
|
||||
'blog_detail',
|
||||
'video_list',
|
||||
'video_detail'
|
||||
);
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Recreate events table with new kind enum (table is empty / low volume today).
|
||||
CREATE TABLE IF NOT EXISTS website_page_views (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
business_id BIGINT NOT NULL REFERENCES businesses (id) ON DELETE CASCADE,
|
||||
page_kind website_page_kind NOT NULL,
|
||||
entity_id BIGINT NOT NULL DEFAULT 0,
|
||||
page_path TEXT,
|
||||
viewed_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_website_page_views_business_kind_time
|
||||
ON website_page_views (business_id, page_kind, viewed_at DESC);
|
||||
|
||||
-- Copy any legacy rows from website_content_views
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.tables
|
||||
WHERE table_schema = 'public' AND table_name = 'website_content_views'
|
||||
) THEN
|
||||
INSERT INTO website_page_views (business_id, page_kind, entity_id, page_path, viewed_at)
|
||||
SELECT
|
||||
business_id,
|
||||
CASE view_kind::text
|
||||
WHEN 'website' THEN 'home'::website_page_kind
|
||||
WHEN 'product' THEN 'product_detail'::website_page_kind
|
||||
WHEN 'portfolio' THEN 'portfolio_detail'::website_page_kind
|
||||
WHEN 'blog' THEN 'blog_detail'::website_page_kind
|
||||
ELSE 'home'::website_page_kind
|
||||
END,
|
||||
COALESCE(entity_id, 0),
|
||||
page_path,
|
||||
viewed_at
|
||||
FROM website_content_views;
|
||||
|
||||
DROP TABLE website_content_views;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
DROP TYPE IF EXISTS website_view_kind;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS website_page_view_counters (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
business_id BIGINT NOT NULL REFERENCES businesses (id) ON DELETE CASCADE,
|
||||
page_kind website_page_kind NOT NULL,
|
||||
entity_id BIGINT NOT NULL DEFAULT 0,
|
||||
total_count BIGINT NOT NULL DEFAULT 0,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
CONSTRAINT uq_website_page_view_counters_biz_kind_entity
|
||||
UNIQUE (business_id, page_kind, entity_id)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_website_page_view_counters_business_kind
|
||||
ON website_page_view_counters (business_id, page_kind);
|
||||
@@ -0,0 +1,5 @@
|
||||
-- Lifetime product analysis counters (visits, cart adds, units sold).
|
||||
ALTER TABLE products
|
||||
ADD COLUMN IF NOT EXISTS visit_count BIGINT NOT NULL DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS cart_add_count BIGINT NOT NULL DEFAULT 0,
|
||||
ADD COLUMN IF NOT EXISTS sale_count BIGINT NOT NULL DEFAULT 0;
|
||||
@@ -0,0 +1,8 @@
|
||||
-- Store Let's Encrypt / TLS notAfter after a successful SSL issue.
|
||||
-- List Valid/Invalid prefers this date; live probes run at most once per day.
|
||||
ALTER TABLE domains
|
||||
ADD COLUMN IF NOT EXISTS ssl_expires_at TIMESTAMPTZ;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_domains_ssl_expires_at
|
||||
ON domains (ssl_expires_at)
|
||||
WHERE ssl_expires_at IS NOT NULL;
|
||||
@@ -0,0 +1,32 @@
|
||||
-- Business annual renewal date + user honorific titles.
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_titles (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
slug VARCHAR(32) NOT NULL,
|
||||
name_en VARCHAR(64) NOT NULL,
|
||||
name_fa VARCHAR(64) NOT NULL,
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
CONSTRAINT user_titles_slug_unique UNIQUE (slug)
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_user_titles_sort
|
||||
ON user_titles (sort_order, id);
|
||||
|
||||
INSERT INTO user_titles (slug, name_en, name_fa, sort_order)
|
||||
VALUES
|
||||
('mr', 'Mr', 'آقای', 10),
|
||||
('mrs', 'Mrs', 'خانم', 20),
|
||||
('ms', 'Ms', 'خانم', 30),
|
||||
('dr', 'Dr', 'دکتر', 40),
|
||||
('eng', 'Eng.', 'مهندس', 50)
|
||||
ON CONFLICT (slug) DO NOTHING;
|
||||
|
||||
ALTER TABLE users
|
||||
ADD COLUMN IF NOT EXISTS title_id BIGINT REFERENCES user_titles (id) ON DELETE SET NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_users_title_id ON users (title_id);
|
||||
|
||||
ALTER TABLE businesses
|
||||
ADD COLUMN IF NOT EXISTS annual_renewal_at TIMESTAMPTZ;
|
||||
Reference in New Issue
Block a user