CREATE TABLE user_totp ( did TEXT PRIMARY KEY REFERENCES users(did) ON DELETE CASCADE, secret_encrypted BYTEA NOT NULL, encryption_version INTEGER NOT NULL DEFAULT 1, verified BOOLEAN NOT NULL DEFAULT FALSE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), last_used TIMESTAMPTZ ); CREATE TABLE backup_codes ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), did TEXT NOT NULL REFERENCES users(did) ON DELETE CASCADE, code_hash TEXT NOT NULL, used_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX idx_backup_codes_did ON backup_codes(did); CREATE TABLE passkeys ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), did TEXT NOT NULL REFERENCES users(did) ON DELETE CASCADE, credential_id BYTEA NOT NULL UNIQUE, public_key BYTEA NOT NULL, sign_count INTEGER NOT NULL DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), last_used TIMESTAMPTZ, friendly_name TEXT, aaguid BYTEA, transports TEXT[] ); CREATE INDEX idx_passkeys_did ON passkeys(did); CREATE TABLE webauthn_challenges ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), did TEXT NOT NULL, challenge BYTEA NOT NULL, challenge_type TEXT NOT NULL, state_json TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), expires_at TIMESTAMPTZ NOT NULL ); CREATE INDEX idx_webauthn_challenges_did ON webauthn_challenges(did);