返回项目列表
Pokemon 标志

Pokemon

包含每只宝可梦详细信息的平台,涉及属性统计、特性、招式、进化链等。

AngularNestJSGraphQL

下面,我展示了这个 Pokedex 项目的技术与架构分析,该项目旨在同时作为仓库的官方文档和案例研究。我的核心重点是以分析和客观的方式描述系统设计、架构决策和数据流。

1. 业务实用性与通用工作流

该应用旨在解决“宝可梦 (Pokémon)”实体复杂数据的索引、搜索和可视化问题。其主要实用价值在于将分散的信息(属性统计、进化链、招式、物理描述)整合到一个具有高视觉保真度的凝聚用户界面中。

主要业务工作流按以下方式运行:

  1. 初始化: 在挂载 Web 应用时,客户端请求与当前 URL 同步的基础状态。如果没有定义参数,状态会自动与初始标识符(ID 1)同步,并请求通用目录的第一个分页片段。
  2. 数据解析: 查询通过 GraphQL 操作发送到后端服务器。该服务充当预先种子的内存数据库的中间件,该数据库包含合并信息,确保极低延迟。
  3. 状态处理: 网络响应改变客户端中不可变的全局状态 (NgRx Signals)。
  4. 响应式更新: 呈现组件(与网络逻辑无关)接收新数据(选定宝可梦的属性和分页网格)并相应地更新 DOM,反映诸如模型和基础属性等图形元素。

2. 整体架构与数据流

我设计的系统结合了后端 Clean Architecture 和 Domain-Driven Design (DDD) 原则,以及前端的容器/呈现者模式 (Smart/Dumb Components)。职责分离确保了高可维护性和可扩展性。

系统拓扑

下图说明了系统不同领域之间的交互:

graph TD
    subgraph Frontend [客户端 - Angular 19]
        UI_Layout[Layout/Smart 组件]
        UI_Dumb[Presentational 组件]
        Store[NgRx Signal Store]
        Service[GraphQL Service / Apollo]

        UI_Layout -->|派发动作| Store
        Store -->|提供响应式状态| UI_Layout
        UI_Layout -->|注入数据| UI_Dumb
        Store -->|调用方法| Service
    end

    subgraph Backend [服务端 - NestJS]
        Resolver[GraphQL Resolver]
        AppService[Application Service]
        Repository[In-Memory 仓库]
        Entities[Domain 实体]

        Service -->|GraphQL 查询| Resolver
        Resolver -->|依赖注入| AppService
        AppService -->|领域调用| Repository
        Repository -.->|映射| Entities
    end

    subgraph Data [初始持久化层]
        Seed[Seed Data JSON]
        PokeAPI[External PokeAPI]
        Repository -.->|初始水化| Seed
        Seed -.->|预缓存| PokeAPI
    end

后端架构

NestJS 服务端实现了分层抽象 (Domain-Driven Design):

  • 呈现层 (Resolvers): PokemonResolver 定义了 GraphQL 契约(自动生成的 Schema)并管理输入对象(过滤器、分页)。
  • 应用层 (Services): PokemonService 编排用例,如单个实体的检索和模糊搜索。
  • 基础设施层 (Repositories): InMemoryPokemonRepository 实现真正的持久化机制。在这种拓扑结构中,使用的是基于先前生成的种子数据集的内存存储。
  • 领域层 (Entities): 诸如 Pokemon、PokemonStats 和 PokemonMove 等类定义了业务核心。

前端架构

Angular 19 客户端使用 NgRx Signals 模型来实现高度可预测和高性能的状态管理:

  • PokemonStore 集中管理全局状态。它在内部使用响应式流 (RxJS) 来消除异步事件的碎片(如搜索的 debounce),然后更新基于 Signals 的状态。
  • 组件严格划分为负责布局/状态的组件和负责纯渲染的组件 (Glassmorphism UI)。

3. 数据建模与业务逻辑

主要实体 Pokemon 封装了相关数据的复杂性。

classDiagram
    class Pokemon {
        +String id
        +Number number
        +String name
        +String[] types
        +String description
        +PokemonPhysic physic
        +PokemonStats stats
        +PokemonEvolution evolution
        +PokemonMove[] moves
    }
    class PokemonStats {
        +Number health
        +Number attack
        +Number defense
        +Number resistance
        +Number speed
    }
    class PokemonMove {
        +String name
        +String type
        +Number damage
    }
    class PokemonPhysic {
        +Number weight
        +Number height
    }
    class PokemonEvolution {
        +String[] pre
        +String[] pos
    }

    Pokemon *-- PokemonStats
    Pokemon *-- PokemonMove
    Pokemon *-- PokemonPhysic
    Pokemon *-- PokemonEvolution

仓库中的搜索逻辑是通过在服务端应用链式过滤操作来解决的,首先评估输入 query 是否截获名称或数字索引,随后根据可选的类型过滤器过滤结果,最后解析对应于当前视图分页的子数组。

4. 技术栈

技术选型基于强类型以及面向事件和数据流的架构。

技术类别在架构中的技术角色
Angular 19前端框架响应式渲染引擎;组件生命周期与状态同步路由。
NgRx Signals状态管理全局状态管理器,改变响应式原子信号;降低标准消化循环的复杂性。
Apollo Client数据拉取具有优化缓存策略的 GraphQL 客户端(例如 cache-and-network)。
Tailwind CSS v4UI 样式PostCSS 架构下的实用程序 CSS 引擎,构建 Glassmorphism 层而无需僵化的组件库。
NestJS后端框架通过控制反转 (IoC) 进行模块化构建,支持企业级设计模式。
GraphQLAPI 层强类型查询接口,减少复杂数据模型的 over-fetching。
BiomeToolchain用于代码格式化和 linting 的统一工具,确保横向语法一致性。

5. 架构总结

前端容器/呈现者模式的巩固与后端的 GraphQL-to-DDD 架构相结合,清除了数据契约中的模糊性,并有效地将状态突变与 UI 中的副作用隔离。结合异步抽象进行内存映射,使系统能够以预先计算的高可用性响应,简化了服务端编排,并将处理集中在客户端层面的 Signals 响应式操作上。

拖动可移动图示。按 + 和 − 缩放,方向键移动,0 重置视图。

一起合作

软件工程师、高级全栈开发工程师,常驻玻利维亚Santa Cruz,远程办公。欢迎新的工作机会。