# Technical Design Document # 绘境AI生态平台MVP Technical Design Document ## Product Overview Context for the technical design. 本技术设计文档面向将要实现绘境AI生态平台MVP的工程团队,基于现有PRD目标,将“一句话AI生成轻量小游戏、游戏流即点即玩、创作者发布与基础数据反馈、运营审核与推荐管理”落地为可实施的系统架构、数据模型、接口设计、测试方案和部署方案。 MVP技术策略采用“模板约束生成 + Web运行容器 + 异步任务队列 + 规则推荐”的方案,优先保障端到端闭环稳定性,而不是追求完全开放式代码生成。生成结果以配置化游戏工程为主,通过统一运行时容器在Web端加载运行,便于性能控制、内容审核、埋点采集和后续扩展。 ### Purpose - 解决的问题 - 非技术创作者无法将游戏创意快速转化为可试玩作品。 - 玩家发现轻量小游戏成本高,传统游戏分发依赖下载、安装和复杂选择。 - 平台早期需要验证AI创作供给、游戏流消费和数据反馈是否能形成生态闭环。 - 技术机会 - 使用大模型理解自然语言Prompt,并映射到受控玩法模板和参数配置。 - 使用Web小游戏运行容器实现即点即玩,降低分发门槛。 - 使用事件埋点和内容质量信号,为后续推荐和商业化提供数据基础。 - 使用内容安全检测与审核后台,降低UGC和AI生成内容的合规风险。 - 典型用户场景 - 创作者输入“做一个像素风太空躲避游戏,飞船躲避陨石并收集能量,坚持60秒获胜”,系统生成可预览小游戏,并允许编辑标题、封面和发布。 - 玩家进入首页后像刷短视频一样上下滑动试玩小游戏,支持点赞、收藏、分享和举报。 - 运营人员进入后台审核新发布游戏,试玩后执行通过、拒绝、下架或加入精选池。 - 团队通过数据看板查看生成成功率、游戏加载时间、试玩转化、互动率和举报率。 ### Target Audience - 普通创作者 / 非技术用户 - 需求:无需编程、美术和引擎知识即可生成可玩游戏。 - 技术支持:Prompt输入、模板选择、异步生成进度、浏览器预览、保存草稿、发布到站内游戏流。 - 进阶UGC创作者 / 游戏达人 - 需求:快速批量产出轻量小游戏,观察数据并优化标题、封面、规则和标签。 - 技术支持:模板参数可调、版本覆盖更新、基础数据看板、分享链接和渠道参数。 - 玩家 / 轻量游戏消费者 - 需求:无需下载,低决策成本连续发现和试玩小游戏。 - 技术支持:移动优先游戏流、资源预加载、CDN加速、错误自动跳过、互动反馈。 - 平台运营人员 - 需求:控制内容质量、安全合规和冷启动推荐效果。 - 技术支持:审核队列、试玩预览、风险标记、精选池、曝光限制和操作日志。 - 系统管理员 / 工程团队 - 需求:监控生成任务、运行错误、服务健康度、权限边界和安全风险。 - 技术支持:结构化日志、指标看板、告警、RBAC、审计日志和回滚机制。 ### Expected Outcomes - 短期业务结果 - MVP上线后8周内支持500名注册创作者。 - 至少100名创作者完成1款游戏发布。 - 累计上线300款可试玩小游戏。 - 玩家单次会话平均试玩不少于3款游戏。 - 技术结果 - 生成任务成功率不低于85%。 - 平台核心链路可用性不低于99%。 - 游戏流首屏可交互时间P75低于3秒,P95低于6秒。 - 游戏加载或运行阻断性错误率低于3%。 - 核心事件上报成功率不低于99%。 - 长期影响 - 为后续可视化编辑器、个性化推荐、广告分成、多渠道自动发布和素材市场建立可扩展架构。 - 沉淀Prompt、模板参数、互动行为和内容质量数据,用于优化生成质量和推荐策略。 ## Architecture The structural design of the system. ### High-Level Architecture - 推荐技术栈 - Frontend:Next.js 14、React、TypeScript、Tailwind CSS、Zustand、React Query。 - Game Runtime:Phaser 3 + 自研Game SDK桥接层,优先支持2D轻量小游戏。 - Backend:NestJS、TypeScript、REST API,按模块化单体起步,预留服务拆分边界。 - Database:PostgreSQL 15,使用Prisma ORM管理Schema和Migration。 - Cache / Queue:Redis 7,BullMQ用于异步生成、审核、资源打包、事件聚合任务。 - Object Storage:阿里云OSS或AWS S3,存储封面、上传素材、生成素材和游戏包。 - CDN:阿里云CDN、CloudFront或Cloudflare,用于游戏资源、封面图和静态前端加速。 - Search / Analytics MVP:PostgreSQL聚合表 + ClickHouse可选;MVP先用PostgreSQL分区事件表,增长后迁移ClickHouse。 - Auth:JWT + Refresh Token,匿名游客使用anonymous_id Cookie / localStorage标识。 - Observability:OpenTelemetry、Prometheus、Grafana、Sentry、Loki或云日志服务。 - 主要组件 - Web App - 创作工作台:Prompt输入、模板选择、生成状态、预览、发布。 - 玩家游戏流:游戏卡片、预加载、滑动切换、互动、举报。 - 创作者后台:我的游戏、数据概览、草稿和发布状态。 - 运营后台:审核、试玩、推荐池、下架、用户权限。 - API Server - 账号与权限模块。 - 游戏与版本管理模块。 - 生成任务模块。 - 发布与审核模块。 - 游戏流推荐模块。 - 互动与埋点模块。 - 文件上传与资源签名模块。 - Generation Worker - 接收Prompt生成任务。 - 调用LLM解析游戏意图。 - 选择玩法模板并生成GameConfig。 - 调用素材生成服务或使用内置素材库。 - 打包游戏资源并输出可运行Manifest。 - Moderation Worker - 检测Prompt、标题、简介、封面和上传素材。 - 输出风险等级、命中策略和审核建议。 - Event Worker - 批量消费前端埋点。 - 写入事件表并更新聚合指标。 - Recommendation Service - MVP为规则策略,可在API Server内实现。 - 根据精选池、新发布、质量分、用户互动和加载错误率返回游戏列表。 - 通信协议 - 前端与后端:REST over HTTPS。 - 生成任务状态:优先Server-Sent Events或轮询;MVP可使用2秒轮询,后续升级WebSocket。 - Worker任务:BullMQ over Redis。 - 静态资源:HTTPS + CDN。 - 第三方AI服务:HTTPS API。 - 设计模式 - Modular Monolith:MVP阶段降低部署和运维复杂度,同时保持模块边界。 - Event-driven:生成、审核、发布、互动、埋点和指标聚合使用事件驱动。 - CQRS Lite:写入操作走业务表,读取高频的游戏流和数据看板使用聚合表或缓存。 - State Machine:GenerationTask、Game、ReviewRecord采用明确状态机,避免状态混乱。 ### Data Structures & Algorithms - 核心数据结构 - GameConfig - JSON结构,描述玩法模板、参数、关卡、角色、素材、胜负条件和UI文案。 - 选择理由:便于受控生成、版本管理、Web运行时加载和安全校验。 - GameManifest - JSON结构,描述运行入口、资源列表、版本号、校验hash、SDK版本和预加载策略。 - 选择理由:前端游戏容器可根据Manifest统一加载不同游戏。 - FeedItem - 包含game_id、creator_id、score、reason、preload_assets、interaction_state。 - 选择理由:解耦推荐计算和前端展示。 - EventPayload - 标准化埋点结构:event_name、user_id、anonymous_id、game_id、session_id、timestamp、properties。 - 选择理由:便于漏斗、留存和内容质量分析。 - GameConfig示例 ```json { "template": "avoidance_v1", "theme": "pixel_space", "durationSeconds": 60, "player": { "sprite": "ship_blue", "speed": 320, "hitPoints": 3 }, "objectives": \[ { "type": "survive", "seconds": 60 }, { "type": "collect", "item": "energy", "target": 20 } \], "enemies": \[ { "type": "asteroid", "spawnRatePerSecond": 1.2, "speedRange": \[120, 260\] } \], "controls": { "mobile": "drag", "desktop": "arrow_keys" }, "winCondition": "survive_and_collect", "loseCondition": "hp_zero" } ``` - 关键算法 - Prompt到模板映射 - 输入:用户Prompt、用户选择模板、风格标签。 - 输出:template_id、confidence、normalized_parameters。 - MVP实现:LLM分类 + 规则兜底。 - 复杂度:O(T),T为模板数量,MVP模板数量小于10,性能可忽略。 - 游戏配置校验 - 输入:GameConfig。 - 输出:validated_config或错误列表。 - 规则:数值范围、必填字段、资源引用、关卡长度、资源体积、敏感词。 - 复杂度:O(N),N为配置节点数。 - 游戏流排序 - MVP评分公式:score = base_weight + recency_score + quality_score + interaction_score + creator_boost - risk_penalty - error_penalty。 - 冷启动权重:精选池、最新发布、每个新作保底曝光。 - 复杂度:候选集过滤O(N),排序O(N log N)。N通过分页候选集控制在200以内。 - 内容质量分 - quality_score基于试玩完成率、30秒留存、点赞率、收藏率、举报率、加载失败率。 - 每小时或每15分钟由Event Worker聚合更新。 - 扩展与性能考虑 - 生成任务使用队列削峰,避免LLM和打包服务阻塞主API。 - 游戏资源限制MVP单包不超过10MB,首屏关键资源不超过2MB。 - 热门游戏Manifest和元数据缓存到Redis,TTL 60至300秒。 - 游戏资源文件使用hash命名,启用长期CDN缓存。 - 埋点批量上报,前端每10条或5秒flush一次,避免影响游戏帧率。 ### System Interfaces - API endpoints |Method|Route|Purpose|Auth| | --------| -------------------------------------------| ----------------------------------| ---------------| |POST|/api/v1/auth/login|登录并返回访问令牌|Public| |POST|/api/v1/auth/refresh|刷新访问令牌|Refresh Token| |GET|/api/v1/me|获取当前用户资料与角色|User| |POST|/api/v1/generation/tasks|创建AI生成任务|Creator| |GET|/api/v1/generation/tasks/{taskId}|查询生成任务状态|Creator| |POST|/api/v1/games|从生成结果创建游戏草稿|Creator| |GET|/api/v1/games/{gameId}|获取游戏详情|Public/Owner| |PATCH|/api/v1/games/{gameId}|更新标题、简介、封面、标签和参数|Owner| |POST|/api/v1/games/{gameId}/publish|提交发布|Owner| |GET|/api/v1/feed|获取游戏流列表|Public| |POST|/api/v1/interactions|点赞、收藏、分享、举报|User| |POST|/api/v1/events/batch|批量上报埋点事件|Public| |GET|/api/v1/creator/games|获取创作者游戏列表|Creator| |GET|/api/v1/creator/games/{gameId}/stats|获取单游戏数据看板|Owner| |GET|/api/v1/admin/reviews|获取审核队列|Operator| |POST|/api/v1/admin/reviews/{reviewId}/decision|审核通过、拒绝或下架|Operator| |POST|/api/v1/admin/featured-games|加入精选池|Operator| - 创建生成任务请求示例 ```json { "prompt": "做一个像素风太空躲避游戏,玩家控制飞船躲避陨石,收集能量块,坚持60秒获胜。", "templateHint": "avoidance", "styleTags": \["pixel", "space"\], "uploadedAssetIds": \["asset_01HXYZ"\] } ``` - 创建生成任务响应示例 ```json { "taskId": "gt_01HZA9Z9H4Q7", "status": "queued", "estimatedSeconds": 90, "pollingIntervalMs": 2000 } ``` - 查询生成任务响应示例 ```json { "taskId": "gt_01HZA9Z9H4Q7", "status": "succeeded", "progress": 100, "currentStep": "preview_ready", "gameDraft": { "gameId": "game_01HZAA1M0KQ8", "buildId": "build_01HZAA1R9QA3", "previewUrl": "https://cdn.example.com/games/build_01HZAA1R9QA3/index.html" }, "error": null } ``` - 获取游戏流请求示例 ```http GET /api/v1/feed?cursor=eyJzY29yZSI6MTIzfQ&limit=10&device=mobile Authorization: Bearer optional ``` - 获取游戏流响应示例 ```json { "items": \[ { "gameId": "game_01HZAA1M0KQ8", "title": "像素太空逃亡", "description": "躲避陨石并收集能量,坚持60秒。", "coverUrl": "https://cdn.example.com/covers/game_01HZAA1M0KQ8.webp", "creator": { "userId": "user_123", "nickname": "小林" }, "manifestUrl": "https://cdn.example.com/manifests/build_01HZAA1R9QA3.json", "preloadAssets": \[ "https://cdn.example.com/assets/ship.webp", "https://cdn.example.com/assets/bg.webp" \], "interactionState": { "liked": false, "favorited": false }, "reason": "featured_and_new" } \], "nextCursor": "eyJzY29yZSI6MTE5fQ" } ``` - 批量埋点请求示例 ```json { "sessionId": "sess_01HZAB", "anonymousId": "anon_abc", "events": \[ { "eventName": "game_impression", "occurredAt": "2026-05-28T10:00:00.000Z", "gameId": "game_01HZAA1M0KQ8", "properties": { "position": 1, "feedRequestId": "feed_req_123" } }, { "eventName": "game_play_30s", "occurredAt": "2026-05-28T10:00:32.000Z", "gameId": "game_01HZAA1M0KQ8", "properties": { "fpsAvg": 52, "loadTimeMs": 1800 } } \] } ``` - Third-party integrations - LLM Provider - 用途:Prompt理解、模板分类、参数生成、失败解释。 - 协议:HTTPS JSON API。 - 要求:设置超时30秒、最大重试2次、供应商错误降级到默认模板建议。 - 图片生成或素材服务 - MVP可选,建议优先使用内置素材库与风格包,减少生成不确定性。 - 若接入图片生成,需进行内容安全检测和资源压缩。 - 内容安全服务 - 用途:文本、图片、用户资料、封面和Prompt检测。 - 协议:HTTPS API。 - 输出:pass、review、reject三类结果。 - 对象存储和CDN - 用途:上传素材、生成资源、游戏包、封面和Manifest。 - 要求:私有源站,CDN公开只读;上传使用服务端签名URL。 - 数据分析工具 - MVP内部事件表即可,后续可对接GrowingIO、神策、Mixpanel或自建ClickHouse。 - Internal modules - AuthModule:登录、Token、角色、匿名用户升级。 - UserModule:用户资料、创作者主页。 - AssetModule:上传、扫描、压缩、对象存储签名。 - GenerationModule:任务创建、状态机、Prompt解析、GameConfig生成。 - GameModule:草稿、版本、发布、详情、Manifest管理。 - ReviewModule:审核队列、审核记录、下架、精选。 - FeedModule:候选集、排序、分页、曝光保底。 - InteractionModule:点赞、收藏、分享、举报。 - AnalyticsModule:事件接收、聚合、看板。 - AdminModule:后台权限、操作审计、系统配置。 ### User Interface - 创作工作台 - 主区域:Prompt输入框、模板卡片、风格标签、上传素材入口。 - 任务页:生成状态、当前步骤、预计等待时间、失败原因和重试入口。 - 预览页:左侧游戏预览容器,右侧基础信息编辑面板。 - 发布页:发布前检查清单、审核状态说明、分享链接。 - 玩家游戏流 - 移动优先,全屏或近全屏纵向滑动。 - 每个游戏项包含封面、标题、作者、玩法提示、开始按钮、点赞、收藏、分享、举报。 - 游戏资源预加载下一项,当前项加载失败时显示错误提示并自动允许跳过。 - 低端设备启用低画质模式,限制帧率到30fps。 - 创作者后台 - 我的游戏列表:封面、标题、状态、曝光、试玩、互动、最后更新时间。 - 数据详情:近7天趋势、曝光到试玩漏斗、平均游玩时长、加载失败率、举报率。 - 操作:编辑、更新、下架、复制分享链接。 - 运营后台 - 审核队列:状态筛选、风险等级、发布时间、创作者、标签。 - 审核详情:游戏试玩、Prompt、生成配置、素材列表、安全检测结果、历史记录。 - 操作:通过、拒绝、下架、备注、加入精选池、限制曝光。 - 交互模式 - 关键流程必须有明确状态:加载中、成功、失败、禁用、重试。 - 生成任务超过120秒提示后台等待,不阻断用户离开页面。 - 所有破坏性操作使用二次确认,例如下架、删除草稿、拒绝审核。 - 可访问性与响应式设计 - 移动端优先适配360px至430px宽度。 - 桌面端优先优化创作工作台和运营后台。 - 文本对比度符合WCAG AA基础要求。 - 核心按钮支持键盘访问和可读ARIA标签。 - 错误提示不只依赖颜色表达,应同时使用文本和图标。 ## Data Model How data is structured, stored, and accessed. ### Entities ```text User - id: uuid (primary key) - phone: varchar(32) (nullable, unique) - email: varchar(255) (nullable, unique) - password_hash: varchar(255) (nullable) - nickname: varchar(64) (not null) - avatar_url: text (nullable) - role: enum(player, creator, operator, admin) (not null, default player) - status: enum(active, suspended, deleted) (not null, default active) - created_at: timestamptz (not null) - updated_at: timestamptz (not null) ``` ```text CreatorProfile - id: uuid (primary key) - user_id: uuid (unique, foreign key User.id) - slug: varchar(64) (unique, not null) - bio: varchar(500) (nullable) - total_games: integer (not null, default 0) - total_plays: bigint (not null, default 0) - created_at: timestamptz (not null) - updated_at: timestamptz (not null) ``` ```text Asset - id: uuid (primary key) - owner_id: uuid (foreign key User.id) - type: enum(image, audio, json, game_bundle, manifest) (not null) - source: enum(uploaded, generated, system) (not null) - storage_key: text (not null) - public_url: text (nullable) - mime_type: varchar(128) (not null) - size_bytes: integer (not null) - width: integer (nullable) - height: integer (nullable) - hash_sha256: char(64) (not null) - moderation_status: enum(pending, passed, review, rejected) (not null, default pending) - created_at: timestamptz (not null) ``` ```text PromptRecord - id: uuid (primary key) - user_id: uuid (foreign key User.id) - raw_prompt: text (not null) - normalized_prompt: text (nullable) - template_hint: varchar(64) (nullable) - style_tags: text\[\] (not null, default empty) - moderation_status: enum(pending, passed, review, rejected) (not null) - moderation_reason: text (nullable) - created_at: timestamptz (not null) ``` ```text GenerationTask - id: uuid (primary key) - user_id: uuid (foreign key User.id) - prompt_record_id: uuid (foreign key PromptRecord.id) - status: enum(queued, running, succeeded, failed, canceled, timed_out) (not null) - progress: integer (0 to 100) - current_step: varchar(64) (nullable) - template_id: varchar(64) (nullable) - llm_request_id: varchar(128) (nullable) - error_code: varchar(64) (nullable) - error_message: text (nullable) - started_at: timestamptz (nullable) - completed_at: timestamptz (nullable) - created_at: timestamptz (not null) - updated_at: timestamptz (not null) ``` ```text Game - id: uuid (primary key) - creator_id: uuid (foreign key User.id) - title: varchar(80) (not null) - description: varchar(500) (not null) - cover_asset_id: uuid (foreign key Asset.id, nullable) - status: enum(draft, pending_review, published, rejected, unpublished, deleted) (not null) - visibility: enum(private, public, limited) (not null, default private) - tags: text\[\] (not null, default empty) - age_rating: enum(all, teen, mature) (not null, default all) - current_version_id: uuid (nullable) - published_at: timestamptz (nullable) - created_at: timestamptz (not null) - updated_at: timestamptz (not null) ``` ```text GameVersion - id: uuid (primary key) - game_id: uuid (foreign key Game.id) - version_number: integer (not null) - generation_task_id: uuid (foreign key GenerationTask.id, nullable) - config_json: jsonb (not null) - manifest_asset_id: uuid (foreign key Asset.id) - bundle_asset_id: uuid (foreign key Asset.id, nullable) - runtime_version: varchar(32) (not null) - status: enum(draft, active, archived, failed) (not null) - created_at: timestamptz (not null) ``` ```text ReviewRecord - id: uuid (primary key) - game_id: uuid (foreign key Game.id) - version_id: uuid (foreign key GameVersion.id) - status: enum(pending, approved, rejected, escalated) (not null) - risk_level: enum(low, medium, high) (not null, default low) - reviewer_id: uuid (foreign key User.id, nullable) - reason_code: varchar(64) (nullable) - comment: text (nullable) - created_at: timestamptz (not null) - decided_at: timestamptz (nullable) ``` ```text Interaction - id: uuid (primary key) - user_id: uuid (foreign key User.id, nullable) - anonymous_id: varchar(128) (nullable) - game_id: uuid (foreign key Game.id) - type: enum(like, favorite, share, report) (not null) - status: enum(active, canceled) (not null, default active) - reason: varchar(128) (nullable, for report) - created_at: timestamptz (not null) - updated_at: timestamptz (not null) ``` ```text EventLog - id: uuid (primary key) - event_name: varchar(64) (not null) - user_id: uuid (nullable) - anonymous_id: varchar(128) (nullable) - session_id: varchar(128) (not null) - game_id: uuid (nullable) - properties: jsonb (not null) - occurred_at: timestamptz (not null) - received_at: timestamptz (not null) ``` ```text GameDailyStats - id: uuid (primary key) - game_id: uuid (foreign key Game.id) - stat_date: date (not null) - impressions: bigint (not null, default 0) - load_success: bigint (not null, default 0) - load_failed: bigint (not null, default 0) - play_starts: bigint (not null, default 0) - play_30s: bigint (not null, default 0) - completes: bigint (not null, default 0) - likes: bigint (not null, default 0) - favorites: bigint (not null, default 0) - shares: bigint (not null, default 0) - reports: bigint (not null, default 0) - avg_play_duration_ms: integer (nullable) - created_at: timestamptz (not null) - updated_at: timestamptz (not null) ``` ```text FeaturedGame - id: uuid (primary key) - game_id: uuid (foreign key Game.id) - operator_id: uuid (foreign key User.id) - priority: integer (not null, default 0) - start_at: timestamptz (not null) - end_at: timestamptz (nullable) - created_at: timestamptz (not null) ``` ```text AuditLog - id: uuid (primary key) - actor_id: uuid (foreign key User.id) - action: varchar(128) (not null) - target_type: varchar(64) (not null) - target_id: uuid (not null) - metadata: jsonb (not null) - ip_address: inet (nullable) - user_agent: text (nullable) - created_at: timestamptz (not null) ``` ### Relationships - User → CreatorProfile:one-to-one;User删除时CreatorProfile软删除或保留匿名化记录。 - User → Game:one-to-many;creator_id限制只能访问和修改自己的游戏。 - User → Asset:one-to-many;上传素材归属用户,系统素材owner可为空或使用system user。 - PromptRecord → GenerationTask:one-to-many;同一Prompt允许多次重试生成。 - GenerationTask → GameVersion:one-to-one或one-to-many;一次成功生成可创建一个版本,重试可产生新版本。 - Game → GameVersion:one-to-many;Game.current_version_id指向当前线上或草稿版本。 - Game → ReviewRecord:one-to-many;每次发布提交生成一条审核记录。 - Game → Interaction:one-to-many;同一用户对同一游戏的like和favorite应有唯一约束。 - Game → GameDailyStats:one-to-many;按game_id和stat_date唯一。 - Game → FeaturedGame:one-to-many;可配置多个时间段的精选计划。 - ReviewRecord → User:many-to-one;reviewer_id为运营或管理员。 - 关键约束 - Game.status为published时必须存在current_version_id、cover_asset_id、title、description。 - GameVersion.config_json必须通过JSON Schema校验。 - Interaction唯一约束:user_id + game_id + type,适用于like和favorite;share和report允许多条但需要限频。 - EventLog按occurred_at月度分区,避免长期写入膨胀影响查询。 - 所有后台操作写入AuditLog。 ### Storage - 数据库 - PostgreSQL作为主库,承载用户、游戏、版本、审核、互动和聚合统计。 - 使用Prisma Migration管理Schema变更。 - 关键索引: - Game(status, published_at desc) - Game(creator_id, updated_at desc) - ReviewRecord(status, created_at asc) - Interaction(game_id, type) - EventLog(occurred_at, event_name) - GameDailyStats(game_id, stat_date) - 缓存 - Redis缓存游戏详情、Manifest元数据、Feed候选集、用户会话和限频计数。 - Feed缓存TTL 60秒,热门游戏详情TTL 300秒。 - 生成任务状态可写PostgreSQL为准,Redis用于短期进度加速读取。 - 队列 - BullMQ队列:generation_queue、moderation_queue、asset_processing_queue、event_aggregation_queue、notification_queue。 - 每类任务配置重试次数、退避策略和死信队列。 - 文件/blob存储 - 原始上传素材:private bucket,需签名访问。 - 处理后封面和公开素材:public-read via CDN或私有源站加CDN回源。 - 游戏Manifest和bundle:版本化路径,例如/games/{gameId}/versions/{versionId}/manifest.json。 - 所有资源文件保留sha256 hash,用于去重、缓存和完整性校验。 ### Data Flow - 创作生成流程 1. 用户登录并进入创作工作台。 2. 前端提交Prompt、模板提示、风格标签和素材ID。 3. API Server创建PromptRecord和GenerationTask,写入generation_queue。 4. Moderation Worker先检测Prompt和上传素材;若reject则任务失败并返回明确原因。 5. Generation Worker调用LLM解析Prompt,选择模板并生成GameConfig。 6. Worker使用JSON Schema和业务规则校验GameConfig。 7. Worker生成或绑定素材,创建GameManifest并上传对象存储。 8. Worker创建Game草稿和GameVersion,更新任务状态为succeeded。 9. 前端轮询任务状态并跳转预览页。 - 发布审核流程 1. 创作者编辑标题、简介、封面、标签和操作说明。 2. 点击发布后,API执行发布前检查。 3. 系统创建ReviewRecord并将Game置为pending_review。 4. 低风险内容可自动通过或进入运营队列,具体由配置控制。 5. 运营通过后Game置为published和public,写入AuditLog。 6. Feed候选集下次刷新时包含该游戏,并为新作分配保底曝光。 - 玩家游戏流流程 1. 玩家打开首页,前端请求/api/v1/feed。 2. FeedModule从精选、最新、质量分候选池取数据并排序。 3. 前端展示第一款游戏并预加载下一款Manifest和关键资源。 4. 玩家开始试玩,Game SDK上报load、start、30s、complete和error事件。 5. 前端批量调用/events/batch上报埋点。 6. Event Worker聚合更新GameDailyStats和质量分。 7. 后续Feed排序降低高错误、高举报游戏的曝光。 - 运营审核流程 1. 运营登录后台,调用/admin/reviews获取待审核列表。 2. 运营查看游戏详情、Prompt、安全检测结果和试玩预览。 3. 运营提交通过、拒绝、下架或精选操作。 4. API更新Game、ReviewRecord、FeaturedGame并写AuditLog。 ## Testing Plan How the product will be validated at every level. ### Testing Strategy - Unit tests - 覆盖范围:Prompt解析适配器、GameConfig校验、状态机转换、Feed评分、权限Guard、事件聚合逻辑。 - 框架:Vitest或Jest。 - 覆盖目标:核心业务模块行覆盖率不低于80%,状态机和权限模块不低于90%。 - Integration tests - 覆盖范围:REST API、PostgreSQL、Redis Queue、对象存储Mock、内容安全Mock、LLM Mock。 - 重点验证:生成任务创建到成功、发布审核、游戏流返回、互动写入、事件聚合。 - 使用Testcontainers启动PostgreSQL和Redis,避免只依赖内存Mock。 - E2E tests - 框架:Playwright。 - 覆盖关键用户流:创作者生成游戏、预览发布、运营审核、玩家游戏流试玩互动、创作者查看数据。 - 移动端视口必须覆盖iPhone和Android常见宽度。 - Performance tests - 工具:k6。 - 目标: - /feed P95低于300ms,不含CDN资源加载。 - /events/batch P95低于200ms。 - /generation/tasks创建任务P95低于500ms。 - 500并发玩家浏览Feed时错误率低于1%。 - 每分钟5,000条事件写入时队列无持续积压。 - Game runtime tests - 使用自动化脚本加载每个模板生成的Manifest。 - 验证资源存在、启动成功、SDK事件发出、低端设备模拟下帧率不低于30fps。 - 对每个模板维护golden config样例。 ### Testing Tools - Frontend - Vitest:组件逻辑和工具函数。 - React Testing Library:UI状态和交互。 - Playwright:跨浏览器和移动视口E2E。 - Lighthouse CI:性能、可访问性和最佳实践检查。 - Backend - Jest或Vitest:服务、控制器和状态机单测。 - Supertest:API集成测试。 - Testcontainers:PostgreSQL和Redis依赖环境。 - Prisma migrate diff:Schema变更验证。 - Game runtime - Playwright:加载游戏容器并监听SDK事件。 - 自定义Manifest Validator:校验Manifest资源、hash和字段完整性。 - Performance and security - k6:API压测。 - OWASP ZAP Baseline Scan:基础Web安全扫描。 - npm audit、pnpm audit、Snyk或GitHub Dependabot:依赖漏洞扫描。 - CI integration - Pull Request阶段:lint、type check、unit tests、API integration tests、build。 - Merge to main阶段:完整测试、Docker镜像构建、安全扫描、部署到staging。 - Release阶段:staging E2E、性能冒烟、手动批准生产部署。 - Code coverage - 全仓库最低70%。 - 核心后端业务模块最低80%。 - 权限、审核和发布状态机最低90%。 - 覆盖率不达标阻断合并。 ### Key Test Cases - 创作链路Happy Path - 创作者登录。 - 输入合法Prompt并选择模板。 - 创建生成任务成功。 - Worker生成GameConfig和Manifest。 - 前端预览成功加载游戏。 - 创作者填写标题、封面、标签并保存。 - 发布与审核 - 发布前缺少标题时返回明确错误。 - 内容安全reject时不得进入公开Feed。 - pending_review游戏只有作者和运营可访问。 - 运营通过后游戏出现在Feed候选集中。 - 运营拒绝后创作者看到原因且可修改重提。 - 玩家游戏流 - 未登录用户可以浏览和试玩。 - 未登录用户点击点赞时触发登录引导,并在登录后恢复操作上下文。 - 游戏加载失败时记录game_load_failed并允许跳过。 - 上下滑动切换不会重复曝光同一游戏,除非列表耗尽。 - 下一款游戏资源成功预加载。 - 互动与埋点 - 同一用户重复点赞不会重复计数。 - 收藏取消后状态更新为canceled。 - 举报行为触发风险信号并对同一匿名用户限频。 - 批量事件中部分无效事件不影响有效事件写入。 - Event Worker聚合后数据看板数值正确。 - 权限与安全敏感操作 - 普通用户不能访问/admin接口。 - 创作者不能编辑他人游戏。 - 运营操作必须写入AuditLog。 - 已删除或下架游戏不能在公开Feed返回。 - 上传非图片或超大文件会被拒绝。 - 性能边界 - 单个游戏Manifest资源超过大小限制时生成失败并返回可理解原因。 - 高并发Feed请求不造成数据库慢查询。 - Redis不可用时Feed可降级为数据库读取并告警。 - LLM超时后任务进入failed或timed_out,允许用户重试。 ### Reporting - CI报告 - GitHub Actions或GitLab CI展示每次PR的测试、覆盖率、构建和安全扫描结果。 - 失败测试必须阻断合并。 - 质量看板 - Grafana展示API错误率、P95延迟、队列长度、生成成功率、游戏加载失败率。 - Sentry展示前端错误、游戏运行错误和后端异常。 - 每日自动生成MVP质量报告:生成任务数、成功率、平均生成时长、审核积压、Feed错误率。 - 缺陷管理 - P0:核心链路不可用、权限绕过、数据丢失、安全事故。 - P1:生成成功率显著下降、游戏流加载异常、审核流程阻塞。 - P2:单页面体验问题、非关键统计延迟、文案错误。 ## Deployment Plan How the product moves from code to production. ### Environment Setup - Development - 本地运行Docker Compose:PostgreSQL、Redis、MinIO、本地邮件或通知Mock。 - 前端Next.js热更新运行在localhost:3000。 - 后端NestJS运行在localhost:4000。 - Worker独立进程运行generation、moderation和event aggregation。 - 使用seed脚本创建管理员、运营、示例创作者、示例游戏和模板数据。 - LLM和内容安全默认使用Mock Provider,可通过环境变量切换真实Provider。 - Staging - 与生产同构但缩小规格。 - 使用独立PostgreSQL、Redis、OSS bucket和CDN域名。 - 接入真实内容安全服务,LLM可使用较低成本模型。 - 仅允许白名单用户访问创作和后台。 - 每次main合并自动部署。 - Production - 云基础设施建议: - API Server运行在Kubernetes、ECS、Cloud Run或Render/Fly.io等容器平台。 - Worker按队列类型独立部署,可横向扩容。 - PostgreSQL使用云托管数据库,开启自动备份和只读副本预留。 - Redis使用托管版,开启持久化和监控。 - 静态前端部署到Vercel、Netlify或对象存储加CDN。 - 生产访问必须使用HTTPS。 - 所有Secrets从云Secret Manager或Vault读取,不写入代码仓库。 ### CI/CD Pipeline - Build steps 1. 安装依赖:pnpm install --frozen-lockfile。 2. 静态检查:eslint、prettier check。 3. 类型检查:tsc --noEmit。 4. 单元测试:vitest/jest with coverage。 5. 集成测试:Testcontainers PostgreSQL和Redis。 6. 前端构建:next build。 7. 后端构建:nest build。 8. Docker镜像构建并打tag。 9. 依赖漏洞扫描和镜像扫描。 - Deployment trigger - Pull Request:创建Preview Deployment,仅连接staging级别Mock服务。 - Merge to main:自动部署Staging。 - Production:手动批准发布,建议每周固定窗口或MVP阶段按需发布。 - Preview deployments - 每个PR生成前端预览URL。 - 后端可共享staging API或部署临时环境。 - Preview环境禁止使用真实用户数据和真实支付/广告相关配置。 ### Deploy Process 1. 准备发布版本 - 确认main分支CI全绿。 - 确认数据库Migration已在staging成功执行。 - 确认Feature Flag默认值符合发布策略。 - Verification checkpoint:staging smoke tests通过,错误率无异常。 2. 执行数据库迁移 - 在生产数据库执行向后兼容Migration。 - 禁止直接删除字段或重命名字段;采用expand-migrate-contract策略。 - Verification checkpoint:迁移执行成功,关键表读写正常。 3. 部署后端API - 使用滚动发布或蓝绿部署。 - 保持旧版本至少可服务5至10分钟,确保无中断。 - Verification checkpoint:/health、/ready、登录、Feed接口正常。 4. 部署Worker - 先暂停或降低新任务消费。 - 部署Worker新版本。 - 恢复队列消费并观察失败率。 - Verification checkpoint:generation_queue和event_aggregation_queue无异常积压。 5. 部署前端 - 发布Next.js前端或静态资源。 - 刷新CDN缓存中需要更新的HTML和Manifest加载脚本。 - Verification checkpoint:创作工作台、游戏流、后台入口可访问。 6. 灰度开启功能 - 使用Feature Flag先对内部用户开放。 - 观察30至60分钟后扩大到种子用户。 - Verification checkpoint:生成成功率、Feed错误率、Sentry错误无异常增长。 ### Rollback Strategy - 应用回滚 - 保留最近3个稳定Docker镜像。 - API和Worker可通过部署平台一键回滚到上一版本。 - 前端可通过Vercel/Netlify回滚或CDN切回上一构建。 - 数据库回滚 - 优先使用向后兼容Migration避免必须回滚数据库。 - 对高风险Migration预先准备rollback SQL。 - 删除数据类操作必须先备份,MVP阶段原则上不做破坏性Migration。 - Feature flags - generation_v2_enabled:控制新生成链路。 - feed_ranking_v2_enabled:控制新推荐评分。 - auto_review_enabled:控制自动审核通过。 - external_asset_generation_enabled:控制外部图片生成服务。 - 任何P0异常优先关闭相关Flag,而不是全站回滚。 - 队列回滚 - Worker新版本异常时暂停队列消费。 - 将失败任务标记为retryable或保持queued,待旧版本恢复后继续消费。 - 对不兼容任务payload使用version字段区分处理逻辑。 ### Post-Deploy Verification - Smoke tests - 用户登录成功。 - 创建生成任务成功,Mock或真实低成本生成可完成。 - 预览游戏可加载并触发game_load_success。 - 游戏可提交审核。 - 运营可通过审核。 - 已发布游戏可出现在Feed。 - 点赞、收藏和埋点上报成功。 - Monitoring dashboards - API Latency:P50、P95、P99。 - API Error Rate:4xx、5xx分布。 - Queue Health:等待数、处理中、失败数、平均处理时长。 - Generation Health:成功率、失败原因、平均生成时长。 - Game Runtime:加载成功率、运行错误率、平均FPS、资源加载时长。 - Database:CPU、连接数、慢查询、锁等待。 - CDN:命中率、回源错误、流量峰值。 - Alert thresholds - API 5xx错误率5分钟内超过2%触发P1告警。 - /feed P95超过800ms持续10分钟触发P1告警。 - 生成成功率15分钟内低于70%触发P1告警。 - generation_queue等待任务超过500或最老任务等待超过10分钟触发P1告警。 - 游戏加载失败率超过8%持续15分钟触发P1告警。 - 数据库连接使用率超过85%持续10分钟触发P1告警。 - 权限相关异常或后台接口未授权访问激增触发P0安全告警。 ## Security & Performance Non-functional requirements and how they are addressed. ### Security - Authentication - 使用JWT Access Token和Refresh Token。 - Access Token有效期15分钟,Refresh Token有效期7至30天。 - Refresh Token存储hash,支持注销和设备级撤销。 - 游客使用anonymous_id,只允许浏览和试玩,不允许发布、收藏和后台操作。 - Authorization - 使用RBAC:player、creator、operator、admin。 - 所有修改游戏、审核、精选、下架和查看后台接口必须校验角色和资源归属。 - 后台接口单独命名空间/admin,并增加IP风险监控和操作审计。 - Input validation and sanitization - API使用Zod或class-validator校验请求。 - Prompt长度限制,例如10至1,000字符。 - 标题限制80字符,简介限制500字符,标签数量限制10个。 - 上传文件限制MIME、扩展名、大小和尺寸。 - 所有用户可见文本输出做HTML escaping,禁止直接渲染未清洗HTML。 - Game sandboxing - 游戏运行在受控iframe或隔离容器中。 - 禁止生成游戏访问任意网络、Cookie、localStorage和父页面DOM。 - Game SDK只暴露有限能力:事件上报、结束游戏、读取配置。 - 设置Content Security Policy限制脚本源、资源源和frame权限。 - Secrets management - 本地开发使用.env.local,不提交仓库。 - Staging和Production使用Secret Manager或Vault。 - LLM、内容安全、OSS、数据库和Redis凭证定期轮换。 - 日志中禁止输出Token、手机号、邮箱、Prompt敏感检测明文结果和第三方API Key。 - Dependency vulnerability scanning - Pull Request阶段运行pnpm audit或Snyk。 - Docker镜像使用Trivy或云厂商镜像扫描。 - Dependabot自动提交安全升级PR。 - OWASP Top 10 considerations - Broken Access Control:RBAC、资源归属校验、后台审计。 - Cryptographic Failures:HTTPS、数据库备份加密、敏感字段加密或脱敏。 - Injection:Prisma参数化查询,禁止拼接SQL;Prompt不直接作为系统指令执行。 - Insecure Design:状态机限制非法发布和审核状态转换。 - Security Misconfiguration:CSP、CORS白名单、生产关闭debug、对象存储私有源站。 - Vulnerable Components:依赖扫描和锁文件审计。 - Identification and Authentication Failures:Refresh Token轮换、登录限频、密码hash使用Argon2或bcrypt。 - Software and Data Integrity Failures:游戏Manifest hash校验,CI签名镜像可选。 - Security Logging and Monitoring Failures:后台操作、登录失败、安全拒绝全部记录。 - SSRF:后端不允许用户提交任意URL抓取资源;如后续支持,必须使用URL allowlist和内网IP阻断。 - Content safety and compliance - Prompt、标题、简介、封面和上传素材均经过内容安全检测。 - risk_level为high时自动拒绝,medium进入人工审核,low可进入普通审核或自动通过。 - 举报达到阈值时自动限制曝光并进入运营复核。 - 针对未成年人保护、版权素材和暴力色情等内容建立可配置策略。 ### Performance - Targets - 游戏流API响应:P95低于300ms,P99低于800ms。 - 游戏详情API响应:P95低于200ms。 - 埋点批量上报API响应:P95低于200ms。 - 生成任务创建API响应:P95低于500ms。 - 生成任务完成时长:P75低于120秒,P95低于240秒。 - 游戏流首屏可交互时间:P75低于3秒,P95低于6秒。 - 游戏运行帧率:中端移动设备平均不低于45fps,低端设备低画质不低于30fps。 - 平台吞吐:MVP支持500并发浏览用户、每分钟5,000条埋点事件、每日1,000次生成任务。 - Optimization - 前端 - Next.js路由级代码分割。 - 游戏流只保留当前、前一、后一三个游戏容器。 - 图片使用WebP/AVIF,封面多尺寸裁剪。 - 下一款游戏Manifest和关键资源预加载。 - 埋点异步批量发送,使用sendBeacon兜底。 - 后端 - 高频读接口使用Redis缓存。 - Feed候选集预计算或短TTL缓存。 - 事件写入走批量insert,聚合异步执行。 - 数据库连接池按实例规格配置,避免连接耗尽。 - 资源 - 游戏bundle hash命名,CDN长期缓存。 - 限制单游戏总资源大小和首屏关键资源大小。 - 音频延迟加载,非关键图片懒加载。 - Worker - 生成Worker按队列长度自动扩容。 - LLM调用设置超时、重试和熔断。 - 资产处理使用并发限制,避免CPU尖峰。 - Monitoring - APM:OpenTelemetry trace跨API、Worker和数据库。 - Error tracking:Sentry捕获前端、Game Runtime和后端异常。 - Custom metrics:生成成功率、审核积压、Feed曝光、游戏加载失败率、互动率。 - Scaling - MVP阶段:API Server 2个实例,Worker按队列1至3个实例,PostgreSQL单主实例,Redis托管实例。 - 增长阶段: - API Server水平扩容。 - Generation Worker按任务量独立扩容。 - Event Worker和Analytics迁移到ClickHouse或数据仓库。 - Feed Service从API Server拆分为独立服务。 - PostgreSQL增加只读副本,读多写少接口走读副本。 - Auto-scaling配置 - API:CPU超过65%或RPS超过阈值扩容。 - Worker:队列等待任务数超过100或最老任务等待超过2分钟扩容。 - Event Worker:事件队列积压超过10,000条扩容。 ### Observability - Logging strategy - 使用结构化JSON日志。 - 所有日志包含request_id、user_id可选、anonymous_id可选、module、operation、duration_ms、status。 - 生成任务日志包含task_id、template_id、provider、error_code,但不直接记录敏感Prompt全文。 - 审核和后台操作写AuditLog并长期保存。 - 日志保留:应用日志30天,审计日志至少180天,安全日志至少180天。 - Metrics - Product metrics - creator_activation_rate。 - generation_success_rate。 - first_publish_conversion_rate。 - feed_session_games_played。 - game_interaction_rate。 - player_d7_retention。 - System metrics - API RPS、latency、error rate。 - Queue depth、processing time、failure count。 - Database CPU、connections、slow queries、locks。 - Redis memory、hit rate、evictions。 - CDN hit rate、origin error rate。 - Game metrics - game_load_time_ms。 - game_load_failed_rate。 - runtime_error_rate。 - fps_avg。 - asset_size_bytes。 - Alerting - 告警渠道:飞书、Slack、邮件或短信,按严重级别区分。 - P0响应:核心链路不可用、安全事故、数据丢失,15分钟内响应。 - P1响应:生成失败率异常、Feed延迟异常、队列严重积压,工作时间30分钟内响应。 - P2响应:非核心页面错误、低频统计延迟,下一工作日处理。 - 每个告警必须包含Runbook链接:问题现象、排查仪表盘、常见原因、回滚步骤和负责人。