feat(convex): add full domain schema and snapshot sync bridge

This commit is contained in:
Codex
2026-02-18 15:06:53 +00:00
parent d1fbff481b
commit 489972c6dc
4 changed files with 970 additions and 2 deletions

View File

@@ -2,6 +2,127 @@ import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
export default defineSchema({
users: defineTable({
x_user_id: v.optional(v.string()),
username: v.optional(v.string()),
email: v.optional(v.string()),
created_at: v.string(),
updated_at: v.string(),
})
.index("by_x_user_id", ["x_user_id"])
.index("by_username", ["username"])
.index("by_email", ["email"]),
wallets: defineTable({
user_id: v.id("users"),
balance_credits: v.number(),
updated_at: v.string(),
}).index("by_user_id", ["user_id"]),
wallet_transactions: defineTable({
user_id: v.id("users"),
type: v.union(v.literal("credit"), v.literal("debit"), v.literal("refund")),
amount: v.number(),
reason: v.optional(v.string()),
idempotency_key: v.string(),
balance_after: v.number(),
created_at: v.string(),
})
.index("by_user_id", ["user_id"])
.index("by_idempotency_key", ["idempotency_key"]),
mention_events: defineTable({
mention_post_id: v.string(),
mention_author_id: v.string(),
parent_post_id: v.string(),
status: v.string(),
error_code: v.optional(v.string()),
created_at: v.string(),
updated_at: v.string(),
})
.index("by_mention_post_id", ["mention_post_id"])
.index("by_parent_post_id", ["parent_post_id"])
.index("by_mention_author_id", ["mention_author_id"]),
articles: defineTable({
x_article_id: v.optional(v.string()),
parent_post_id: v.string(),
author_id: v.optional(v.string()),
title: v.string(),
char_count: v.number(),
content_hash: v.optional(v.string()),
raw_content: v.optional(v.string()),
created_at: v.string(),
updated_at: v.string(),
})
.index("by_x_article_id", ["x_article_id"])
.index("by_parent_post_id", ["parent_post_id"])
.index("by_content_hash", ["content_hash"]),
audio_jobs: defineTable({
user_id: v.id("users"),
mention_event_id: v.optional(v.id("mention_events")),
article_id: v.id("articles"),
status: v.union(
v.literal("received"),
v.literal("validated"),
v.literal("priced"),
v.literal("charged"),
v.literal("synthesizing"),
v.literal("uploaded"),
v.literal("completed"),
v.literal("failed_refunded"),
v.literal("failed_not_refunded"),
),
credits_charged: v.number(),
tts_provider: v.optional(v.string()),
tts_model: v.optional(v.string()),
error: v.optional(v.string()),
asset_id: v.optional(v.id("audio_assets")),
created_at: v.string(),
updated_at: v.string(),
})
.index("by_user_id", ["user_id"])
.index("by_mention_event_id", ["mention_event_id"])
.index("by_article_id", ["article_id"])
.index("by_status", ["status"]),
audio_assets: defineTable({
job_id: v.id("audio_jobs"),
storage_key: v.optional(v.string()),
duration_sec: v.optional(v.number()),
size_bytes: v.optional(v.number()),
codec: v.optional(v.string()),
public_url_ttl: v.optional(v.number()),
deleted_at: v.optional(v.string()),
last_played_at: v.optional(v.string()),
created_at: v.string(),
updated_at: v.string(),
}).index("by_job_id", ["job_id"]),
audio_access_grants: defineTable({
audio_asset_id: v.id("audio_assets"),
user_id: v.id("users"),
granted_via: v.union(v.literal("owner"), v.literal("repurchase"), v.literal("admin")),
credits_paid: v.number(),
created_at: v.string(),
})
.index("by_audio_asset_id", ["audio_asset_id"])
.index("by_user_id", ["user_id"])
.index("by_asset_and_user", ["audio_asset_id", "user_id"]),
payment_events: defineTable({
provider: v.string(),
provider_event_id: v.string(),
status: v.string(),
payload_hash: v.optional(v.string()),
created_at: v.string(),
updated_at: v.string(),
})
.index("by_provider_event_id", ["provider_event_id"])
.index("by_provider_and_event", ["provider", "provider_event_id"]),
// Legacy compatibility table while runtime is still transitioning away from snapshot persistence.
state_snapshots: defineTable({
snapshot: v.any(),
updatedAt: v.string(),