597 lines
20 KiB
SQL
597 lines
20 KiB
SQL
-- AlphaX Agent PostgreSQL initial schema.
|
|
-- Keep column names compatible with the current SQLite data model.
|
|
|
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
version TEXT PRIMARY KEY,
|
|
applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS coin_state (
|
|
symbol TEXT PRIMARY KEY,
|
|
state TEXT NOT NULL DEFAULT '蓄力',
|
|
score INTEGER DEFAULT 0,
|
|
anomaly_type TEXT DEFAULT '',
|
|
sector TEXT DEFAULT '',
|
|
leader_status TEXT DEFAULT '',
|
|
detected_at TEXT NOT NULL,
|
|
last_alert_time TEXT DEFAULT '',
|
|
last_alert_level TEXT DEFAULT '',
|
|
detail_json TEXT DEFAULT '{}'
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS screening_log (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
scan_time TEXT NOT NULL,
|
|
layer TEXT NOT NULL,
|
|
symbol TEXT NOT NULL,
|
|
state TEXT NOT NULL,
|
|
score INTEGER DEFAULT 0,
|
|
price DOUBLE PRECISION NOT NULL,
|
|
signals TEXT DEFAULT '',
|
|
sector TEXT DEFAULT '',
|
|
leader_status TEXT DEFAULT '',
|
|
is_meme INTEGER DEFAULT 0,
|
|
change_24h DOUBLE PRECISION DEFAULT 0,
|
|
funding_rate DOUBLE PRECISION DEFAULT 0,
|
|
detail_json TEXT DEFAULT '{}'
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_screening_log_time ON screening_log(scan_time DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_screening_log_layer_time ON screening_log(layer, scan_time DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_screening_log_symbol_time ON screening_log(symbol, scan_time DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS recommendation (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
symbol TEXT NOT NULL,
|
|
rec_time TEXT NOT NULL,
|
|
rec_state TEXT NOT NULL,
|
|
rec_score INTEGER DEFAULT 0,
|
|
entry_price DOUBLE PRECISION NOT NULL,
|
|
stop_loss DOUBLE PRECISION DEFAULT 0,
|
|
tp1 DOUBLE PRECISION DEFAULT 0,
|
|
tp2 DOUBLE PRECISION DEFAULT 0,
|
|
sector TEXT DEFAULT '',
|
|
signals TEXT DEFAULT '',
|
|
is_meme INTEGER DEFAULT 0,
|
|
status TEXT DEFAULT 'active',
|
|
current_price DOUBLE PRECISION DEFAULT 0,
|
|
max_price DOUBLE PRECISION DEFAULT 0,
|
|
min_price DOUBLE PRECISION DEFAULT 0,
|
|
pnl_pct DOUBLE PRECISION DEFAULT 0,
|
|
max_pnl_pct DOUBLE PRECISION DEFAULT 0,
|
|
max_drawdown_pct DOUBLE PRECISION DEFAULT 0,
|
|
hit_tp1_time TEXT DEFAULT '',
|
|
hit_tp2_time TEXT DEFAULT '',
|
|
stopped_out_time TEXT DEFAULT '',
|
|
expired_time TEXT DEFAULT '',
|
|
last_track_time TEXT DEFAULT '',
|
|
entry_plan_json TEXT DEFAULT '{}',
|
|
action_status TEXT DEFAULT '持有',
|
|
strategy_version TEXT DEFAULT '',
|
|
direction TEXT DEFAULT '中性',
|
|
force_reason TEXT DEFAULT '',
|
|
base_state TEXT DEFAULT '',
|
|
sector_signal_count INTEGER DEFAULT 0,
|
|
market_context_json TEXT DEFAULT '{}',
|
|
derivatives_context_json TEXT DEFAULT '{}',
|
|
sector_context_json TEXT DEFAULT '{}',
|
|
lifecycle_state TEXT DEFAULT 'watching',
|
|
display_bucket TEXT DEFAULT 'watch_pool',
|
|
execution_status TEXT DEFAULT 'observe',
|
|
state_reason TEXT DEFAULT '',
|
|
entry_triggered INTEGER DEFAULT 0,
|
|
archived_at TEXT DEFAULT '',
|
|
signal_codes_json TEXT DEFAULT '[]',
|
|
signal_labels_json TEXT DEFAULT '[]',
|
|
opportunity_level TEXT DEFAULT '',
|
|
opportunity_level_label TEXT DEFAULT '',
|
|
holding_horizon TEXT DEFAULT '',
|
|
entry_model TEXT DEFAULT '',
|
|
stop_model TEXT DEFAULT '',
|
|
tp_model TEXT DEFAULT ''
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_rec_active_symbol_bucket ON recommendation(symbol, status, display_bucket, id DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_rec_display_bucket_time ON recommendation(display_bucket, rec_time DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_rec_symbol_time ON recommendation(symbol, rec_time DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_rec_opportunity_level_time ON recommendation(opportunity_level, rec_time DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS price_tracking (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
rec_id BIGINT NOT NULL,
|
|
symbol TEXT NOT NULL,
|
|
track_time TEXT NOT NULL,
|
|
price DOUBLE PRECISION NOT NULL,
|
|
pnl_pct DOUBLE PRECISION DEFAULT 0
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_price_tracking_rec_id_id ON price_tracking(rec_id, id DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_price_tracking_rec_time ON price_tracking(rec_id, track_time DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS latest_price_cache (
|
|
symbol TEXT PRIMARY KEY,
|
|
price DOUBLE PRECISION NOT NULL,
|
|
updated_at TEXT NOT NULL,
|
|
source TEXT DEFAULT 'tracker'
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_latest_price_cache_updated_at ON latest_price_cache(updated_at);
|
|
|
|
CREATE TABLE IF NOT EXISTS cron_run_log (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
job_name TEXT NOT NULL,
|
|
script_name TEXT NOT NULL,
|
|
run_status TEXT NOT NULL,
|
|
result_status TEXT DEFAULT '',
|
|
started_at TEXT NOT NULL,
|
|
finished_at TEXT NOT NULL,
|
|
duration_ms INTEGER DEFAULT 0,
|
|
summary_json TEXT DEFAULT '{}',
|
|
error_message TEXT DEFAULT ''
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_cron_run_log_job_started ON cron_run_log(job_name, started_at DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS signal_performance (
|
|
signal_type TEXT PRIMARY KEY,
|
|
category TEXT DEFAULT '',
|
|
total_count INTEGER DEFAULT 0,
|
|
hit_count INTEGER DEFAULT 0,
|
|
miss_count INTEGER DEFAULT 0,
|
|
hit_rate DOUBLE PRECISION DEFAULT 0,
|
|
avg_pnl DOUBLE PRECISION DEFAULT 0,
|
|
weight DOUBLE PRECISION DEFAULT 1.0,
|
|
last_updated TEXT DEFAULT ''
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS review_log (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
rec_id BIGINT NOT NULL,
|
|
symbol TEXT NOT NULL,
|
|
review_time TEXT NOT NULL,
|
|
outcome TEXT NOT NULL,
|
|
pnl_48h DOUBLE PRECISION DEFAULT 0,
|
|
max_pnl_48h DOUBLE PRECISION DEFAULT 0,
|
|
triggered_signals TEXT DEFAULT '',
|
|
hit_signals TEXT DEFAULT '',
|
|
miss_signals TEXT DEFAULT '',
|
|
lesson TEXT DEFAULT ''
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_review_log_rec_id ON review_log(rec_id);
|
|
CREATE INDEX IF NOT EXISTS idx_review_log_time ON review_log(review_time DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS missed_explosions (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
symbol TEXT NOT NULL,
|
|
detect_time TEXT NOT NULL,
|
|
price_at_detect DOUBLE PRECISION DEFAULT 0,
|
|
price_before DOUBLE PRECISION DEFAULT 0,
|
|
gain_pct DOUBLE PRECISION DEFAULT 0,
|
|
reason_missed TEXT DEFAULT '',
|
|
features_detected TEXT DEFAULT '',
|
|
lesson TEXT DEFAULT ''
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS strategy_iteration_log (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
run_date TEXT NOT NULL,
|
|
created_at TEXT NOT NULL,
|
|
trigger_source TEXT DEFAULT 'daily_review',
|
|
title TEXT NOT NULL,
|
|
summary TEXT DEFAULT '',
|
|
findings_json TEXT DEFAULT '[]',
|
|
problems_json TEXT DEFAULT '[]',
|
|
actions_json TEXT DEFAULT '[]',
|
|
changed_rules_json TEXT DEFAULT '[]',
|
|
metrics_json TEXT DEFAULT '{}',
|
|
related_symbols_json TEXT DEFAULT '[]',
|
|
config_diff_json TEXT DEFAULT '{}',
|
|
effect_summary_json TEXT DEFAULT '{}',
|
|
pollution_summary_json TEXT DEFAULT '{}',
|
|
strategy_version TEXT DEFAULT '',
|
|
version_change_summary TEXT DEFAULT '',
|
|
success_analysis_json TEXT DEFAULT '{}',
|
|
failure_analysis_json TEXT DEFAULT '{}',
|
|
candidate_rules_json TEXT DEFAULT '[]',
|
|
release_decision TEXT DEFAULT '',
|
|
release_reason TEXT DEFAULT '',
|
|
confidence_level TEXT DEFAULT '',
|
|
promotion_state TEXT DEFAULT 'research_only'
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS strategy_rule_candidate (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
created_at TEXT NOT NULL,
|
|
source TEXT DEFAULT '',
|
|
rule_type TEXT DEFAULT '',
|
|
signal_name TEXT DEFAULT '',
|
|
rule_description TEXT DEFAULT '',
|
|
support_count INTEGER DEFAULT 0,
|
|
success_count INTEGER DEFAULT 0,
|
|
fail_count INTEGER DEFAULT 0,
|
|
avg_pnl DOUBLE PRECISION DEFAULT 0,
|
|
max_gain DOUBLE PRECISION DEFAULT 0,
|
|
max_drawdown DOUBLE PRECISION DEFAULT 0,
|
|
confidence_score DOUBLE PRECISION DEFAULT 0,
|
|
sample_size INTEGER DEFAULT 0,
|
|
status TEXT DEFAULT 'candidate',
|
|
release_version TEXT DEFAULT '',
|
|
notes TEXT DEFAULT '',
|
|
source_ref TEXT DEFAULT ''
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_rule_candidate_status ON strategy_rule_candidate(status, created_at);
|
|
|
|
CREATE TABLE IF NOT EXISTS strategy_failure_pattern (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
created_at TEXT NOT NULL,
|
|
symbol TEXT NOT NULL,
|
|
version TEXT DEFAULT '',
|
|
failure_type TEXT DEFAULT '',
|
|
failure_reason TEXT DEFAULT '',
|
|
signal_combo TEXT DEFAULT '[]',
|
|
market_context_json TEXT DEFAULT '{}',
|
|
entry_quality_issue TEXT DEFAULT '',
|
|
pnl_pct DOUBLE PRECISION DEFAULT 0,
|
|
max_drawdown_pct DOUBLE PRECISION DEFAULT 0,
|
|
lesson TEXT DEFAULT ''
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_failure_pattern_type ON strategy_failure_pattern(failure_type, created_at);
|
|
|
|
CREATE TABLE IF NOT EXISTS push_log (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
symbol TEXT NOT NULL,
|
|
push_type TEXT NOT NULL,
|
|
action_status TEXT DEFAULT '',
|
|
pushed_at TEXT NOT NULL,
|
|
rec_id BIGINT DEFAULT 0
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_push_lookup ON push_log(symbol, push_type, pushed_at);
|
|
CREATE INDEX IF NOT EXISTS idx_push_log_rec_action ON push_log(rec_id, push_type, action_status, pushed_at);
|
|
|
|
CREATE TABLE IF NOT EXISTS sentiment_events (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
symbol TEXT NOT NULL,
|
|
name TEXT DEFAULT '',
|
|
source TEXT NOT NULL,
|
|
event_type TEXT NOT NULL,
|
|
trend_rank INTEGER DEFAULT 0,
|
|
trend_score INTEGER DEFAULT 0,
|
|
market_cap_rank INTEGER DEFAULT 0,
|
|
extra_json TEXT DEFAULT '{}',
|
|
detected_at TEXT NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_sentiment_lookup ON sentiment_events(symbol, source, detected_at);
|
|
|
|
CREATE TABLE IF NOT EXISTS llm_insights (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
target_type TEXT NOT NULL,
|
|
target_id TEXT NOT NULL,
|
|
insight_type TEXT NOT NULL,
|
|
prompt_version TEXT NOT NULL,
|
|
input_hash TEXT NOT NULL,
|
|
status TEXT NOT NULL DEFAULT 'success',
|
|
input_json TEXT DEFAULT '{}',
|
|
content_json TEXT DEFAULT '{}',
|
|
error TEXT DEFAULT '',
|
|
model TEXT DEFAULT '',
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_llm_insights_unique
|
|
ON llm_insights(target_type, target_id, insight_type, input_hash);
|
|
CREATE INDEX IF NOT EXISTS idx_llm_insights_lookup
|
|
ON llm_insights(target_type, target_id, insight_type, status, updated_at);
|
|
|
|
CREATE TABLE IF NOT EXISTS event_news (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
event_hash TEXT UNIQUE,
|
|
source TEXT NOT NULL,
|
|
symbol TEXT NOT NULL,
|
|
title TEXT NOT NULL,
|
|
url TEXT DEFAULT '',
|
|
published_at TEXT NOT NULL,
|
|
detected_at TEXT NOT NULL,
|
|
importance TEXT DEFAULT 'B',
|
|
event_type TEXT DEFAULT '',
|
|
raw_json TEXT DEFAULT '{}',
|
|
processed INTEGER DEFAULT 0,
|
|
decision TEXT DEFAULT '',
|
|
tech_score INTEGER DEFAULT 0,
|
|
rec_id BIGINT DEFAULT 0,
|
|
pushed INTEGER DEFAULT 0
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_event_news_time ON event_news(published_at, detected_at);
|
|
CREATE INDEX IF NOT EXISTS idx_event_news_symbol ON event_news(symbol);
|
|
|
|
CREATE TABLE IF NOT EXISTS onchain_token_map (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
symbol TEXT NOT NULL,
|
|
chain TEXT NOT NULL,
|
|
contract_address TEXT NOT NULL,
|
|
source TEXT DEFAULT '',
|
|
confidence INTEGER DEFAULT 0,
|
|
is_active INTEGER DEFAULT 1,
|
|
raw_json TEXT DEFAULT '{}',
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL,
|
|
UNIQUE(symbol, chain, contract_address)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_onchain_token_map_symbol ON onchain_token_map(symbol, confidence, is_active);
|
|
|
|
CREATE TABLE IF NOT EXISTS onchain_events (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
event_hash TEXT UNIQUE,
|
|
chain TEXT NOT NULL,
|
|
symbol TEXT NOT NULL,
|
|
contract_address TEXT DEFAULT '',
|
|
event_type TEXT NOT NULL,
|
|
signal_code TEXT NOT NULL,
|
|
signal_label TEXT DEFAULT '',
|
|
direction TEXT DEFAULT 'neutral',
|
|
value_usd DOUBLE PRECISION DEFAULT 0,
|
|
amount DOUBLE PRECISION DEFAULT 0,
|
|
tx_hash TEXT DEFAULT '',
|
|
wallet_address TEXT DEFAULT '',
|
|
wallet_label TEXT DEFAULT '',
|
|
counterparty_label TEXT DEFAULT '',
|
|
confidence INTEGER DEFAULT 0,
|
|
severity TEXT DEFAULT 'B',
|
|
status TEXT DEFAULT 'new',
|
|
detected_at TEXT NOT NULL,
|
|
source TEXT DEFAULT '',
|
|
url TEXT DEFAULT '',
|
|
raw_json TEXT DEFAULT '{}'
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_onchain_events_time ON onchain_events(detected_at, signal_code);
|
|
CREATE INDEX IF NOT EXISTS idx_onchain_events_symbol ON onchain_events(symbol, detected_at);
|
|
CREATE INDEX IF NOT EXISTS idx_onchain_events_chain ON onchain_events(chain, detected_at);
|
|
|
|
CREATE TABLE IF NOT EXISTS onchain_token_metrics (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
symbol TEXT NOT NULL,
|
|
chain TEXT NOT NULL,
|
|
contract_address TEXT DEFAULT '',
|
|
"window" TEXT NOT NULL,
|
|
metric_time TEXT NOT NULL,
|
|
dex_volume_usd DOUBLE PRECISION DEFAULT 0,
|
|
dex_volume_change_pct DOUBLE PRECISION DEFAULT 0,
|
|
liquidity_usd DOUBLE PRECISION DEFAULT 0,
|
|
liquidity_change_pct DOUBLE PRECISION DEFAULT 0,
|
|
exchange_netflow_usd DOUBLE PRECISION DEFAULT 0,
|
|
whale_accumulation_usd DOUBLE PRECISION DEFAULT 0,
|
|
holder_delta DOUBLE PRECISION DEFAULT 0,
|
|
smart_money_score DOUBLE PRECISION DEFAULT 0,
|
|
onchain_score DOUBLE PRECISION DEFAULT 0,
|
|
risk_score DOUBLE PRECISION DEFAULT 0,
|
|
source TEXT DEFAULT '',
|
|
raw_json TEXT DEFAULT '{}',
|
|
UNIQUE(symbol, chain, contract_address, "window", metric_time)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_onchain_metrics_symbol ON onchain_token_metrics(symbol, metric_time);
|
|
|
|
CREATE TABLE IF NOT EXISTS onchain_raw_events (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
event_hash TEXT UNIQUE,
|
|
source TEXT NOT NULL,
|
|
chain TEXT NOT NULL,
|
|
event_type TEXT NOT NULL,
|
|
token_address TEXT DEFAULT '',
|
|
symbol_guess TEXT DEFAULT '',
|
|
name TEXT DEFAULT '',
|
|
title TEXT DEFAULT '',
|
|
description TEXT DEFAULT '',
|
|
url TEXT DEFAULT '',
|
|
icon TEXT DEFAULT '',
|
|
amount DOUBLE PRECISION DEFAULT 0,
|
|
total_amount DOUBLE PRECISION DEFAULT 0,
|
|
importance DOUBLE PRECISION DEFAULT 0,
|
|
mapped_symbol TEXT DEFAULT '',
|
|
mapping_status TEXT DEFAULT 'unmapped',
|
|
detected_at TEXT NOT NULL,
|
|
raw_json TEXT DEFAULT '{}'
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_onchain_raw_events_time ON onchain_raw_events(detected_at, importance);
|
|
CREATE INDEX IF NOT EXISTS idx_onchain_raw_events_chain ON onchain_raw_events(chain, detected_at);
|
|
CREATE INDEX IF NOT EXISTS idx_onchain_raw_events_mapping ON onchain_raw_events(mapping_status, detected_at);
|
|
|
|
CREATE TABLE IF NOT EXISTS app_user (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
email TEXT NOT NULL UNIQUE,
|
|
password_hash TEXT NOT NULL,
|
|
password_salt TEXT NOT NULL,
|
|
email_verified INTEGER DEFAULT 0,
|
|
status TEXT DEFAULT 'pending_email_verification',
|
|
invite_code TEXT NOT NULL UNIQUE,
|
|
invited_by_user_id BIGINT,
|
|
free_trial_claimed INTEGER DEFAULT 0,
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL,
|
|
last_login_at TEXT DEFAULT '',
|
|
is_admin INTEGER DEFAULT 0
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_app_user_email ON app_user(email);
|
|
CREATE INDEX IF NOT EXISTS idx_app_user_invite_code ON app_user(invite_code);
|
|
|
|
CREATE TABLE IF NOT EXISTS email_verification_code (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
user_id BIGINT NOT NULL,
|
|
email TEXT NOT NULL,
|
|
code_hash TEXT NOT NULL,
|
|
purpose TEXT NOT NULL DEFAULT 'register',
|
|
expires_at TEXT NOT NULL,
|
|
used_at TEXT DEFAULT '',
|
|
created_at TEXT NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_email_code_lookup ON email_verification_code(email, purpose, used_at);
|
|
|
|
CREATE TABLE IF NOT EXISTS user_session (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
user_id BIGINT NOT NULL,
|
|
token_hash TEXT NOT NULL UNIQUE,
|
|
created_at TEXT NOT NULL,
|
|
expires_at TEXT NOT NULL,
|
|
revoked_at TEXT DEFAULT ''
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_user_session_token ON user_session(token_hash);
|
|
|
|
CREATE TABLE IF NOT EXISTS subscription_plan (
|
|
code TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
duration_days INTEGER NOT NULL,
|
|
price_usdt DOUBLE PRECISION DEFAULT 0,
|
|
status TEXT DEFAULT 'active',
|
|
sort_order INTEGER DEFAULT 0,
|
|
created_at TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS user_subscription (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
user_id BIGINT NOT NULL,
|
|
plan_code TEXT NOT NULL,
|
|
start_at TEXT NOT NULL,
|
|
end_at TEXT NOT NULL,
|
|
status TEXT DEFAULT 'active',
|
|
source TEXT NOT NULL,
|
|
order_id BIGINT,
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_user_subscription_user ON user_subscription(user_id, status, end_at);
|
|
|
|
CREATE TABLE IF NOT EXISTS payment_order (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
user_id BIGINT NOT NULL,
|
|
plan_code TEXT NOT NULL,
|
|
amount_usdt DOUBLE PRECISION NOT NULL DEFAULT 0,
|
|
chain TEXT NOT NULL DEFAULT 'TRC20',
|
|
pay_address TEXT DEFAULT '',
|
|
txid TEXT DEFAULT '',
|
|
status TEXT NOT NULL DEFAULT 'pending',
|
|
created_at TEXT NOT NULL,
|
|
paid_at TEXT DEFAULT '',
|
|
expire_at TEXT DEFAULT '',
|
|
admin_note TEXT DEFAULT '',
|
|
raw_payload_json TEXT DEFAULT '{}'
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_payment_order_user ON payment_order(user_id, status);
|
|
CREATE INDEX IF NOT EXISTS idx_payment_order_txid ON payment_order(txid);
|
|
CREATE INDEX IF NOT EXISTS idx_payment_order_created ON payment_order(created_at);
|
|
|
|
CREATE TABLE IF NOT EXISTS pending_registration (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
email TEXT NOT NULL,
|
|
code_hash TEXT NOT NULL,
|
|
expires_at TEXT NOT NULL,
|
|
used_at TEXT DEFAULT '',
|
|
created_at TEXT NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_pending_reg_email ON pending_registration(email, used_at);
|
|
|
|
CREATE TABLE IF NOT EXISTS referral_reward (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
inviter_user_id BIGINT NOT NULL,
|
|
invitee_user_id BIGINT NOT NULL,
|
|
order_id BIGINT,
|
|
reward_type TEXT NOT NULL DEFAULT 'days',
|
|
reward_days INTEGER DEFAULT 0,
|
|
reward_amount_usdt DOUBLE PRECISION DEFAULT 0,
|
|
status TEXT DEFAULT 'pending',
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS user_activity (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
user_id BIGINT NOT NULL,
|
|
action TEXT NOT NULL,
|
|
page TEXT DEFAULT '',
|
|
ip TEXT DEFAULT '',
|
|
created_at TEXT NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_ua_user ON user_activity(user_id, created_at);
|
|
CREATE INDEX IF NOT EXISTS idx_ua_date ON user_activity(created_at);
|
|
|
|
CREATE TABLE IF NOT EXISTS user_watchlist (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
user_id BIGINT NOT NULL,
|
|
symbol TEXT NOT NULL,
|
|
created_at TEXT NOT NULL,
|
|
UNIQUE(user_id, symbol)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_user_watchlist_user ON user_watchlist(user_id, symbol);
|
|
|
|
CREATE TABLE IF NOT EXISTS user_saved_observation (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
user_id BIGINT NOT NULL,
|
|
rec_id BIGINT NOT NULL,
|
|
note TEXT DEFAULT '',
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL,
|
|
UNIQUE(user_id, rec_id)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_saved_obs_user ON user_saved_observation(user_id, rec_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS user_push_rule (
|
|
user_id BIGINT PRIMARY KEY,
|
|
watchlist_only INTEGER DEFAULT 0,
|
|
min_score INTEGER DEFAULT 0,
|
|
min_rr DOUBLE PRECISION DEFAULT 0,
|
|
push_buy_now INTEGER DEFAULT 1,
|
|
push_wait_pullback INTEGER DEFAULT 1,
|
|
push_observe INTEGER DEFAULT 0,
|
|
quiet_start TEXT DEFAULT '',
|
|
quiet_end TEXT DEFAULT '',
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS system_reset_log (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
reset_at TEXT NOT NULL,
|
|
reason TEXT DEFAULT '',
|
|
backup_path TEXT DEFAULT '',
|
|
counts_json TEXT DEFAULT '{}'
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_system_reset_log_time ON system_reset_log(reset_at DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS scheduler_job_config (
|
|
job_name TEXT PRIMARY KEY,
|
|
command TEXT NOT NULL,
|
|
args_json TEXT DEFAULT '[]',
|
|
enabled INTEGER DEFAULT 1,
|
|
every_seconds INTEGER NOT NULL,
|
|
initial_delay INTEGER DEFAULT 0,
|
|
lock_group TEXT DEFAULT '',
|
|
description TEXT DEFAULT '',
|
|
sort_order INTEGER DEFAULT 0,
|
|
created_at TEXT NOT NULL,
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS scheduler_runtime_status (
|
|
job_name TEXT PRIMARY KEY,
|
|
status TEXT DEFAULT 'idle',
|
|
pid INTEGER DEFAULT 0,
|
|
run_kind TEXT DEFAULT '',
|
|
trigger_id BIGINT DEFAULT 0,
|
|
locked_by TEXT DEFAULT '',
|
|
next_run_at TEXT DEFAULT '',
|
|
last_started_at TEXT DEFAULT '',
|
|
last_finished_at TEXT DEFAULT '',
|
|
last_exit_code INTEGER DEFAULT 0,
|
|
last_duration_ms INTEGER DEFAULT 0,
|
|
last_error TEXT DEFAULT '',
|
|
output_tail TEXT DEFAULT '',
|
|
updated_at TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS scheduler_manual_trigger (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
job_name TEXT NOT NULL,
|
|
force INTEGER DEFAULT 0,
|
|
status TEXT DEFAULT 'queued',
|
|
requested_by TEXT DEFAULT '',
|
|
requested_at TEXT NOT NULL,
|
|
started_at TEXT DEFAULT '',
|
|
finished_at TEXT DEFAULT '',
|
|
exit_code INTEGER DEFAULT 0,
|
|
duration_ms INTEGER DEFAULT 0,
|
|
output_tail TEXT DEFAULT '',
|
|
error_message TEXT DEFAULT ''
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_scheduler_trigger_status ON scheduler_manual_trigger(status, requested_at);
|