-- SQLite 마일리지 데이터베이스 스키마 -- pharmacy-pos-qr-system/backend/db/mileage_schema.sql -- 1. 사용자 테이블 (카카오 로그인 계정) CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, nickname VARCHAR(100), profile_image_url VARCHAR(500), email VARCHAR(200), is_email_verified BOOLEAN DEFAULT FALSE, phone VARCHAR(20), birthday VARCHAR(10), mileage_balance INTEGER DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 2. 외부 로그인 매핑 테이블 CREATE TABLE IF NOT EXISTS customer_identities ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, provider VARCHAR(20) NOT NULL, provider_user_id VARCHAR(100) NOT NULL, provider_data TEXT, access_token TEXT, refresh_token TEXT, token_expires_at DATETIME, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id), UNIQUE(provider, provider_user_id) ); CREATE INDEX IF NOT EXISTS idx_identities_user ON customer_identities(user_id); -- 3. 영수증 QR 토큰 테이블 CREATE TABLE IF NOT EXISTS claim_tokens ( id INTEGER PRIMARY KEY AUTOINCREMENT, transaction_id VARCHAR(20) NOT NULL, pharmacy_id VARCHAR(20), token_hash VARCHAR(64) NOT NULL, total_amount INTEGER NOT NULL, claimable_points INTEGER NOT NULL, expires_at DATETIME NOT NULL, claimed_at DATETIME, claimed_by_user_id INTEGER, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (claimed_by_user_id) REFERENCES users(id), UNIQUE(transaction_id), UNIQUE(token_hash) ); CREATE INDEX IF NOT EXISTS idx_tokens_hash ON claim_tokens(token_hash); CREATE INDEX IF NOT EXISTS idx_tokens_expires ON claim_tokens(expires_at); -- 4. 마일리지 원장 테이블 CREATE TABLE IF NOT EXISTS mileage_ledger ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, transaction_id VARCHAR(20), points INTEGER NOT NULL, balance_after INTEGER NOT NULL, reason VARCHAR(50) NOT NULL, description TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id), UNIQUE(transaction_id) ); CREATE INDEX IF NOT EXISTS idx_ledger_user ON mileage_ledger(user_id); CREATE INDEX IF NOT EXISTS idx_ledger_transaction ON mileage_ledger(transaction_id); -- 5. POS 고객 연결 테이블 CREATE TABLE IF NOT EXISTS pos_customer_links ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, pharmacy_id VARCHAR(20), cuscode VARCHAR(10), customer_name VARCHAR(50), linked_at DATETIME DEFAULT CURRENT_TIMESTAMP, is_active BOOLEAN DEFAULT TRUE, FOREIGN KEY (user_id) REFERENCES users(id), UNIQUE(user_id, pharmacy_id) ); CREATE INDEX IF NOT EXISTS idx_links_cuscode ON pos_customer_links(cuscode); -- 6. 알림톡 발송 로그 테이블 CREATE TABLE IF NOT EXISTS alimtalk_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, template_code VARCHAR(50) NOT NULL, recipient_no VARCHAR(20) NOT NULL, user_id INTEGER, trigger_source VARCHAR(20) NOT NULL, -- 'kiosk', 'admin', 'manual' 등 template_params TEXT, -- JSON 문자열 success BOOLEAN NOT NULL, result_message TEXT, transaction_id VARCHAR(20), created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ); CREATE INDEX IF NOT EXISTS idx_alimtalk_created ON alimtalk_logs(created_at); CREATE INDEX IF NOT EXISTS idx_alimtalk_recipient ON alimtalk_logs(recipient_no); -- 7. AI 추천 테이블 CREATE TABLE IF NOT EXISTS ai_recommendations ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, transaction_id VARCHAR(20), recommended_product TEXT NOT NULL, recommendation_message TEXT NOT NULL, recommendation_reason TEXT, trigger_products TEXT, ai_raw_response TEXT, status VARCHAR(20) DEFAULT 'active', displayed_count INTEGER DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, expires_at DATETIME, displayed_at DATETIME, dismissed_at DATETIME, FOREIGN KEY (user_id) REFERENCES users(id) ); CREATE INDEX IF NOT EXISTS idx_rec_user_status ON ai_recommendations(user_id, status); CREATE INDEX IF NOT EXISTS idx_rec_expires ON ai_recommendations(expires_at); -- 8. 반려동물 테이블 CREATE TABLE IF NOT EXISTS pets ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, name VARCHAR(50) NOT NULL, -- 이름 (예: 뽀삐, 나비) species VARCHAR(20) NOT NULL, -- 종류: dog, cat, other breed VARCHAR(50), -- 품종 (말티즈, 페르시안 등) gender VARCHAR(10), -- male, female, unknown birth_date DATE, -- 생년월일 (나중에 사용) age_months INTEGER, -- 월령 (나중에 사용) weight DECIMAL(5,2), -- 체중 kg (나중에 사용) photo_url TEXT, -- 사진 URL notes TEXT, -- 특이사항/메모 is_active BOOLEAN DEFAULT TRUE, -- 활성 상태 created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ); CREATE INDEX IF NOT EXISTS idx_pets_user ON pets(user_id); CREATE INDEX IF NOT EXISTS idx_pets_species ON pets(species); -- 9. OTC 용법 라벨 테이블 (바코드 기준 오버라이드 데이터) CREATE TABLE IF NOT EXISTS otc_label_presets ( id INTEGER PRIMARY KEY AUTOINCREMENT, barcode VARCHAR(20) NOT NULL UNIQUE, -- 바코드 (PK 역할) drug_code VARCHAR(20), -- MSSQL DrugCode (참조용) display_name VARCHAR(100), -- 표시 이름 (오버라이드, NULL이면 MSSQL 이름 사용) effect VARCHAR(100), -- 효능 (예: "치통, 두통") dosage_instruction TEXT, -- 용법 (예: "1일 3회, 1회 1정, 식후 30분") usage_tip TEXT, -- 부가 설명 (예: "[통증 시에만 복용]") use_wide_format BOOLEAN DEFAULT TRUE, -- 와이드 포맷 사용 여부 print_count INTEGER DEFAULT 0, -- 인쇄 횟수 (통계용) last_printed_at DATETIME, -- 마지막 인쇄 시간 created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX IF NOT EXISTS idx_otc_label_barcode ON otc_label_presets(barcode); CREATE INDEX IF NOT EXISTS idx_otc_label_drug_code ON otc_label_presets(drug_code);