guardia-mall/backend/src/main/resources/db/schema.sql

802 lines
74 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- ============================================================================
-- GUARDiA Mall — PostgreSQL 스키마 (mall_db)
-- 미국 다지점 꽃집 옴니채널 e-커머스
-- 매장·ZIP배송권역·매장별재고ON/OFF·상품/3사이즈/옵션·장바구니·주문·스케줄링/타임슬롯·
-- 당일배송·구독·서지프라이싱·배송/기사라우팅·매장간재고이양·리뷰·회원·CS·분석·찜
-- 모든 테이블 IF NOT EXISTS, 시드는 ON CONFLICT DO NOTHING (멱등).
-- ============================================================================
-- ---------------------------------------------------------------------------
-- 0. 공통 (인증/감사/설정/AI)
-- ---------------------------------------------------------------------------
-- 인증/관리자 계정 (auth UserMapper + admin AdminUserMapper 가 사용하는 테이블)
CREATE TABLE IF NOT EXISTS mall_account (
id BIGSERIAL PRIMARY KEY, username VARCHAR(200) UNIQUE NOT NULL, password_hash VARCHAR(500) NOT NULL,
role VARCHAR(50) DEFAULT 'USER', display_name VARCHAR(200),
store_id BIGINT, -- StoreManager 배정 매장 (SuperAdmin=NULL)
is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT NOW()
);
-- 시드 비밀번호 = admin123 (bcrypt $2a$10)
INSERT INTO mall_account (username, password_hash, role, display_name, store_id) VALUES
('admin', '$2a$10$Uo4GFiJ2TZy9KlGRALfDt.gcE0e7..57rXBRaEv1mJG2XqANG3OI2', 'ADMIN', 'Super Admin (대표)', NULL),
('manager', '$2a$10$Uo4GFiJ2TZy9KlGRALfDt.gcE0e7..57rXBRaEv1mJG2XqANG3OI2', 'MANAGER', 'Store Manager (1호점)', 1),
('jane', '$2a$10$Uo4GFiJ2TZy9KlGRALfDt.gcE0e7..57rXBRaEv1mJG2XqANG3OI2', 'USER', 'Jane Doe', NULL)
ON CONFLICT (username) DO NOTHING;
CREATE TABLE IF NOT EXISTS mall_audit_log (
id BIGSERIAL PRIMARY KEY, actor VARCHAR(200), action VARCHAR(100), target VARCHAR(300), detail TEXT, created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_mall_audit_action ON mall_audit_log(action);
CREATE TABLE IF NOT EXISTS mall_setting (key VARCHAR(200) PRIMARY KEY, value TEXT, updated_at TIMESTAMP DEFAULT NOW());
INSERT INTO mall_setting (key, value) VALUES
('ollama_text_model','llama3'),
('company_name','Montvale Florist'),
('company_tagline','100% Florist-Designed and Hand-Delivered!'),
('company_address','6 Railroad Ave, Montvale, NJ 07645'),
('company_phone','(201) 690-6721'),
('company_email','wecare@montvalefloristnj.com'),
('company_founded','2010'),
('company_rating','4.9'),
('company_review_count','44893'),
('social_instagram','@themontvaleflorist'),
('social_facebook','montvaleflorist1'),
('social_pinterest','montvaleflorist'),
('social_yelp','montvale-florist-montvale-3'),
('hours_weekday','Mon-Fri 9:00 AM - 5:30 PM'),
('hours_saturday','Sat 9:00 AM - 4:00 PM'),
('hours_sunday','Sun 9:00 AM - 12:00 PM'),
('payment_provider','mock'),('tax_provider','mock'),('address_provider','mock'),
('sms_provider','mock'),('email_provider','mock')
ON CONFLICT (key) DO NOTHING;
CREATE TABLE IF NOT EXISTS mall_ai_result (
id BIGSERIAL PRIMARY KEY, ai_type VARCHAR(60), prompt TEXT, result_json TEXT, model VARCHAR(60),
created_by VARCHAR(200), created_at TIMESTAMP DEFAULT NOW()
);
-- ---------------------------------------------------------------------------
-- 1. 매장 (Stores) — 10+ 미국 매장
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS mall_store (
id BIGSERIAL PRIMARY KEY, code VARCHAR(40) UNIQUE NOT NULL, name VARCHAR(200) NOT NULL,
city VARCHAR(120), state VARCHAR(10), zip VARCHAR(10), address VARCHAR(400),
phone VARCHAR(40), timezone VARCHAR(60) DEFAULT 'America/New_York',
open_time VARCHAR(10) DEFAULT '09:00', close_time VARCHAR(10) DEFAULT '18:00',
same_day_cutoff VARCHAR(10) DEFAULT '12:00', -- 당일배송 마감 (매장 로컬타임)
delivery_radius_mi NUMERIC(6,2) DEFAULT 15.0, -- 배송 반경(마일)
daily_capacity INTEGER DEFAULT 50, -- 일일 처리 용량(주문수)
lat NUMERIC(10,6), lng NUMERIC(10,6),
active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP DEFAULT NOW()
);
-- 실데이터: Montvale Florist = 플래그십 1호점(id=1). 나머지는 트라이스테이트 확장 매장.
-- Montvale 운영시간/마감(당일배송): 월-금 9:00-17:30(마감 13:00=2PM 사이트표기 기준 보수적 1PM), 토 9:00-16:00(마감 12:00), 일 9:00-12:00(마감 10:00)
-- (id 명시: manager 계정 store_id=1 정합)
INSERT INTO mall_store (id, code, name, city, state, zip, address, phone, timezone, open_time, close_time, same_day_cutoff, delivery_radius_mi, daily_capacity, lat, lng) VALUES
(1,'MONTVALE','Montvale Florist','Montvale','NJ','07645','6 Railroad Ave','+1-201-690-6721','America/New_York','09:00','17:30','13:00',15.0,80,41.040800,-74.029900),
(2,'HACKENSACK','Montvale Florist — Hackensack','Hackensack','NJ','07601','120 Main St','+1-201-555-0102','America/New_York','09:00','17:30','13:00',12.0,60,40.885900,-74.043400),
(3,'PARAMUS','Montvale Florist — Paramus','Paramus','NJ','07652','201 Bergen Town Ctr','+1-201-555-0103','America/New_York','09:00','17:30','13:00',14.0,55,40.944500,-74.071500),
(4,'FORTLEE','Montvale Florist — Fort Lee','Fort Lee','NJ','07024','1605 Center Ave','+1-201-555-0104','America/New_York','09:00','17:30','13:00',12.0,50,40.850800,-73.970900),
(5,'ENGLEWOOD','Montvale Florist — Englewood','Englewood','NJ','07631','25 N Dean St','+1-201-555-0105','America/New_York','09:00','17:30','13:00',13.0,45,40.892900,-73.972700),
(6,'RIDGEWOOD','Montvale Florist — Ridgewood','Ridgewood','NJ','07450','10 E Ridgewood Ave','+1-201-555-0106','America/New_York','09:00','17:30','13:00',13.0,45,40.979500,-74.116600),
(7,'FAIRLAWN','Montvale Florist — Fair Lawn','Fair Lawn','NJ','07410','22-15 Broadway','+1-201-555-0107','America/New_York','09:00','17:30','13:00',12.0,40,40.940300,-74.131500),
(8,'TEANECK','Montvale Florist — Teaneck','Teaneck','NJ','07666','100 Cedar Ln','+1-201-555-0108','America/New_York','09:00','17:30','13:00',12.0,40,40.897700,-74.016000),
(9,'GARFIELD','Montvale Florist — Garfield','Garfield','NJ','07026','50 Outwater Ln','+1-973-555-0109','America/New_York','09:00','17:30','13:00',11.0,35,40.881400,-74.108500),
(10,'NYACK','Montvale Florist — Nyack (NY)','Nyack','NY','10960','30 S Broadway','+1-845-555-0110','America/New_York','09:00','17:30','13:00',14.0,40,41.090900,-73.917800),
(11,'NANUET','Montvale Florist — Nanuet (NY)','Nanuet','NY','10954','75 W Route 59','+1-845-555-0111','America/New_York','09:00','17:30','13:00',15.0,35,41.088600,-74.013700)
ON CONFLICT (code) DO NOTHING;
SELECT setval(pg_get_serial_sequence('mall_store','id'), GREATEST((SELECT MAX(id) FROM mall_store),1));
-- ---------------------------------------------------------------------------
-- 2. 배송권역 (Delivery_Zones) — ZIP → 매장 매핑
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS mall_zone (
id BIGSERIAL PRIMARY KEY, store_id BIGINT NOT NULL, zip VARCHAR(10) NOT NULL,
city VARCHAR(120), state VARCHAR(10), radius_mi NUMERIC(6,2) DEFAULT 15.0,
surge_eligible BOOLEAN DEFAULT TRUE, active BOOLEAN DEFAULT TRUE
);
CREATE INDEX IF NOT EXISTS idx_mall_zone_zip ON mall_zone(zip);
-- 실데이터: Montvale Florist 무료배송 권역 (NJ 0701007699, NY 1052010994)
-- 대표 ZIP을 플래그십(1) + 트라이스테이트 확장 매장에 매핑. surge 기본 ON.
INSERT INTO mall_zone (store_id, zip, city, state, radius_mi) VALUES
-- 플래그십 Montvale & 인근 (Bergen County core)
(1,'07645','Montvale','NJ',15.0),(1,'07677','Woodcliff Lake','NJ',15.0),(1,'07675','Westwood','NJ',15.0),
(1,'07656','Park Ridge','NJ',15.0),(1,'07647','Northvale','NJ',15.0),(1,'07648','Norwood','NJ',15.0),
(1,'07646','New Milford','NJ',15.0),(1,'07627','Demarest','NJ',15.0),(1,'07620','Alpine','NJ',15.0),
-- Hackensack
(2,'07601','Hackensack','NJ',12.0),(2,'07602','Hackensack','NJ',12.0),(2,'07603','Bogota','NJ',12.0),
(2,'07606','South Hackensack','NJ',12.0),
-- Paramus
(3,'07652','Paramus','NJ',14.0),(3,'07653','Paramus','NJ',14.0),(3,'07663','Saddle Brook','NJ',14.0),
-- Fort Lee
(4,'07024','Fort Lee','NJ',12.0),(4,'07020','Edgewater','NJ',12.0),(4,'07010','Cliffside Park','NJ',12.0),
(4,'07022','Fairview','NJ',12.0),
-- Englewood
(5,'07631','Englewood','NJ',13.0),(5,'07632','Englewood Cliffs','NJ',13.0),(5,'07650','Palisades Park','NJ',13.0),
(5,'07666','Teaneck','NJ',13.0),
-- Ridgewood
(6,'07450','Ridgewood','NJ',13.0),(6,'07452','Glen Rock','NJ',13.0),(6,'07432','Midland Park','NJ',13.0),
(6,'07446','Ramsey','NJ',13.0),(6,'07401','Allendale','NJ',13.0),
-- Fair Lawn
(7,'07410','Fair Lawn','NJ',12.0),(7,'07470','Wayne','NJ',12.0),(7,'07012','Clifton','NJ',12.0),
-- Teaneck
(8,'07670','Tenafly','NJ',12.0),(8,'07621','Bergenfield','NJ',12.0),(8,'07624','Closter','NJ',12.0),
-- Garfield
(9,'07026','Garfield','NJ',11.0),(9,'07055','Passaic','NJ',11.0),(9,'07057','Wallington','NJ',11.0),
-- Nyack NY (Rockland)
(10,'10960','Nyack','NY',14.0),(10,'10994','West Nyack','NY',14.0),(10,'10989','Valley Cottage','NY',14.0),
(10,'10968','Piermont','NY',14.0),(10,'10520','Croton-on-Hudson','NY',14.0),
-- Nanuet NY (Rockland)
(11,'10954','Nanuet','NY',15.0),(11,'10901','Suffern','NY',15.0),(11,'10952','Monsey','NY',15.0),
(11,'10977','Spring Valley','NY',15.0),(11,'10956','New City','NY',15.0)
ON CONFLICT DO NOTHING;
-- ---------------------------------------------------------------------------
-- 2b. 배송지역 (Delivery Areas) — Montvale Florist 당일배송 68개 시(NJ)
-- 도시 단위(같은 당일배송 권역) + 대표 ZIP/좌표 → 최근접 매장 거리 계산 근거.
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS mall_delivery_area (
id BIGSERIAL PRIMARY KEY,
store_id BIGINT NOT NULL DEFAULT 1, -- 매핑 매장(Montvale 플래그십=1)
city VARCHAR(120) NOT NULL,
state VARCHAR(10) NOT NULL DEFAULT 'NJ',
zip VARCHAR(10), -- 대표 ZIP
lat NUMERIC(10,6), lng NUMERIC(10,6), -- 대표 좌표(시 중심)
same_day BOOLEAN DEFAULT TRUE, -- 동일(당일) 배송 표시
active BOOLEAN DEFAULT TRUE,
CONSTRAINT uq_mall_delivery_area UNIQUE (city, state)
);
CREATE INDEX IF NOT EXISTS idx_mall_delivery_area_city ON mall_delivery_area(city);
CREATE INDEX IF NOT EXISTS idx_mall_delivery_area_zip ON mall_delivery_area(zip);
INSERT INTO mall_delivery_area (store_id, city, state, zip, lat, lng, same_day) VALUES
(1,'Allendale','NJ','07401',41.041400,-74.129400,TRUE),(1,'Alpine','NJ','07620',40.957000,-73.930900,TRUE),
(1,'Bergenfield','NJ','07621',40.927400,-73.997400,TRUE),(1,'Bogota','NJ','07603',40.875300,-74.029600,TRUE),
(1,'Carlstadt','NJ','07072',40.840300,-74.090300,TRUE),(1,'Cliffside Park','NJ','07010',40.821300,-73.987800,TRUE),
(1,'Closter','NJ','07624',40.973100,-73.961800,TRUE),(1,'Cresskill','NJ','07626',40.941900,-73.959700,TRUE),
(1,'Demarest','NJ','07627',40.957300,-73.962800,TRUE),(1,'Dumont','NJ','07628',40.940500,-73.992700,TRUE),
(1,'East Rutherford','NJ','07073',40.836700,-74.097900,TRUE),(1,'Edgewater','NJ','07020',40.827500,-73.974700,TRUE),
(1,'Elmwood Park','NJ','07407',40.904100,-74.118500,TRUE),(1,'Emerson','NJ','07630',40.976300,-74.026900,TRUE),
(1,'Englewood Cliffs','NJ','07632',40.886000,-73.952200,TRUE),(1,'Englewood','NJ','07631',40.892900,-73.972700,TRUE),
(1,'Fair Lawn','NJ','07410',40.940300,-74.131500,TRUE),(1,'Fairview','NJ','07022',40.811900,-74.001100,TRUE),
(1,'Fort Lee','NJ','07024',40.850800,-73.970900,TRUE),(1,'Franklin Lakes','NJ','07417',41.013800,-74.207300,TRUE),
(1,'Garfield','NJ','07026',40.881400,-74.108500,TRUE),(1,'Glen Rock','NJ','07452',40.962900,-74.132900,TRUE),
(1,'Hackensack','NJ','07601',40.885900,-74.043400,TRUE),(1,'Harrington Park','NJ','07640',40.985100,-73.980200,TRUE),
(1,'Hasbrouck Heights','NJ','07604',40.858500,-74.075000,TRUE),(1,'Haworth','NJ','07641',40.960600,-73.991200,TRUE),
(1,'Hillsdale','NJ','07642',41.000200,-74.040000,TRUE),(1,'Ho-Ho-Kus','NJ','07423',40.998900,-74.103200,TRUE),
(1,'Leonia','NJ','07605',40.862400,-73.989900,TRUE),(1,'Little Ferry','NJ','07643',40.851800,-74.040400,TRUE),
(1,'Lodi','NJ','07644',40.882600,-74.083100,TRUE),(1,'Lyndhurst','NJ','07071',40.812200,-74.124200,TRUE),
(1,'Mahwah','NJ','07430',41.087400,-74.159000,TRUE),(1,'Maywood','NJ','07607',40.902000,-74.061800,TRUE),
(1,'Midland Park','NJ','07432',40.989400,-74.142200,TRUE),(1,'Millburn','NJ','07041',40.725800,-74.302900,TRUE),
(1,'Montvale','NJ','07645',41.040800,-74.029900,TRUE),(1,'Moonachie','NJ','07074',40.842500,-74.046500,TRUE),
(1,'New Milford','NJ','07646',40.934700,-74.019100,TRUE),(1,'North Arlington','NJ','07031',40.788400,-74.133400,TRUE),
(1,'Northvale','NJ','07647',41.007400,-73.948300,TRUE),(1,'Norwood','NJ','07648',40.994400,-73.958800,TRUE),
(1,'Oakland','NJ','07436',41.029900,-74.265400,TRUE),(1,'Oradell','NJ','07649',40.955700,-74.034000,TRUE),
(1,'Palisades Park','NJ','07650',40.848200,-73.997300,TRUE),(1,'Paramus','NJ','07652',40.944500,-74.071500,TRUE),
(1,'Park Ridge','NJ','07656',41.038200,-74.041700,TRUE),(1,'Ramsey','NJ','07446',41.057300,-74.141100,TRUE),
(1,'Ridgefield Park','NJ','07660',40.857200,-74.022600,TRUE),(1,'Ridgefield','NJ','07657',40.832800,-74.001500,TRUE),
(1,'Ridgewood','NJ','07450',40.979500,-74.116600,TRUE),(1,'River Edge','NJ','07661',40.927300,-74.039600,TRUE),
(1,'Rochelle Park','NJ','07662',40.906900,-74.077800,TRUE),(1,'Rutherford','NJ','07070',40.826600,-74.106500,TRUE),
(1,'Saddle Brook','NJ','07663',40.902300,-74.092700,TRUE),(1,'Saddle River','NJ','07458',41.029900,-74.099500,TRUE),
(1,'Secaucus','NJ','07094',40.789000,-74.056500,TRUE),(1,'South Hackensack','NJ','07606',40.861700,-74.050900,TRUE),
(1,'Teaneck','NJ','07666',40.897700,-74.016000,TRUE),(1,'Tenafly','NJ','07670',40.925700,-73.962900,TRUE),
(1,'Teterboro','NJ','07608',40.857800,-74.060800,TRUE),(1,'Township Of Washington','NJ','07676',40.992000,-74.063000,TRUE),
(1,'Waldwick','NJ','07463',41.012000,-74.118600,TRUE),(1,'Wallington','NJ','07057',40.853100,-74.106000,TRUE),
(1,'Westwood','NJ','07675',40.991900,-74.032900,TRUE),(1,'Wood Ridge','NJ','07075',40.844700,-74.087500,TRUE),
(1,'Woodcliff Lake','NJ','07677',41.022300,-74.062700,TRUE),(1,'Wyckoff','NJ','07481',41.009600,-74.172600,TRUE)
ON CONFLICT (city, state) DO UPDATE
SET store_id=EXCLUDED.store_id, zip=EXCLUDED.zip, lat=EXCLUDED.lat, lng=EXCLUDED.lng,
same_day=EXCLUDED.same_day, active=TRUE;
-- 앱 계정 권한(소유자 postgres로 생성 시 대비) — 신규 테이블/시퀀스 한정
DO $$ BEGIN
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname='mall_user') THEN
GRANT SELECT, INSERT, UPDATE, DELETE ON mall_delivery_area TO mall_user;
GRANT USAGE, SELECT ON SEQUENCE mall_delivery_area_id_seq TO mall_user;
END IF;
END $$;
-- ---------------------------------------------------------------------------
-- 3. 카탈로그 / 상품 / 사이즈 / 옵션
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS mall_category (
id BIGSERIAL PRIMARY KEY, parent_id BIGINT, name VARCHAR(200) NOT NULL, code VARCHAR(60),
sort_order INTEGER DEFAULT 0, active BOOLEAN DEFAULT TRUE
);
-- 실데이터: Montvale Florist (montvalefloristnj.com) 카테고리 트리
-- Occasions / Flower Type / Plants / Colors / Collections / Price Range
INSERT INTO mall_category (id, parent_id, name, code, sort_order) VALUES
-- 최상위
(1,NULL,'Occasions','OCCASION',1),(2,NULL,'Flower Type','FLOWER',2),
(15,NULL,'Plants','PLANTS',3),(16,NULL,'Colors','COLOR',4),
(17,NULL,'Collections','COLLECTION',5),(18,NULL,'Price Range','PRICE',6),
-- Occasions
(3,1,'Birthday','BIRTHDAY',1),(4,1,'Anniversary','ANNIVERSARY',2),(5,1,'Sympathy & Funeral','SYMPATHY',3),
(6,1,'Get Well','GETWELL',4),(7,1,'Love & Romance','ROMANCE',5),(8,1,'Congratulations','CONGRATS',6),
(19,1,'Thinking of You','THINKING',7),(20,1,'Thank You','THANKYOU',8),(21,1,'Just Because','JUSTBECAUSE',9),
-- Flower Type
(9,2,'Roses','ROSES',1),(10,2,'Tulips','TULIPS',2),(11,2,'Lilies','LILIES',3),
(12,2,'Sunflowers','SUNFLOWERS',4),(13,2,'Hydrangeas','HYDRANGEAS',5),(14,2,'Mixed','MIXED',6),
-- Plants
(22,15,'Blooming Plants','BLOOMING_PLANTS',1),(23,15,'Green Plants','GREEN_PLANTS',2),
-- Colors
(24,16,'Red','RED',1),(25,16,'Pink','PINK',2),(26,16,'White','WHITE',3),
(27,16,'Purple','PURPLE',4),(28,16,'Yellow','YELLOW',5),(29,16,'Green','GREEN',6),(30,16,'Mixed','MIXED_COLOR',7),
-- Collections
(31,17,'Premium Collection','PREMIUM',1),(32,17,'Gift Baskets','GIFT_BASKETS',2),
(33,17,'Wedding','WEDDING',3),(34,17,'Custom Designs','CUSTOM',4),(35,17,'Florist''s Choice Daily Deal','DAILY_DEAL',5),
-- Price Range
(36,18,'Under $50','UNDER_50',1),(37,18,'$50 - $60','PR_50_60',2),
(38,18,'$60 - $80','PR_60_80',3),(39,18,'Over $80','OVER_80',4)
ON CONFLICT (id) DO NOTHING;
SELECT setval(pg_get_serial_sequence('mall_category','id'), GREATEST((SELECT MAX(id) FROM mall_category),1));
-- 상품: 행사/꽃종류/유통기한/사이즈는 별도 테이블(mall_product_size)
CREATE TABLE IF NOT EXISTS mall_product (
id BIGSERIAL PRIMARY KEY, category_id BIGINT, sku VARCHAR(80), name VARCHAR(300) NOT NULL,
brand VARCHAR(120), description TEXT, price NUMERIC(12,2) NOT NULL, sale_price NUMERIC(12,2),
status VARCHAR(30) DEFAULT 'ON_SALE', stock INTEGER DEFAULT 0, thumbnail VARCHAR(600),
occasion VARCHAR(60), -- BIRTHDAY/ANNIVERSARY/...
flower_type VARCHAR(60), -- ROSES/TULIPS/...
shelf_life_days INTEGER DEFAULT 5, -- 생화 시한성(유통기한 일수)
rating_avg NUMERIC(3,2) DEFAULT 0, review_count INTEGER DEFAULT 0, sales_count INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT NOW()
);
-- 3사이즈 (Original / Deluxe / Grand) — Bouqs 패턴
CREATE TABLE IF NOT EXISTS mall_product_size (
id BIGSERIAL PRIMARY KEY, product_id BIGINT NOT NULL,
size_code VARCHAR(20) NOT NULL, -- ORIGINAL / DELUXE / GRAND
label VARCHAR(60), price NUMERIC(12,2) NOT NULL, stem_count INTEGER, sort_order INTEGER DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_mall_psize_product ON mall_product_size(product_id);
-- 옵션 (화병/카드메시지/포장)
CREATE TABLE IF NOT EXISTS mall_product_option (
id BIGSERIAL PRIMARY KEY, product_id BIGINT NOT NULL, option_name VARCHAR(120),
option_value VARCHAR(200), extra_price NUMERIC(12,2) DEFAULT 0, stock INTEGER DEFAULT 0,
sku_suffix VARCHAR(60), option_type VARCHAR(40) -- VASE / CARD_MESSAGE / WRAP
);
CREATE TABLE IF NOT EXISTS mall_product_image (
id BIGSERIAL PRIMARY KEY, product_id BIGINT NOT NULL, url VARCHAR(600), sort_order INTEGER DEFAULT 0, is_main BOOLEAN DEFAULT FALSE
);
-- 실데이터: Montvale Florist 실상품(실명·실가) — image_url=/img/products/<slug>.<ext>
-- brand='Montvale Florist'. price = 사이트 표기 "From" 가격. 이미지는 backend static에서 그대로 서빙.
INSERT INTO mall_product (id, category_id, sku, name, brand, description, price, sale_price, status, stock, thumbnail, occasion, flower_type, shelf_life_days, rating_avg, review_count, sales_count) VALUES
(1,35,'MV-DAILY-DEAL','Florist''s Choice Daily Deal','Montvale Florist','Can''t decide? How about a surprise! A creative mix of seasonal blooms arranged with the designer''s freshest selection. Measures 10"-20" H (size will vary). 100% Florist-Designed and Hand-Delivered.',69.99,NULL,'ON_SALE',120,'/img/products/florists-choice-daily-deal.png','JUSTBECAUSE','MIXED',6,4.9,142,640),
(2,3,'MV-RADIANT-RAINBOW','Radiant Rainbow™','Montvale Florist','A vibrant, joyful arrangement bursting with a rainbow of seasonal blooms. Perfect for birthdays and any happy celebration.',79.95,NULL,'ON_SALE',90,'/img/products/radiant-rainbow.jpg','BIRTHDAY','MIXED',6,4.9,118,420),
(3,5,'MV-HALCYON-HEART','Halcyon Heart™','Montvale Florist','A serene, heartfelt tribute of soft blooms expressing peace, love, and remembrance.',79.95,NULL,'ON_SALE',60,'/img/products/halcyon-heart.jpg','SYMPATHY','MIXED',6,4.8,64,180),
(4,5,'MV-GRACEFUL-EMBRACE','Graceful Embrace','Montvale Florist','An elegant arrangement of gentle blooms offering comfort and a graceful embrace of sympathy.',79.95,NULL,'ON_SALE',55,'/img/products/graceful-embrace.jpg','SYMPATHY','MIXED',6,4.7,52,150),
(5,31,'MV-BLOOMING-DAYDREAM','Blooming Daydream','Montvale Florist','A premium, dreamy bouquet of lush garden blooms — a beautiful daydream brought to life.',99.95,NULL,'ON_SALE',45,'/img/products/blooming-daydream.jpg','ANNIVERSARY','MIXED',5,4.9,40,160),
(6,3,'MV-SPRING-SERENADE','Spring Serenade','Montvale Florist','A fresh, fragrant medley of spring flowers that sings of the season.',79.95,NULL,'ON_SALE',60,'/img/products/spring-serenade.jpg','BIRTHDAY','MIXED',5,4.7,38,140),
(7,23,'MV-GREEN-GRACE','Green Grace','Montvale Florist','A lush, verdant arrangement of greens and textured foliage — graceful and grounding.',99.95,NULL,'ON_SALE',40,'/img/products/green-grace.jpg','SYMPATHY','GREEN',7,4.8,30,110),
(8,9,'MV-12-RED-ROSES','12 Classic Red Roses','Montvale Florist','A timeless dozen of premium long-stemmed red roses — the ultimate expression of love.',99.95,NULL,'ON_SALE',100,'/img/products/classic-red-roses.jpg','ROMANCE','ROSES',6,4.9,210,720),
(9,20,'MV-JOYFUL-THANKS','Joyful Thanks™','Montvale Florist','A cheerful thank-you bouquet of bright seasonal blooms to express heartfelt gratitude.',59.95,NULL,'ON_SALE',80,'/img/products/joyful-thanks.jpg','THANKYOU','MIXED',6,4.6,58,210),
(10,31,'MV-BREATHTAKING-BEAUTY','Breathtaking Beauty™','Montvale Florist','A stunning premium arrangement of luxurious blooms that takes the breath away.',99.95,NULL,'ON_SALE',45,'/img/products/breathtaking-beauty.jpg','ROMANCE','MIXED',5,4.9,72,260),
(11,9,'MV-SWEETEST-ROSES','Sweetest Roses™','Montvale Florist','An opulent display of the sweetest premium roses — grand romance in full bloom.',199.99,NULL,'ON_SALE',25,'/img/products/sweetest-roses.jpg','ROMANCE','ROSES',6,5.0,44,120),
(12,32,'MV-FRUIT-BASKET','Fruit Basket','Montvale Florist','A bountiful gourmet fruit basket filled with fresh seasonal fruit — a wholesome, comforting gift.',99.95,NULL,'ON_SALE',40,'/img/products/fruit-basket.jpg','GETWELL','MIXED',10,4.6,33,140),
(13,13,'MV-HYDRANGEA-HIGHLIGHT','Hydrangea Highlight','Montvale Florist','Lush hydrangeas take center stage in this elegant, full-bodied arrangement.',79.95,NULL,'ON_SALE',45,'/img/products/hydrangea-highlight.jpg','BIRTHDAY','HYDRANGEAS',5,4.8,40,150),
(14,3,'MV-FULL-OF-SMILES','Full of Smiles','Montvale Florist','A bright, playful bouquet bursting with color to bring a smile to anyone''s day.',59.95,NULL,'ON_SALE',75,'/img/products/full-of-smiles.jpg','GETWELL','MIXED',6,4.6,71,260),
(15,35,'MV-FC-BIRTHDAY','Florist''s Choice for Birthday','Montvale Florist','Let our designer create a one-of-a-kind birthday arrangement with the freshest blooms of the day.',69.95,NULL,'ON_SALE',70,'/img/products/florists-choice-birthday.jpg','BIRTHDAY','MIXED',6,4.7,64,230),
(16,7,'MV-RASPBERRIES-BLISS','Raspberries & Bliss','Montvale Florist','A romantic blend of berry-toned blooms — pure blissful indulgence.',79.99,NULL,'ON_SALE',50,'/img/products/raspberries-and-bliss.jpg','ROMANCE','MIXED',6,4.7,32,120),
(17,31,'MV-MAGNIFICENT-MIDNIGHT','Magnificent Midnight','Montvale Florist','A dramatic premium arrangement of deep, moody blooms — magnificently bold.',199.95,NULL,'ON_SALE',25,'/img/products/magnificent-midnight.jpg','ANNIVERSARY','MIXED',5,4.9,28,90),
(18,31,'MV-FAIRY-BLOSSOM','Fairy Blossom Bouquet','Montvale Florist','A whimsical, ethereal bouquet of delicate blossoms — a touch of fairytale magic.',124.99,NULL,'ON_SALE',35,'/img/products/fairy-blossom-bouquet.jpg','ANNIVERSARY','MIXED',5,4.8,21,80),
(19,9,'MV-12-WHITE-ROSES','Dozen White Roses','Montvale Florist','A pristine dozen of premium white roses — pure elegance for any tribute or celebration.',99.95,NULL,'ON_SALE',70,'/img/products/dozen-white-roses.jpg','SYMPATHY','ROSES',6,4.8,55,200),
(20,9,'MV-LOVE-BRETT','Love Brett','Montvale Florist','A heartfelt rose arrangement designed to say "I love you" in the language of flowers.',99.95,NULL,'ON_SALE',45,'/img/products/love-brett.gif','ROMANCE','ROSES',6,4.6,18,60),
(21,9,'MV-SWEET-HONEY-KISSES','Sweet Honey Kisses','Montvale Florist','Warm honey and blush tones blend in this sweet, romantic rose bouquet.',79.95,NULL,'ON_SALE',50,'/img/products/sweet-honey-kisses.jpg','ROMANCE','ROSES',6,4.6,24,90),
(22,27,'MV-LAVENDER-LUST','Lavender Lust','Montvale Florist','A dreamy lavender-hued arrangement — soft, romantic, and utterly captivating.',79.95,NULL,'ON_SALE',45,'/img/products/lavender-lust.jpg','ROMANCE','MIXED',6,4.7,26,95),
(23,5,'MV-GARDEN-MEMORIES','Garden of Memories','Montvale Florist','A gentle garden-style arrangement honoring cherished memories with grace.',69.95,NULL,'ON_SALE',50,'/img/products/garden-of-memories.jpg','SYMPATHY','MIXED',6,4.7,30,110),
(24,11,'MV-TENDER-LILY-SPRAY','Tender Sentiments Lily Spray™','Montvale Florist','A graceful funeral lily spray expressing tender sentiments and deep sympathy.',159.95,NULL,'ON_SALE',20,'/img/products/tender-sentiments-lily-spray.jpg','SYMPATHY','LILIES',7,4.8,15,40),
(25,22,'MV-PEACE-LILY-PLANT','Peace Lily Plant','Montvale Florist','A lush, easy-care peace lily plant — a living symbol of peace and lasting remembrance.',79.95,NULL,'ON_SALE',55,'/img/products/peace-lily-plant.jpg','SYMPATHY','LILIES',30,4.8,42,160),
(26,32,'MV-TWILIGHT-BASKET','Love''s Twilight Sympathy Basket™','Montvale Florist','A serene basket of soft twilight blooms offering comfort and sympathy.',129.95,NULL,'ON_SALE',30,'/img/products/loves-twilight-sympathy-basket.jpg','SYMPATHY','MIXED',6,4.7,18,60),
(27,5,'MV-IN-LOVING-MEMORY','In Loving Memory','Montvale Florist','A dignified tribute arrangement crafted in loving memory of those dearly missed.',159.95,NULL,'ON_SALE',25,'/img/products/in-loving-memory.jpg','SYMPATHY','MIXED',6,4.8,22,70),
(28,32,'MV-AMETHYST-BASKET','Amethyst Sunset Sympathy Basket™','Montvale Florist','A rich basket of amethyst and sunset-toned blooms expressing heartfelt condolence.',129.95,NULL,'ON_SALE',28,'/img/products/amethyst-sunset-sympathy-basket.jpg','SYMPATHY','PURPLE',6,4.7,16,55),
(29,5,'MV-CALMING-COMFORT','Calming Comfort™','Montvale Florist','A soothing arrangement of soft pastel blooms offering calm and comfort in times of loss.',129.95,NULL,'ON_SALE',30,'/img/products/calming-comfort.jpg','SYMPATHY','MIXED',6,4.8,20,65),
(30,23,'MV-VERDANT-GARDENS','Verdant Gardens','Montvale Florist','A fresh, green garden arrangement full of lush foliage and natural texture.',79.95,NULL,'ON_SALE',45,'/img/products/verdant-gardens.jpg','SYMPATHY','GREEN',7,4.6,18,60),
(31,31,'MV-WITH-OPEN-HEARTS','With Open Hearts™','Montvale Florist','A grand, heartfelt premium tribute of abundant blooms offered with open hearts.',249.95,NULL,'ON_SALE',18,'/img/products/with-open-hearts.jpg','SYMPATHY','MIXED',6,4.9,12,40),
(32,7,'MV-STRAWBERRY-BLUSH','Strawberry Blush','Montvale Florist','A romantic blush-and-berry arrangement, sweet and softly captivating.',99.95,NULL,'ON_SALE',45,'/img/products/strawberry-blush.jpg','ROMANCE','PINK',6,4.7,24,85),
(33,35,'MV-FC-ROMANCE','Florist''s Choice for Romance','Montvale Florist','A designer''s romantic masterpiece, crafted with the most luxurious blooms of the day.',149.99,NULL,'ON_SALE',35,'/img/products/florists-choice-romance.jpg','ROMANCE','MIXED',6,4.8,20,70),
(34,7,'MV-DELIGHTFUL-DUALITY','Delightful Duality','Montvale Florist','A striking two-tone arrangement balancing bold and soft blooms in delightful harmony.',99.95,NULL,'ON_SALE',40,'/img/products/delightful-duality.jpg','ROMANCE','MIXED',6,4.7,19,65),
(35,31,'MV-NOTHING-COMPARES','Nothing Compares','Montvale Florist','An unrivaled premium arrangement of the rarest, most exquisite blooms — nothing compares.',299.95,NULL,'ON_SALE',15,'/img/products/nothing-compares.jpg','ROMANCE','MIXED',5,5.0,14,45),
(36,23,'MV-EMERALD-GARDEN','Emerald Garden','Montvale Florist','A rich emerald-green plant garden, lush and long-lasting.',119.95,NULL,'ON_SALE',30,'/img/products/emerald-garden.jpg','SYMPATHY','GREEN',30,4.7,17,55),
(37,5,'MV-FOREVER-SYMPATHY','Forever With Sympathy','Montvale Florist','A timeless sympathy arrangement of soft blooms expressing lasting condolence.',79.95,NULL,'ON_SALE',40,'/img/products/forever-with-sympathy.jpg','SYMPATHY','MIXED',6,4.6,16,55)
ON CONFLICT (id) DO NOTHING;
SELECT setval(pg_get_serial_sequence('mall_product','id'), GREATEST((SELECT MAX(id) FROM mall_product),1));
-- 상품 메인 이미지 시드 (detail 갤러리) — thumbnail 경로를 main 이미지로
INSERT INTO mall_product_image (product_id, url, sort_order, is_main)
SELECT p.id, p.thumbnail, 0, TRUE FROM mall_product p
WHERE p.thumbnail IS NOT NULL
AND NOT EXISTS (SELECT 1 FROM mall_product_image i WHERE i.product_id=p.id);
-- 3사이즈 시드 (모든 상품에 Original/Deluxe/Grand)
INSERT INTO mall_product_size (product_id, size_code, label, price, stem_count, sort_order)
SELECT p.id, 'ORIGINAL','Original', p.price, 12, 1 FROM mall_product p
WHERE NOT EXISTS (SELECT 1 FROM mall_product_size s WHERE s.product_id=p.id AND s.size_code='ORIGINAL');
INSERT INTO mall_product_size (product_id, size_code, label, price, stem_count, sort_order)
SELECT p.id, 'DELUXE','Deluxe', ROUND(p.price*1.4,2), 18, 2 FROM mall_product p
WHERE NOT EXISTS (SELECT 1 FROM mall_product_size s WHERE s.product_id=p.id AND s.size_code='DELUXE');
INSERT INTO mall_product_size (product_id, size_code, label, price, stem_count, sort_order)
SELECT p.id, 'GRAND','Grand', ROUND(p.price*1.9,2), 24, 3 FROM mall_product p
WHERE NOT EXISTS (SELECT 1 FROM mall_product_size s WHERE s.product_id=p.id AND s.size_code='GRAND');
-- 옵션 시드 (화병/카드/포장)
INSERT INTO mall_product_option (product_id, option_name, option_value, extra_price, stock, option_type)
SELECT p.id, 'Vase','Glass Vase Upgrade', 12.00, 999, 'VASE' FROM mall_product p
WHERE NOT EXISTS (SELECT 1 FROM mall_product_option o WHERE o.product_id=p.id AND o.option_type='VASE');
INSERT INTO mall_product_option (product_id, option_name, option_value, extra_price, stock, option_type)
SELECT p.id, 'Wrap','Premium Gift Wrap', 6.00, 999, 'WRAP' FROM mall_product p
WHERE NOT EXISTS (SELECT 1 FROM mall_product_option o WHERE o.product_id=p.id AND o.option_type='WRAP');
INSERT INTO mall_product_option (product_id, option_name, option_value, extra_price, stock, option_type)
SELECT p.id, 'Card','Personalized Card Message', 0.00, 999, 'CARD_MESSAGE' FROM mall_product p
WHERE NOT EXISTS (SELECT 1 FROM mall_product_option o WHERE o.product_id=p.id AND o.option_type='CARD_MESSAGE');
-- ---------------------------------------------------------------------------
-- 실데이터 보강: Montvale Florist any-occasion·sympathy 신규 상품 (id 38~70)
-- 크롤링: montvalefloristnj.com/any-occasion · /sympathy-and-funeral · /get-well
-- category_id: 5=Sympathy & Funeral, 6=Get Well. brand='Montvale Florist'. 이미지 캡쳐 그대로(/img/products/<slug>.jpg)
-- ---------------------------------------------------------------------------
INSERT INTO mall_product (id, category_id, sku, name, brand, description, price, sale_price, status, stock, thumbnail, occasion, flower_type, shelf_life_days, rating_avg, review_count, sales_count) VALUES
(38,6,'MV-EUROPEAN-TERRACE','European Terrace™','Montvale Florist','A lush European-style garden basket of blooming and green plants — a living terrace of natural beauty. 100% Florist-Designed and Hand-Delivered.',99.95,NULL,'ON_SALE',35,'/img/products/european-terrace.jpg','GETWELL','MIXED',7,4.80,34,120),
(39,5,'MV-FOND-REMEM-SPRAY','Fond Remembrance Standing Spray','Montvale Florist','A graceful funeral standing spray of soft blooms expressing fond remembrance and heartfelt sympathy.',159.95,NULL,'ON_SALE',35,'/img/products/fond-remembrance-standing-spray.jpg','SYMPATHY','MIXED',7,4.80,18,55),
(40,5,'MV-LAVENDER-MEM-SPRAY','Lavender Memories Spray™','Montvale Florist','A serene standing spray of lavender-hued blooms honoring cherished memories with grace and peace.',179.95,NULL,'ON_SALE',35,'/img/products/lavender-memories-spray.jpg','SYMPATHY','PURPLE',7,4.80,14,45),
(41,5,'MV-BRIGHT-MEMORIES','Bright Memories','Montvale Florist','A warm, uplifting tribute of bright seasonal blooms celebrating a life brightly lived.',129.95,NULL,'ON_SALE',35,'/img/products/bright-memories.jpg','SYMPATHY','MIXED',6,4.70,16,50),
(42,5,'MV-ADORING-TRIBUTE','Adoring Tribute','Montvale Florist','An adoring floral tribute of elegant blooms offered in loving honor and remembrance.',149.95,NULL,'ON_SALE',35,'/img/products/adoring-tribute.jpg','SYMPATHY','MIXED',6,4.80,12,40),
(43,5,'MV-SWEET-COMFORT','Sweet Comfort','Montvale Florist','A soothing arrangement of soft, sweet blooms offering comfort and solace in times of loss.',129.95,NULL,'ON_SALE',35,'/img/products/sweet-comfort.jpg','SYMPATHY','MIXED',6,4.70,15,48),
(44,5,'MV-JOYFUL-MEMORIES','Joyful Memories','Montvale Florist','A vibrant tribute of cheerful blooms celebrating the joyful memories of a treasured life.',129.95,NULL,'ON_SALE',35,'/img/products/joyful-memories.jpg','SYMPATHY','MIXED',6,4.70,13,42),
(45,5,'MV-PASSIONATE-FAITH','Passionate Faith Sympathy Wreath™','Montvale Florist','A dignified sympathy wreath of rich blooms expressing passionate faith and eternal devotion.',199.95,NULL,'ON_SALE',35,'/img/products/passionate-faith-sympathy-wreath.jpg','SYMPATHY','MIXED',7,4.80,10,32),
(46,5,'MV-SPIRITED-REMEM','Spirited Remembrance™','Montvale Florist','A spirited arrangement of lively blooms honoring a vibrant spirit and lasting remembrance.',129.95,NULL,'ON_SALE',35,'/img/products/spirited-remembrance.jpg','SYMPATHY','MIXED',6,4.70,14,44),
(47,5,'MV-FOND-REMEM-TRIBUTE','Fond Remembrance Tribute','Montvale Florist','A heartfelt tribute of gentle blooms expressing fond remembrance and deep sympathy.',129.95,NULL,'ON_SALE',35,'/img/products/fond-remembrance-tribute.jpg','SYMPATHY','MIXED',6,4.70,12,38),
(48,5,'MV-HEAVENS-PROMISE','Heaven''s Promise Sympathy Tribute™','Montvale Florist','A peaceful sympathy tribute of soft blooms evoking heaven''s promise of eternal peace.',129.95,NULL,'ON_SALE',35,'/img/products/heavens-promise-sympathy-tribute.jpg','SYMPATHY','MIXED',6,4.80,11,36),
(49,5,'MV-ENDURING-FAITH','Enduring Faith','Montvale Florist','A grand standing tribute of abundant blooms expressing enduring faith and steadfast love.',249.95,NULL,'ON_SALE',35,'/img/products/enduring-faith.jpg','SYMPATHY','MIXED',7,4.90,9,28),
(50,5,'MV-GENTLE-REPOSE','Gentle Repose Lily Spray™','Montvale Florist','A graceful lily standing spray offering gentle repose and serene, heartfelt condolence.',199.95,NULL,'ON_SALE',35,'/img/products/gentle-repose-lily-spray.jpg','SYMPATHY','LILIES',7,4.80,10,30),
(51,5,'MV-STARGAZER-WREATH','Stargazer Sentiments Wreath™','Montvale Florist','A striking sympathy wreath featuring stargazer lilies — a beautiful expression of heartfelt sentiments.',229.95,NULL,'ON_SALE',35,'/img/products/stargazer-sentiments-wreath.jpg','SYMPATHY','LILIES',7,4.80,8,26),
(52,5,'MV-WARM-REMEM','Warm Remembrance','Montvale Florist','A warm tribute of golden and amber blooms honoring a cherished life with heartfelt remembrance.',129.95,NULL,'ON_SALE',35,'/img/products/warm-remembrance.jpg','SYMPATHY','MIXED',6,4.70,13,41),
(53,5,'MV-SHADES-REMEM','Shades of Remembrance™','Montvale Florist','A tonal tribute of layered blooms in soft shades expressing tender remembrance and sympathy.',129.95,NULL,'ON_SALE',35,'/img/products/shades-of-remembrance.jpg','SYMPATHY','MIXED',6,4.70,12,39),
(54,5,'MV-TENDER-CASKET','Tender Sentiments Casket Spray™','Montvale Florist','An elegant casket spray of abundant blooms expressing the most tender sentiments and deep sympathy.',249.95,NULL,'ON_SALE',35,'/img/products/tender-sentiments-casket-spray.jpg','SYMPATHY','MIXED',7,4.90,9,27),
(55,5,'MV-FROM-THE-HEART','From the Heart','Montvale Florist','A sincere arrangement of heartfelt blooms offered straight from the heart in loving sympathy.',129.95,NULL,'ON_SALE',35,'/img/products/from-the-heart.jpg','SYMPATHY','MIXED',6,4.70,14,43),
(56,5,'MV-GARDEN-PATH','Garden Path Tribute','Montvale Florist','A natural garden-style tribute of soft blooms tracing a gentle path of remembrance.',129.95,NULL,'ON_SALE',35,'/img/products/garden-path-tribute.jpg','SYMPATHY','MIXED',6,4.70,11,37),
(57,5,'MV-HEAVENLY-HORIZONS','Heavenly Horizons Spray™','Montvale Florist','A serene standing spray of soft blooms evoking heavenly horizons and eternal peace.',179.95,NULL,'ON_SALE',35,'/img/products/heavenly-horizons-spray.jpg','SYMPATHY','MIXED',7,4.80,10,31),
(58,5,'MV-ROSY-HEART-WREATH','Rosy Remembrance Heart Wreath™','Montvale Florist','A heart-shaped sympathy wreath of roses and soft blooms — a rosy tribute of enduring love.',249.95,NULL,'ON_SALE',35,'/img/products/rosy-remembrance-heart-wreath.jpg','SYMPATHY','ROSES',6,4.90,8,25),
(59,5,'MV-LOVE-PRAYERS-CROSS','Love and Prayers Sympathy Cross™','Montvale Florist','A dignified sympathy cross of pristine blooms expressing love, faith, and heartfelt prayers.',229.95,NULL,'ON_SALE',35,'/img/products/love-and-prayers-sympathy-cross.jpg','SYMPATHY','MIXED',7,4.80,9,29),
(60,5,'MV-ENDURING-LOVE-WREATH','Enduring Love Wreath™','Montvale Florist','A grand sympathy wreath of abundant blooms symbolizing enduring, unbroken love and remembrance.',299.95,NULL,'ON_SALE',35,'/img/products/enduring-love-wreath.jpg','SYMPATHY','MIXED',7,4.90,7,22),
(61,5,'MV-SHINING-LIGHT','Shining Light Tribute','Montvale Florist','A radiant tribute of bright blooms honoring a shining light and a life that brightened many.',129.95,NULL,'ON_SALE',35,'/img/products/shining-light-tribute.jpg','SYMPATHY','MIXED',6,4.70,12,38),
(62,5,'MV-LOVING-THOUGHTS','Loving Thoughts Wreath','Montvale Florist','A classic sympathy wreath of soft blooms conveying loving thoughts and heartfelt condolence.',249.95,NULL,'ON_SALE',35,'/img/products/loving-thoughts-wreath.jpg','SYMPATHY','MIXED',7,4.80,8,24),
(63,5,'MV-SYMPATHETIC-HEART','Sympathetic Heart Standing Spray™','Montvale Florist','A heart-shaped standing spray of abundant blooms offering deep, sympathetic comfort.',279.95,NULL,'ON_SALE',35,'/img/products/sympathetic-heart-standing-spray.jpg','SYMPATHY','MIXED',7,4.90,7,21),
(64,5,'MV-INTO-OPEN-ARMS','Into Open Arms','Montvale Florist','A welcoming tribute of soft blooms embracing a loved one into open, eternal arms.',129.00,NULL,'ON_SALE',35,'/img/products/into-open-arms.jpg','SYMPATHY','MIXED',6,4.70,11,35),
(65,5,'MV-ENCIRCLED-LOVE','Encircled By Love™','Montvale Florist','A circular sympathy wreath of lush blooms expressing a love that encircles eternally.',249.95,NULL,'ON_SALE',35,'/img/products/encircled-by-love.jpg','SYMPATHY','MIXED',7,4.80,8,26),
(66,5,'MV-STARGAZER-CROSS','Stargazer Sympathies Cross™','Montvale Florist','A sympathy cross featuring stargazer lilies — a graceful expression of faith and sympathy.',229.95,NULL,'ON_SALE',35,'/img/products/stargazer-sympathies-cross.jpg','SYMPATHY','LILIES',7,4.80,8,25),
(67,5,'MV-ALWAYS-REMEM-SPRAY','Always Remembered Sympathy Spray™','Montvale Florist','A standing sympathy spray of soft blooms honoring a loved one always remembered.',199.95,NULL,'ON_SALE',35,'/img/products/always-remembered-sympathy-spray.jpg','SYMPATHY','MIXED',7,4.80,9,29),
(68,5,'MV-FOREVER-ADORED-CASKET','Forever Adored Casket Spray','Montvale Florist','A luxurious casket spray of abundant premium blooms honoring one forever adored.',329.95,NULL,'ON_SALE',35,'/img/products/forever-adored-casket-spray.jpg','SYMPATHY','MIXED',7,4.90,6,18),
(69,5,'MV-PASSIONATE-GRACE','Passionate Grace Wreath™','Montvale Florist','A sympathy wreath of rich, graceful blooms expressing passionate grace and devotion.',249.95,NULL,'ON_SALE',35,'/img/products/passionate-grace-wreath.jpg','SYMPATHY','MIXED',7,4.80,7,23),
(70,5,'MV-LOVES-REMEM-WREATH','Love''s Remembrance Wreath™','Montvale Florist','A grand sympathy wreath of abundant blooms expressing love''s lasting remembrance.',279.95,NULL,'ON_SALE',35,'/img/products/loves-remembrance-wreath.jpg','SYMPATHY','MIXED',7,4.90,6,20)
ON CONFLICT (id) DO NOTHING;
SELECT setval(pg_get_serial_sequence('mall_product','id'), GREATEST((SELECT MAX(id) FROM mall_product),1));
-- 신규 상품(38~70) 메인 이미지/사이즈/옵션
INSERT INTO mall_product_image (product_id, url, sort_order, is_main)
SELECT p.id, p.thumbnail, 0, TRUE FROM mall_product p
WHERE p.id BETWEEN 38 AND 70 AND p.thumbnail IS NOT NULL
AND NOT EXISTS (SELECT 1 FROM mall_product_image i WHERE i.product_id=p.id);
INSERT INTO mall_product_size (product_id, size_code, label, price, stem_count, sort_order)
SELECT p.id, 'ORIGINAL','Original', p.price, 12, 1 FROM mall_product p
WHERE p.id BETWEEN 38 AND 70 AND NOT EXISTS (SELECT 1 FROM mall_product_size s WHERE s.product_id=p.id AND s.size_code='ORIGINAL');
INSERT INTO mall_product_size (product_id, size_code, label, price, stem_count, sort_order)
SELECT p.id, 'DELUXE','Deluxe', ROUND(p.price*1.4,2), 18, 2 FROM mall_product p
WHERE p.id BETWEEN 38 AND 70 AND NOT EXISTS (SELECT 1 FROM mall_product_size s WHERE s.product_id=p.id AND s.size_code='DELUXE');
INSERT INTO mall_product_size (product_id, size_code, label, price, stem_count, sort_order)
SELECT p.id, 'GRAND','Grand', ROUND(p.price*1.9,2), 24, 3 FROM mall_product p
WHERE p.id BETWEEN 38 AND 70 AND NOT EXISTS (SELECT 1 FROM mall_product_size s WHERE s.product_id=p.id AND s.size_code='GRAND');
INSERT INTO mall_product_option (product_id, option_name, option_value, extra_price, stock, option_type)
SELECT p.id, 'Vase','Glass Vase Upgrade', 12.00, 999, 'VASE' FROM mall_product p
WHERE p.id BETWEEN 38 AND 70 AND NOT EXISTS (SELECT 1 FROM mall_product_option o WHERE o.product_id=p.id AND o.option_type='VASE');
INSERT INTO mall_product_option (product_id, option_name, option_value, extra_price, stock, option_type)
SELECT p.id, 'Wrap','Premium Gift Wrap', 6.00, 999, 'WRAP' FROM mall_product p
WHERE p.id BETWEEN 38 AND 70 AND NOT EXISTS (SELECT 1 FROM mall_product_option o WHERE o.product_id=p.id AND o.option_type='WRAP');
INSERT INTO mall_product_option (product_id, option_name, option_value, extra_price, stock, option_type)
SELECT p.id, 'Card','Personalized Card Message', 0.00, 999, 'CARD_MESSAGE' FROM mall_product p
WHERE p.id BETWEEN 38 AND 70 AND NOT EXISTS (SELECT 1 FROM mall_product_option o WHERE o.product_id=p.id AND o.option_type='CARD_MESSAGE');
-- ---------------------------------------------------------------------------
-- 실데이터 보강: Montvale Florist 시즌 디자이너 상품 (id 71~73)
-- 크롤링: montvalefloristnj.com /flowers-over-80 · /flowers-60-to-80 (전 카탈로그 대조 후 신규만)
-- brand='Montvale Florist'. 이미지 캡쳐 그대로(/img/products/<slug>.<ext>, 원본 Cloudinary). price=사이트 Standard.
-- ---------------------------------------------------------------------------
INSERT INTO mall_product (id, category_id, sku, name, brand, description, price, sale_price, status, stock, thumbnail, occasion, flower_type, shelf_life_days, rating_avg, review_count, sales_count) VALUES
(71,31,'MV-MOTHERS-DAY-DESIGNER','Mother''s Day Designer Bouquet','Montvale Florist','Give this truly special gift to the woman who has done so much. Using only the freshest and most beautiful flowers, our experts will create a one-of-a-kind arrangement just for her. Mom''s gorgeous flowers will include the designer''s choice of fresh blooms. Measures 10"-20" H (size will vary). 100% Florist-Designed and Hand-Delivered.',249.95,NULL,'ON_SALE',30,'/img/products/mothers-day-designer-bouquet.png','ANNIVERSARY','MIXED',6,4.00,3,40),
(72,7,'MV-VALENTINES-SPECIAL','Valentine''s Day Special Bouquet','Montvale Florist','Your Valentine deserves the best. And nothing says "I love you" like a one-of-a-kind bouquet. Just leave it up to our floral designers — they''ll select from our most beautiful blooms to create a romantic showstopper for your sweetheart. Your special arrangement will include the designer''s choice of fresh blooms. Measures 10"-20" H (size will vary).',399.99,NULL,'ON_SALE',20,'/img/products/valentines-day-special-bouquet.png','ROMANCE','MIXED',6,5.00,3,60),
(73,35,'MV-VERY-MERRY-XMAS','Very Merry Christmas Artist''s Design','Montvale Florist','Celebrate the season with a festive holiday arrangement personally crafted by our designers using the designer''s choice of fresh seasonal blooms. Each Very Merry Christmas design is uniquely arranged for your recipient with Christmassy cheer. Measures 10"-20" H (size will vary).',79.95,NULL,'ON_SALE',45,'/img/products/very-merry-christmas-artists-design.jpg','JUSTBECAUSE','MIXED',6,5.00,3,80)
ON CONFLICT (id) DO NOTHING;
SELECT setval(pg_get_serial_sequence('mall_product','id'), GREATEST((SELECT MAX(id) FROM mall_product),1));
INSERT INTO mall_product_image (product_id, url, sort_order, is_main)
SELECT p.id, p.thumbnail, 0, TRUE FROM mall_product p
WHERE p.id BETWEEN 71 AND 73 AND p.thumbnail IS NOT NULL
AND NOT EXISTS (SELECT 1 FROM mall_product_image i WHERE i.product_id=p.id);
INSERT INTO mall_product_size (product_id, size_code, label, price, stem_count, sort_order)
SELECT p.id, 'ORIGINAL','Standard', p.price, 12, 1 FROM mall_product p
WHERE p.id BETWEEN 71 AND 73 AND NOT EXISTS (SELECT 1 FROM mall_product_size s WHERE s.product_id=p.id AND s.size_code='ORIGINAL');
INSERT INTO mall_product_size (product_id, size_code, label, price, stem_count, sort_order)
SELECT p.id, 'DELUXE','Deluxe', ROUND(p.price*1.4,2), 18, 2 FROM mall_product p
WHERE p.id BETWEEN 71 AND 73 AND NOT EXISTS (SELECT 1 FROM mall_product_size s WHERE s.product_id=p.id AND s.size_code='DELUXE');
INSERT INTO mall_product_size (product_id, size_code, label, price, stem_count, sort_order)
SELECT p.id, 'GRAND','Premium', ROUND(p.price*1.9,2), 24, 3 FROM mall_product p
WHERE p.id BETWEEN 71 AND 73 AND NOT EXISTS (SELECT 1 FROM mall_product_size s WHERE s.product_id=p.id AND s.size_code='GRAND');
INSERT INTO mall_product_option (product_id, option_name, option_value, extra_price, stock, option_type)
SELECT p.id, 'Vase','Glass Vase Upgrade', 12.00, 999, 'VASE' FROM mall_product p
WHERE p.id BETWEEN 71 AND 73 AND NOT EXISTS (SELECT 1 FROM mall_product_option o WHERE o.product_id=p.id AND o.option_type='VASE');
INSERT INTO mall_product_option (product_id, option_name, option_value, extra_price, stock, option_type)
SELECT p.id, 'Wrap','Premium Gift Wrap', 6.00, 999, 'WRAP' FROM mall_product p
WHERE p.id BETWEEN 71 AND 73 AND NOT EXISTS (SELECT 1 FROM mall_product_option o WHERE o.product_id=p.id AND o.option_type='WRAP');
INSERT INTO mall_product_option (product_id, option_name, option_value, extra_price, stock, option_type)
SELECT p.id, 'Card','Personalized Card Message', 0.00, 999, 'CARD_MESSAGE' FROM mall_product p
WHERE p.id BETWEEN 71 AND 73 AND NOT EXISTS (SELECT 1 FROM mall_product_option o WHERE o.product_id=p.id AND o.option_type='CARD_MESSAGE');
-- ---------------------------------------------------------------------------
-- 4. 매장별 재고 ON/OFF (Store_Inventory)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS mall_store_inventory (
id BIGSERIAL PRIMARY KEY, store_id BIGINT NOT NULL, product_id BIGINT NOT NULL,
available BOOLEAN DEFAULT TRUE, -- 당일 입고 ON/OFF
on_hand INTEGER DEFAULT 0,
updated_by VARCHAR(200), updated_at TIMESTAMP DEFAULT NOW(),
UNIQUE(store_id, product_id)
);
CREATE INDEX IF NOT EXISTS idx_mall_sinv_store ON mall_store_inventory(store_id);
-- 모든 매장 × 모든 상품 = 가용(ON) 기본 시드
INSERT INTO mall_store_inventory (store_id, product_id, available, on_hand)
SELECT s.id, p.id, TRUE, 25 FROM mall_store s CROSS JOIN mall_product p
WHERE NOT EXISTS (SELECT 1 FROM mall_store_inventory si WHERE si.store_id=s.id AND si.product_id=p.id);
-- 단일 재고 (옵션 없는 ERP 동기 — 기존 호환)
CREATE TABLE IF NOT EXISTS mall_inventory (
id BIGSERIAL PRIMARY KEY, product_id BIGINT, option_id BIGINT, sku VARCHAR(80),
on_hand INTEGER DEFAULT 0, reserved INTEGER DEFAULT 0, safety_stock INTEGER DEFAULT 0,
erp_sync_status VARCHAR(20) DEFAULT 'NONE', updated_at TIMESTAMP DEFAULT NOW()
);
-- ---------------------------------------------------------------------------
-- 5. 스케줄링 (타임슬롯·당일마감·공휴일 블록아웃·서지프라이싱)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS mall_schedule_slot (
id BIGSERIAL PRIMARY KEY, store_id BIGINT NOT NULL, slot_date DATE NOT NULL,
slot_label VARCHAR(60) NOT NULL, -- 'Morning 9-12', 'Afternoon 12-3', 'Evening 3-6'
start_time VARCHAR(10), end_time VARCHAR(10),
capacity INTEGER DEFAULT 20, booked INTEGER DEFAULT 0,
surge_multiplier NUMERIC(4,2) DEFAULT 1.00, -- 서지프라이싱 배수
active BOOLEAN DEFAULT TRUE
);
CREATE INDEX IF NOT EXISTS idx_mall_slot_store_date ON mall_schedule_slot(store_id, slot_date);
-- 공휴일 블록아웃 + 서지 (밸런타인/어머니날)
CREATE TABLE IF NOT EXISTS mall_holiday (
id BIGSERIAL PRIMARY KEY, holiday_date DATE NOT NULL, name VARCHAR(120),
blocked BOOLEAN DEFAULT FALSE, -- 주문 차단
surge_multiplier NUMERIC(4,2) DEFAULT 1.00,
store_id BIGINT, -- NULL=전 매장
UNIQUE(holiday_date, store_id)
);
INSERT INTO mall_holiday (holiday_date, name, blocked, surge_multiplier, store_id) VALUES
('2026-02-14','Valentine''s Day', FALSE, 1.50, NULL),
('2026-05-10','Mother''s Day', FALSE, 1.40, NULL),
('2026-12-25','Christmas Day', TRUE, 1.00, NULL)
ON CONFLICT (holiday_date, store_id) DO NOTHING;
-- ---------------------------------------------------------------------------
-- 6. 장바구니
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS mall_cart_item (
id BIGSERIAL PRIMARY KEY, owner VARCHAR(200) NOT NULL, product_id BIGINT, option_id BIGINT,
size_code VARCHAR(20), product_name VARCHAR(300), option_label VARCHAR(200),
unit_price NUMERIC(12,2), quantity INTEGER DEFAULT 1,
card_message VARCHAR(500), created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_mall_cart_owner ON mall_cart_item(owner);
-- ---------------------------------------------------------------------------
-- 7. 주문 (로컬배송 vs 매장픽업, 예약 날짜·슬롯)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS mall_order (
id BIGSERIAL PRIMARY KEY, order_no VARCHAR(40) UNIQUE NOT NULL, owner VARCHAR(200) NOT NULL,
store_id BIGINT, -- 처리 매장
fulfillment_type VARCHAR(20) DEFAULT 'DELIVERY', -- DELIVERY / PICKUP
status VARCHAR(30) DEFAULT 'PENDING',
total_amount NUMERIC(12,2), discount_amount NUMERIC(12,2) DEFAULT 0,
tax_amount NUMERIC(12,2) DEFAULT 0, surge_amount NUMERIC(12,2) DEFAULT 0,
pay_amount NUMERIC(12,2),
receiver_name VARCHAR(200), receiver_phone VARCHAR(60), address VARCHAR(600),
delivery_zip VARCHAR(10),
scheduled_date DATE, slot_id BIGINT, slot_label VARCHAR(60),
card_message VARCHAR(500), memo VARCHAR(500), coupon_id BIGINT,
proof_photo_url VARCHAR(600), -- 꽃사진(제작완료) Proof of Quality
pod_photo_url VARCHAR(600), -- 문앞사진 Proof of Delivery
created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_mall_order_store ON mall_order(store_id);
CREATE INDEX IF NOT EXISTS idx_mall_order_status ON mall_order(status);
CREATE TABLE IF NOT EXISTS mall_order_item (
id BIGSERIAL PRIMARY KEY, order_id BIGINT NOT NULL, product_id BIGINT, option_id BIGINT,
size_code VARCHAR(20), product_name VARCHAR(300), option_label VARCHAR(200),
unit_price NUMERIC(12,2), quantity INTEGER, line_amount NUMERIC(12,2)
);
-- ---------------------------------------------------------------------------
-- 8. 결제 (민감정보 AES 암호화 *_enc)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS mall_payment (
id BIGSERIAL PRIMARY KEY, order_id BIGINT, method VARCHAR(40), pg_tid VARCHAR(120),
amount NUMERIC(12,2), status VARCHAR(30) DEFAULT 'READY',
card_no_enc VARCHAR(500), account_no_enc VARCHAR(500),
vbank_no VARCHAR(60), vbank_bank VARCHAR(80),
paid_at TIMESTAMP, created_at TIMESTAMP DEFAULT NOW()
);
-- ---------------------------------------------------------------------------
-- 9. 구독 (주간/격주/월간)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS mall_subscription (
id BIGSERIAL PRIMARY KEY, owner VARCHAR(200) NOT NULL, store_id BIGINT, product_id BIGINT,
size_code VARCHAR(20), frequency VARCHAR(20) DEFAULT 'WEEKLY', -- WEEKLY/BIWEEKLY/MONTHLY
delivery_zip VARCHAR(10), address VARCHAR(600), receiver_name VARCHAR(200), receiver_phone VARCHAR(60),
next_delivery_date DATE, status VARCHAR(20) DEFAULT 'ACTIVE', -- ACTIVE/PAUSED/CANCELLED
price NUMERIC(12,2), created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_mall_sub_owner ON mall_subscription(owner);
-- ---------------------------------------------------------------------------
-- 10. 매장간 재고 이양 (Transfer)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS mall_transfer (
id BIGSERIAL PRIMARY KEY, from_store_id BIGINT NOT NULL, to_store_id BIGINT NOT NULL,
product_id BIGINT NOT NULL, quantity INTEGER NOT NULL,
status VARCHAR(20) DEFAULT 'REQUESTED', -- REQUESTED/APPROVED/REJECTED/COMPLETED
requested_by VARCHAR(200), approved_by VARCHAR(200), reason VARCHAR(400),
ai_recommended BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW()
);
-- ---------------------------------------------------------------------------
-- 11. 배송 / 기사 라우팅
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS mall_delivery (
id BIGSERIAL PRIMARY KEY, order_id BIGINT, store_id BIGINT,
carrier VARCHAR(120), tracking_no VARCHAR(120),
driver_name VARCHAR(120), driver_phone VARCHAR(60),
status VARCHAR(30) DEFAULT 'READY', -- READY/IN_TRANSIT/OUT_FOR_DELIVERY/DELIVERED/FAILED
receiver_name VARCHAR(200), address VARCHAR(600), delivery_zip VARCHAR(10),
lat NUMERIC(10,6), lng NUMERIC(10,6), route_seq INTEGER, eta VARCHAR(40), pod_photo_url VARCHAR(600),
shipped_at TIMESTAMP, delivered_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW()
);
-- ---------------------------------------------------------------------------
-- 12. 리뷰 / 회원 / CS / 찜
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS mall_review (
id BIGSERIAL PRIMARY KEY, product_id BIGINT, order_id BIGINT, author VARCHAR(200),
rating INTEGER, title VARCHAR(300), content TEXT, image_url VARCHAR(600),
helpful_count INTEGER DEFAULT 0, store_id BIGINT, created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_mall_review_product ON mall_review(product_id);
INSERT INTO mall_review (product_id, author, rating, title, content, store_id) VALUES
(8,'jane',5,'Stunning red roses','A perfect classic dozen — arrived fresh and beautifully arranged. My wife loved them!',1),
(2,'jane',5,'So radiant!','The Radiant Rainbow lived up to its name — vibrant and full of life.',1),
(1,'jane',5,'Best surprise','The Florist''s Choice Daily Deal was even prettier than I imagined. Trust the designers!',1),
(14,'jane',4,'Brought a smile','Full of Smiles really did brighten the whole room.',1)
ON CONFLICT DO NOTHING;
-- 실데이터: Montvale Florist 상품 상세 페이지 실제 고객 리뷰 (Lovingly 검증 리뷰, montvalefloristnj.com)
-- 멱등: 동일 (product_id, author, content) 존재 시 INSERT 생략. store_id=1. created_at=사이트 표기일.
DO $$
DECLARE r RECORD;
BEGIN
FOR r IN
SELECT * FROM (VALUES
('Florist''s Choice Daily Deal','Natalie',5,'absolutely wonderful! i''ve been ordering bouquets for my mom''s birthday every year from here and they''ve always delivered the most beautiful flowers. thank you montvale florist!','2025-09-30'),
('Florist''s Choice Daily Deal','Nickoletta',5,'Beautiful, fresh flowers and excellent customer service - thank you!','2025-07-02'),
('Florist''s Choice Daily Deal','Maria',5,'Flowers were very fresh and beautifully arranged. Never disappointed with my orders! Great florist- I''ll continue to use them!','2025-03-29'),
('Radiant Rainbow™','shilpa',5,'Flowers are beautiful!! Staff is always wonderful!! This is the place to go in Bergen County!','2026-03-27'),
('Radiant Rainbow™','Anonymous',5,'Excellent prompt same day service. Like ordering a pizza to be delivered. Great job!','2026-03-04'),
('Radiant Rainbow™','James',5,'It was so easy to work online with Montvale Florist. Great selection, Great delivery. Overall very pleased. Thank you.','2025-09-14'),
('12 Classic Red Roses','Robert',5,'They were absolutely beautiful!','2026-02-19'),
('12 Classic Red Roses','Louis',5,'The roses and style of arrangement with Baby Breathe was perfect. The delivery time was also perfect... thanks again','2026-02-18'),
('12 Classic Red Roses','Dave',5,'Once again you ''delivered''- the red roses are spectacular! My girlfriend Sarah loved the bouquet!','2025-05-28'),
('Breathtaking Beauty™','Nikki',5,'I ordered flowers for my moms birthday and they are absolutely gorgeous and the vase itself is stunning. We couldn''t believe how big the arrangement was! Exceeded expectations and will be ordering again.','2026-03-28'),
('Breathtaking Beauty™','Kathy',5,'Our Aunt Joan loved the flowers and said they were beautiful!!','2026-03-02'),
('Breathtaking Beauty™','Gaddy',5,'Absolutely beautiful arrangements and exceptional service! I ordered a birthday bouquet for my wife from Montvale Florist, and they went above and beyond. The arrangement was stunning, fresh, vibrant, and full of color. It''s not just flowers, it''s an experience. I''ll definitely be ordering from them again for every special occasion.','2025-11-13'),
('Full of Smiles','Karen',5,'Very good service. Flowers looked beautiful and were delivered on time.','2018-03-13'),
('Full of Smiles','Barbara',5,'Flowers were delivered on time and were beautiful. My cousin was delighted with the arrangement.','2026-05-13'),
('Full of Smiles','Patricia',5,'My daughter in law loved the arrangement. Thank you so much.','2026-05-13'),
('Dozen White Roses','Kate',5,'So happy with Montvale Florist and the beautiful white roses delivered for my grandmother''s wake. Easy to work with and happy with the results. Would recommend!','2021-12-19'),
('Dozen White Roses','Barbara',5,'Flowers were delivered on time and were beautiful. My cousin was delighted with the arrangement.','2026-05-13'),
('Dozen White Roses','Patricia',5,'My daughter in law loved the arrangement. Thank you so much.','2026-05-13'),
('Blooming Daydream','Barbara',5,'Flowers were delivered on time and were beautiful. My cousin was delighted with the arrangement.','2026-05-13'),
('Blooming Daydream','Patricia',5,'My daughter in law loved the arrangement. Thank you so much.','2026-05-13'),
('Blooming Daydream','Linda',5,'Fiftieth Anniversary bouquet stunning and delivered right on time.','2026-04-20'),
('Halcyon Heart™','Brittany',5,'great experience ordering from here! was super easy and quick .. will definitely repeat.. my sister loved the flowers too they look super duper beautiful!! thanks for making gift-giving easy :D -britt','2022-08-31'),
('Halcyon Heart™','Jody',5,'Five stars! Thank you so much! You hit this one out the park!','2022-01-15'),
('Halcyon Heart™','Josette',5,'My People said they were beautiful thank you for a great job I will be happy to use you again','2021-05-25'),
('Peace Lily Plant','Roseann',5,'Exceeded expectations - great work!','2020-05-28'),
('Peace Lily Plant','Barbara',5,'Flowers were delivered on time and were beautiful. My cousin was delighted with the arrangement.','2026-05-13'),
('Peace Lily Plant','Patricia',5,'My daughter in law loved the arrangement. Thank you so much.','2026-05-13'),
('Joyful Thanks™','Barbara',5,'Flowers were delivered on time and were beautiful. My cousin was delighted with the arrangement.','2026-05-13'),
('Joyful Thanks™','Maria',5,'absolutely gorgeous flowers. helpful staff.','2026-02-26'),
('Joyful Thanks™','Susan',5,'She said they were absolutely gorgeous ! Thank you!','2024-08-21'),
('Spring Serenade','Barbara',5,'Flowers were delivered on time and were beautiful. My cousin was delighted with the arrangement.','2026-05-13'),
('Spring Serenade','Patricia',5,'My daughter in law loved the arrangement. Thank you so much.','2026-05-13'),
('Spring Serenade','Linda',5,'Fiftieth Anniversary bouquet stunning and delivered right on time.','2026-04-20'),
('Sweetest Roses™','JosephCallahan',5,'Joe and his staff have once again done a fantastic job creating a beautiful piece. I highly recommend Montvale Florist','2025-08-31'),
('Sweetest Roses™','Joseph',5,'Everything was perfect and looked even better than we could have imagined. You did the most amazing job and can''t thank you enough.','2023-09-01'),
('Sweetest Roses™','Joseph',5,'All I can say is ''Wow'' My girlfriend loved her flowers. She sent me a picture right away, and they were gorgeous. I called at 1130 am, and they were delivered. Great job!!!','2023-06-17'),
('Strawberry Blush','Judith',5,'The flowers were beautiful as usual. We love your arrangements!','2022-05-03'),
('Strawberry Blush','Roxanne',5,'Yes princess kim was very happy! I will continue to use Montvale florist! I give you five stars. Thanks again foxy','2022-04-19'),
('Strawberry Blush','Joan',5,'she loved her flowers and I loved that you were able to get them to her so quickly. thanks again.','2021-12-26'),
('Hydrangea Highlight','Judith',5,'Yes she did those are her favorite flowers Next week I''ll be ordering for Christmas you guys are so great thank you','2025-12-19'),
('Hydrangea Highlight','Mamie',5,'The lovely floral arrangement that I chose for delivery from their website was spot on. I live out of state and often with online floral orders you may not get what you ordered. Montvale Florist proved to be trustworthy. I was so pleased and so was the recipient!','2021-10-14'),
('Hydrangea Highlight','Barbara',5,'Flowers were delivered on time and were beautiful. My cousin was delighted with the arrangement.','2026-05-13'),
('Green Grace','Ethan',5,'Thank you for your fast and wonderful service. I ordered a plant arrangement for my family who moved into their new home and it came within hours of the order fresh and lovely arranged. Thank you.','2026-01-31'),
('Green Grace','Barbara',5,'Flowers were delivered on time and were beautiful. My cousin was delighted with the arrangement.','2026-05-13'),
('Green Grace','Patricia',5,'My daughter in law loved the arrangement. Thank you so much.','2026-05-13'),
('Graceful Embrace','Patricia',5,'My daughter in law loved the arrangement. Thank you so much.','2026-05-13'),
('Graceful Embrace','Tracey',5,'Thank you arrangement was lovely and delivered same day! Will definitely order from here again!','2024-07-31'),
('Graceful Embrace','Kristine',5,'Highly recommend. Delivered a beautiful flower arrangement on short notice.','2023-06-17'),
('In Loving Memory','Barbara',5,'Flowers were delivered on time and were beautiful. My cousin was delighted with the arrangement.','2026-05-13'),
('In Loving Memory','Patricia',5,'My daughter in law loved the arrangement. Thank you so much.','2026-05-13'),
('In Loving Memory','Linda',5,'Fiftieth Anniversary bouquet stunning and delivered right on time.','2026-04-20'),
('Lavender Lust','Andrew',5,'Timely delivery, beautiful flowers!','2024-02-18'),
('Lavender Lust','Barbara',5,'Flowers were delivered on time and were beautiful. My cousin was delighted with the arrangement.','2026-05-13'),
('Lavender Lust','Patricia',5,'My daughter in law loved the arrangement. Thank you so much.','2026-05-13'),
('Mother''s Day Designer Bouquet','Joseph',5,'I would like to thank you for such an excellent service that you provided as florist for our big day. Your arrangements blew us away. Thank you so much as it was an amazing surprise and they were delivered on time as I asked for.','2023-05-12'),
('Mother''s Day Designer Bouquet','Christian',5,'Very good.','2022-05-21'),
('Mother''s Day Designer Bouquet','Josh',2,'I was disappointed by this bouquet. I spent on the deluxe version of the Mother''s Day Designer bouquet, and what was delivered was a smaller bouquet than expected. Customer service confirmed it was their Deluxe size.','2022-05-11'),
('Valentine''s Day Special Bouquet','Stephan',5,'Valentine gifts was great my girl loved the flowers & chocolate','2024-02-19'),
('Valentine''s Day Special Bouquet','Joseph',5,'I want to thank you for the excellent service that you provided as a florist for surprising my love. Your arrangements blew us away. The arrangement looked beautiful, and everything you did looked magical. Thank you for helping us make our day so perfect.','2024-01-17'),
('Valentine''s Day Special Bouquet','Annalise',5,'Montvale florist always makes the most beautiful arrangements. They have always been reliable and accommodating. Everyone we have encountered who works there is friendly and hardworking. I am very pleased with the service.','2023-02-18'),
('Very Merry Christmas Artist''s Design','David',5,'My mom loved the Christmas flower arrangement you delivered! We weren''t able to celebrate with her due to Covid, but your arrangement let her know we were thinking about her, thank you!','2020-12-30'),
('Very Merry Christmas Artist''s Design','Jan',5,'Thank you for the lovely flowers you did for our family friends in New Jersey they were very nice and Christmassy','2020-12-26'),
('Very Merry Christmas Artist''s Design','Karen',5,'Flowers were beautiful! I''ll definitely order from them again. Great job!!!','2020-12-25')
) AS t(pname, author, rating, content, rdate)
LOOP
INSERT INTO mall_review (product_id, author, rating, title, content, store_id, created_at)
SELECT p.id, r.author, r.rating, NULL, r.content, 1, r.rdate::timestamp
FROM mall_product p
WHERE p.name = r.pname
AND NOT EXISTS (SELECT 1 FROM mall_review v WHERE v.product_id=p.id AND v.author=r.author AND v.content=r.content);
END LOOP;
END $$;
-- 리뷰에 맞춰 상품 통계 갱신: 기존(1~70) review_count는 마케팅 집계 수치 → 실제행수가 클 때만 상향, 신규(71~73)는 실제값.
UPDATE mall_product p SET
review_count = CASE WHEN p.id BETWEEN 71 AND 73 THEN sub.cnt ELSE GREATEST(p.review_count, sub.cnt) END,
rating_avg = sub.avg_rating
FROM (SELECT product_id, COUNT(*) AS cnt, ROUND(AVG(rating)::numeric,2) AS avg_rating FROM mall_review GROUP BY product_id) sub
WHERE p.id = sub.product_id;
CREATE TABLE IF NOT EXISTS mall_member (
id BIGSERIAL PRIMARY KEY, username VARCHAR(200) UNIQUE, display_name VARCHAR(200),
email VARCHAR(200), phone VARCHAR(60), default_zip VARCHAR(10), default_address VARCHAR(600),
crm_customer_key VARCHAR(120), tier VARCHAR(40) DEFAULT 'STANDARD',
created_at TIMESTAMP DEFAULT NOW()
);
INSERT INTO mall_member (username, display_name, email, default_zip) VALUES
('jane','Jane Doe','jane@example.com','07645') ON CONFLICT (username) DO NOTHING;
CREATE TABLE IF NOT EXISTS mall_cs_ticket (
id BIGSERIAL PRIMARY KEY, owner VARCHAR(200), order_no VARCHAR(40), category VARCHAR(60),
subject VARCHAR(300), content TEXT, status VARCHAR(20) DEFAULT 'OPEN',
itsm_sr_id VARCHAR(60), ai_reply TEXT, created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS mall_wishlist (
id BIGSERIAL PRIMARY KEY, owner VARCHAR(200) NOT NULL, product_id BIGINT NOT NULL,
created_at TIMESTAMP DEFAULT NOW(), UNIQUE(owner, product_id)
);
-- ---------------------------------------------------------------------------
-- 13. 프로모션 (기존 호환)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS mall_promotion (
id BIGSERIAL PRIMARY KEY, title VARCHAR(300), banner VARCHAR(600), description TEXT,
category_id BIGINT, start_date DATE, end_date DATE, active BOOLEAN DEFAULT TRUE
);
CREATE TABLE IF NOT EXISTS mall_coupon (
id BIGSERIAL PRIMARY KEY, code VARCHAR(60) UNIQUE, name VARCHAR(200),
discount_type VARCHAR(20) DEFAULT 'FIXED', discount_value NUMERIC(12,2),
min_order_amount NUMERIC(12,2) DEFAULT 0, max_discount NUMERIC(12,2),
valid_from DATE, valid_to DATE, issued_limit INTEGER, issued_count INTEGER DEFAULT 0,
active BOOLEAN DEFAULT TRUE
);
INSERT INTO mall_coupon (code, name, discount_type, discount_value, min_order_amount) VALUES
('WELCOME10','Welcome $10 Off','FIXED',10.00,50.00),
('SPRING15','Spring 15%','PERCENT',15.00,40.00)
ON CONFLICT (code) DO NOTHING;
-- ---------------------------------------------------------------------------
-- 14. 등급별 고객관리 (Loyalty) — 등급기준·등급별 혜택·포인트 원장
-- ---------------------------------------------------------------------------
-- 등급 기준(누적 구매액/주문수 임계). 자동 산정 시 12개월 누적값과 비교.
-- tier_code: BASIC / SILVER / GOLD / VIP (rank ASC = 낮은 등급)
CREATE TABLE IF NOT EXISTS mall_tier_benefit (
id BIGSERIAL PRIMARY KEY,
tier_code VARCHAR(20) UNIQUE NOT NULL, -- BASIC/SILVER/GOLD/VIP
name VARCHAR(80) NOT NULL,
tier_rank INTEGER NOT NULL, -- 1=BASIC ... 4=VIP
min_spend_12m NUMERIC(12,2) DEFAULT 0, -- 등급 진입 누적 구매액(12개월)
min_orders_12m INTEGER DEFAULT 0, -- 등급 진입 누적 주문수(12개월)
discount_rate NUMERIC(5,2) DEFAULT 0, -- 등급 할인율(%)
free_ship_threshold NUMERIC(12,2), -- 무료배송 임계액(NULL=없음, 0=항상 무료)
point_earn_rate NUMERIC(5,2) DEFAULT 1.0, -- 포인트 적립률(% of pay_amount)
priority_slot BOOLEAN DEFAULT FALSE, -- 피크시즌 우선 타임슬롯
birthday_coupon BOOLEAN DEFAULT FALSE, -- 생일 쿠폰/꽃
exclusive_events BOOLEAN DEFAULT FALSE, -- 전용 이벤트 접근
color VARCHAR(20), -- UI 배지 색상
active BOOLEAN DEFAULT TRUE, updated_at TIMESTAMP DEFAULT NOW()
);
INSERT INTO mall_tier_benefit
(tier_code, name, tier_rank, min_spend_12m, min_orders_12m, discount_rate, free_ship_threshold, point_earn_rate, priority_slot, birthday_coupon, exclusive_events, color) VALUES
('BASIC','일반 (Basic)', 1, 0.00, 0, 0.00, NULL, 1.0, FALSE, FALSE, FALSE, '#9CA3AF'),
('SILVER','실버 (Silver)',2, 300.00, 3, 3.00, 75.00, 1.5, FALSE, TRUE, FALSE, '#94A3B8'),
('GOLD','골드 (Gold)', 3, 1000.00, 8, 5.00, 50.00, 2.0, TRUE, TRUE, TRUE, '#D4AF37'),
('VIP','VIP', 4, 3000.00,20, 8.00, 0.00, 3.0, TRUE, TRUE, TRUE, '#7C3AED')
ON CONFLICT (tier_code) DO NOTHING;
-- 포인트 원장(ledger): 적립(EARN)/사용(USE)/만료(EXPIRE)/조정(ADJUST). 잔액=SUM(points).
CREATE TABLE IF NOT EXISTS mall_point_ledger (
id BIGSERIAL PRIMARY KEY, owner VARCHAR(200) NOT NULL,
entry_type VARCHAR(20) NOT NULL, -- EARN/USE/EXPIRE/ADJUST
points INTEGER NOT NULL, -- 적립 +, 사용/만료 -
order_no VARCHAR(40), reason VARCHAR(300),
expire_at DATE, -- 적립분 만료일(EARN)
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_mall_point_owner ON mall_point_ledger(owner);
-- ---------------------------------------------------------------------------
-- 15. 이벤트 / 캠페인 (Event)
-- ---------------------------------------------------------------------------
-- event_type: DISCOUNT/POINT_BONUS/GIFT/TIER_ONLY/SEASON
CREATE TABLE IF NOT EXISTS mall_event (
id BIGSERIAL PRIMARY KEY, code VARCHAR(60) UNIQUE, title VARCHAR(300) NOT NULL,
event_type VARCHAR(30) DEFAULT 'DISCOUNT',
description TEXT,
start_date DATE, end_date DATE,
target_tiers VARCHAR(120), -- 콤마구분 등급코드(빈값=전체) 예: 'GOLD,VIP'
store_ids VARCHAR(200), -- 콤마구분 매장ID(빈값=전 매장/권역)
coupon_id BIGINT, -- 연계 쿠폰(이벤트 참여 시 발급)
bonus_point_rate NUMERIC(5,2), -- POINT_BONUS 추가 적립률(%)
gift_description VARCHAR(300), -- GIFT 사은품 설명
status VARCHAR(20) DEFAULT 'DRAFT', -- DRAFT/PUBLISHED/ENDED
active BOOLEAN DEFAULT TRUE,
created_by VARCHAR(200), created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_mall_event_status ON mall_event(status);
-- 스토어프론트 배너(이미지/문구/링크)
CREATE TABLE IF NOT EXISTS mall_event_banner (
id BIGSERIAL PRIMARY KEY, event_id BIGINT NOT NULL,
image_url VARCHAR(600), headline VARCHAR(300), subtext VARCHAR(400),
link_url VARCHAR(600), sort_order INTEGER DEFAULT 0, active BOOLEAN DEFAULT TRUE
);
CREATE INDEX IF NOT EXISTS idx_mall_evtbanner_event ON mall_event_banner(event_id);
-- 이벤트 참여 이력(성과 집계용)
CREATE TABLE IF NOT EXISTS mall_event_participation (
id BIGSERIAL PRIMARY KEY, event_id BIGINT NOT NULL, owner VARCHAR(200) NOT NULL,
coupon_id BIGINT, order_no VARCHAR(40), reward VARCHAR(200),
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_mall_evtpart_event ON mall_event_participation(event_id);
-- 샘플 시즌 이벤트 시드 (밸런타인·어머니날)
INSERT INTO mall_event (id, code, title, event_type, description, start_date, end_date, target_tiers, coupon_id, bonus_point_rate, status, active, created_by) VALUES
(1,'VDAY2026','Valentine''s Day Bloom Sale','SEASON','Celebrate love with 15% off select bouquets.','2026-02-07','2026-02-14','', 2, NULL,'PUBLISHED',TRUE,'system'),
(2,'MDAY2026','Mother''s Day Special','SEASON','Honor Mom — bonus points + free delivery on Deluxe.','2026-05-03','2026-05-10','', NULL, 2.0,'PUBLISHED',TRUE,'system'),
(3,'VIPSPRING','VIP Spring Preview','TIER_ONLY','Exclusive early access for Gold & VIP members.','2026-03-01','2026-03-31','GOLD,VIP', NULL, NULL,'PUBLISHED',TRUE,'system')
ON CONFLICT (id) DO NOTHING;
SELECT setval(pg_get_serial_sequence('mall_event','id'), GREATEST((SELECT MAX(id) FROM mall_event),1));
INSERT INTO mall_event_banner (event_id, image_url, headline, subtext, link_url, sort_order) VALUES
(1,'/img/event-valentine.jpg','Valentine''s Day Bloom Sale','15% off romantic roses & more','/events/VDAY2026',1),
(2,'/img/event-mother.jpg','Mother''s Day Special','Bonus points + free delivery on Deluxe','/events/MDAY2026',1)
ON CONFLICT DO NOTHING;