Prepare secure config and reliable workout sync
This commit is contained in:
+96
-6
@@ -10,14 +10,17 @@ USE fitness_app;
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
uuid CHAR(36) UNIQUE NOT NULL COMMENT 'Unique identifier for the user',
|
||||
username VARCHAR(50) UNIQUE NOT NULL,
|
||||
email VARCHAR(100) UNIQUE NOT NULL,
|
||||
password_hash VARCHAR(255) NOT NULL COMMENT 'bcrypt hash',
|
||||
api_key VARCHAR(64) UNIQUE NOT NULL COMMENT 'API key for client authentication',
|
||||
api_secret VARCHAR(64) NOT NULL COMMENT 'Secret for HMAC signature',
|
||||
phone_e164 VARCHAR(16) UNIQUE COMMENT 'Verified phone number in E.164 format',
|
||||
phone_verified_at DATETIME NULL,
|
||||
username VARCHAR(50) UNIQUE,
|
||||
email VARCHAR(100) UNIQUE,
|
||||
password_hash VARCHAR(255) NULL COMMENT 'Optional legacy password hash',
|
||||
api_key VARCHAR(64) UNIQUE COMMENT 'Optional legacy API key',
|
||||
api_secret VARCHAR(64) NULL COMMENT 'Optional legacy HMAC secret',
|
||||
full_name VARCHAR(100),
|
||||
avatar_url VARCHAR(255),
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
account_role ENUM('member', 'owner', 'content_manager', 'support') NOT NULL DEFAULT 'member',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_uuid (uuid),
|
||||
@@ -25,11 +28,97 @@ CREATE TABLE IF NOT EXISTS users (
|
||||
INDEX idx_created_at (created_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE app_settings (
|
||||
setting_key VARCHAR(100) PRIMARY KEY,
|
||||
setting_value JSON NOT NULL,
|
||||
is_public BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
revision BIGINT UNSIGNED NOT NULL DEFAULT 1,
|
||||
updated_by INT NULL,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_settings_public (is_public, setting_key),
|
||||
CONSTRAINT fk_settings_editor FOREIGN KEY (updated_by) REFERENCES users(id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE app_setting_audit (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
setting_key VARCHAR(100) NOT NULL,
|
||||
previous_value JSON NULL,
|
||||
new_value JSON NOT NULL,
|
||||
actor_user_id INT NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_settings_audit_key_time (setting_key, created_at),
|
||||
INDEX idx_settings_audit_actor_time (actor_user_id, created_at),
|
||||
CONSTRAINT fk_settings_audit_actor FOREIGN KEY (actor_user_id) REFERENCES users(id) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Phone OTP challenges contain keyed digests, never the plaintext code.
|
||||
CREATE TABLE otp_challenges (
|
||||
challenge_uuid CHAR(36) PRIMARY KEY,
|
||||
phone_e164 VARCHAR(16) NOT NULL,
|
||||
purpose ENUM('register', 'login', 'change_phone') NOT NULL,
|
||||
code_digest CHAR(64) NOT NULL,
|
||||
attempt_count TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
max_attempts TINYINT UNSIGNED NOT NULL DEFAULT 5,
|
||||
request_ip_digest CHAR(64) NULL,
|
||||
device_uuid CHAR(36) NULL,
|
||||
expires_at DATETIME NOT NULL,
|
||||
consumed_at DATETIME NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
INDEX idx_otp_phone_created (phone_e164, created_at),
|
||||
INDEX idx_otp_expiry (expires_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE auth_rate_limit_buckets (
|
||||
bucket_digest CHAR(64) PRIMARY KEY,
|
||||
bucket_type ENUM('phone', 'ip', 'device') NOT NULL,
|
||||
window_started_at DATETIME NOT NULL,
|
||||
request_count INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
blocked_until DATETIME NULL,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX idx_rate_bucket_expiry (updated_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE user_devices (
|
||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
device_uuid CHAR(36) NOT NULL,
|
||||
platform ENUM('ios', 'android', 'web') NOT NULL,
|
||||
public_key TEXT NULL,
|
||||
key_fingerprint CHAR(64) NULL UNIQUE,
|
||||
key_algorithm VARCHAR(32) NULL,
|
||||
display_name VARCHAR(80) NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
last_seen_at DATETIME NULL,
|
||||
revoked_at DATETIME NULL,
|
||||
UNIQUE KEY uq_device_user_uuid (user_id, device_uuid),
|
||||
INDEX idx_devices_user_active (user_id, revoked_at),
|
||||
CONSTRAINT fk_devices_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE auth_sessions (
|
||||
session_uuid CHAR(36) PRIMARY KEY,
|
||||
family_uuid CHAR(36) NOT NULL,
|
||||
user_id INT NOT NULL,
|
||||
device_uuid CHAR(36) NULL,
|
||||
refresh_token_digest CHAR(64) NOT NULL UNIQUE,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
last_used_at DATETIME NULL,
|
||||
expires_at DATETIME NOT NULL,
|
||||
revoked_at DATETIME NULL,
|
||||
replaced_by CHAR(36) NULL,
|
||||
INDEX idx_sessions_user_active (user_id, revoked_at, expires_at),
|
||||
INDEX idx_sessions_family (family_uuid),
|
||||
CONSTRAINT fk_sessions_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_sessions_device FOREIGN KEY (user_id, device_uuid)
|
||||
REFERENCES user_devices(user_id, device_uuid) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Workouts Table
|
||||
CREATE TABLE IF NOT EXISTS workouts (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
workout_uuid CHAR(36) UNIQUE NOT NULL COMMENT 'Unique identifier for the workout',
|
||||
user_id INT NOT NULL,
|
||||
client_workout_uuid CHAR(36) NULL COMMENT 'Client-generated idempotency key',
|
||||
workout_type ENUM('running', 'walking') NOT NULL,
|
||||
distance_meters INT NOT NULL COMMENT 'Total distance in meters',
|
||||
duration_seconds INT NOT NULL COMMENT 'Total duration in seconds',
|
||||
@@ -59,7 +148,8 @@ CREATE TABLE IF NOT EXISTS workouts (
|
||||
INDEX idx_workout_type (workout_type),
|
||||
INDEX idx_synced_at (synced_at),
|
||||
INDEX idx_created_at (created_at),
|
||||
INDEX idx_user_created (user_id, created_at)
|
||||
INDEX idx_user_created (user_id, created_at),
|
||||
UNIQUE KEY uq_user_client_workout (user_id, client_workout_uuid)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Workout Segments Table (for detailed route tracking if needed)
|
||||
|
||||
Reference in New Issue
Block a user