feat: scaffold frontend pnpm monorepo with apps (admin, web) and shared packages (types, api-client, ui)
This commit is contained in:
@@ -0,0 +1,46 @@
|
|||||||
|
# WTFX Frontend Monorepo Architecture
|
||||||
|
|
||||||
|
WTFX 前端采用 **pnpm workspace Monorepo + Feature-Driven 领域划分** 架构。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 架构总览
|
||||||
|
|
||||||
|
```
|
||||||
|
wtf-frontend/
|
||||||
|
├── apps/
|
||||||
|
│ ├── admin/ # 超级管理员控制台 (合约部署向导、协议治理、风险裁决)
|
||||||
|
│ │ └── src/
|
||||||
|
│ │ ├── routes/ # 路由页面 (dashboard, markets, governance, deploy)
|
||||||
|
│ │ └── features/ # 独立业务领域 (contract-deploy, protocol-governance, risk-control)
|
||||||
|
│ │
|
||||||
|
│ └── web/ # 用户端交易主站 (高频预测交易、图表、持仓)
|
||||||
|
│ └── src/
|
||||||
|
│ ├── routes/ # 路由页面 (markets, trade, portfolio, profile)
|
||||||
|
│ └── features/ # 独立业务领域 (market, trading, wallet, prediction)
|
||||||
|
│
|
||||||
|
├── packages/
|
||||||
|
│ ├── types/ # 【核心】全栈共享 TypeScript 数据类型 (Market, Order, Position)
|
||||||
|
│ ├── api-client/ # 【核心】统一 API SDK 客户端 (供 Web/Admin/后续 TMA 复用)
|
||||||
|
│ ├── ui/ # 共享 Trading UI 基础原子组件库
|
||||||
|
│ └── config/ # 共享 ESLint / TS / Tailwind 配置
|
||||||
|
│
|
||||||
|
├── package.json # Monorepo 根管理
|
||||||
|
└── pnpm-workspace.yaml # Workspace 定义
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 核心架构守则 (Frontend Architecture Rules)
|
||||||
|
|
||||||
|
1. **【Feature-Driven 组织业务】**:
|
||||||
|
- 业务代码按领域归类在 `src/features/<feature-name>/` 下,严禁在全局 `components/` 堆积上百个业务大泥球组件。
|
||||||
|
2. **【SDK 与 Type 唯一维护源】**:
|
||||||
|
- 所有前后端交互数据类型在 `packages/types` 统一定义;
|
||||||
|
- 所有 REST / GraphQL API 调用通过 `packages/api-client`,确保 Web、Admin 以及后续 TMA 共享同一套接口客户端。
|
||||||
|
3. **【按需抽象,拒绝过度设计】**:
|
||||||
|
- 业务特定的复杂图表/组件(如 TradingView 集成)优先放在 `apps/web/features/trading/` 中;
|
||||||
|
- 仅当多个 App(如 Admin 与 Web)真实产生复用时,才提取到 `packages/ui/`。
|
||||||
|
4. **【Admin 与 Web 严格独立部署】**:
|
||||||
|
- Admin 运行在 `:3100` (`admin.wtfx.app`),Web 运行在 `:3000` (`wtfx.app`);
|
||||||
|
- 两者拥有独立的路由体系与鉴权逻辑,严禁在同一 App 内通过 `if (isAdmin)` 揉杂代码。
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "@wtfx/admin",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev -p 3100",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start -p 3100"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@wtfx/types": "workspace:*",
|
||||||
|
"@wtfx/api-client": "workspace:*",
|
||||||
|
"@wtfx/ui": "workspace:*",
|
||||||
|
"react": "^18.3.1",
|
||||||
|
"react-dom": "^18.3.1",
|
||||||
|
"next": "^14.2.4",
|
||||||
|
"ethers": "^6.13.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "@wtfx/web",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev -p 3000",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start -p 3000"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@wtfx/types": "workspace:*",
|
||||||
|
"@wtfx/api-client": "workspace:*",
|
||||||
|
"@wtfx/ui": "workspace:*",
|
||||||
|
"react": "^18.3.1",
|
||||||
|
"react-dom": "^18.3.1",
|
||||||
|
"next": "^14.2.4",
|
||||||
|
"ethers": "^6.13.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "wtf-frontend-monorepo",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev:admin": "pnpm --filter @wtfx/admin dev",
|
||||||
|
"dev:web": "pnpm --filter @wtfx/web dev",
|
||||||
|
"build:admin": "pnpm --filter @wtfx/admin build",
|
||||||
|
"build:web": "pnpm --filter @wtfx/web build",
|
||||||
|
"lint": "pnpm -r lint"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.4.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"name": "@wtfx/api-client",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "./src/index.ts",
|
||||||
|
"dependencies": {
|
||||||
|
"@wtfx/types": "workspace:*"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { Market, Order, Position, GovernanceConfig } from '@wtfx/types';
|
||||||
|
|
||||||
|
export class WtfxApiClient {
|
||||||
|
private baseUrl: string;
|
||||||
|
|
||||||
|
constructor(baseUrl: string) {
|
||||||
|
this.baseUrl = baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMarkets(): Promise<Market[]> {
|
||||||
|
const res = await fetch(`${this.baseUrl}/api/v1/markets`);
|
||||||
|
return res.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMarket(marketAddress: string): Promise<Market> {
|
||||||
|
const res = await fetch(`${this.baseUrl}/api/v1/markets/${marketAddress}`);
|
||||||
|
return res.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getPositions(userAddress: string): Promise<Position[]> {
|
||||||
|
const res = await fetch(`${this.baseUrl}/api/v1/positions?user=${userAddress}`);
|
||||||
|
return res.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getGovernanceConfig(): Promise<GovernanceConfig> {
|
||||||
|
const res = await fetch(`${this.baseUrl}/api/v1/governance`);
|
||||||
|
return res.json();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "@wtfx/types",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "./src/index.ts",
|
||||||
|
"types": "./src/index.ts"
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
export interface Market {
|
||||||
|
questionId: string;
|
||||||
|
marketAddress: string;
|
||||||
|
title: string;
|
||||||
|
imageUri?: string;
|
||||||
|
outcomeNames: string[];
|
||||||
|
status: 'Trading' | 'Graduated' | 'Finalised' | 'Refunded';
|
||||||
|
tierId: number;
|
||||||
|
totalMarketCap: string;
|
||||||
|
timestampEnd: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Order {
|
||||||
|
id: string;
|
||||||
|
marketAddress: string;
|
||||||
|
outcomeIndex: number;
|
||||||
|
side: 'BUY' | 'SELL';
|
||||||
|
amount: string;
|
||||||
|
price: string;
|
||||||
|
status: 'OPEN' | 'FILLED' | 'CANCELLED';
|
||||||
|
createdAt: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Position {
|
||||||
|
marketAddress: string;
|
||||||
|
tokenId: string;
|
||||||
|
outcomeName: string;
|
||||||
|
shares: string;
|
||||||
|
avgCost: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GovernanceConfig {
|
||||||
|
creatorShare: string;
|
||||||
|
centralWallet: string;
|
||||||
|
defaultFeeRate: string;
|
||||||
|
disputeWindow: number;
|
||||||
|
tiers: Record<number, {
|
||||||
|
thresholdMcap: string;
|
||||||
|
thresholdMaxSupply: string;
|
||||||
|
disputeWindow: number;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "@wtfx/ui",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "./src/index.ts"
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export const UI_VERSION = "1.0.0";
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
packages:
|
||||||
|
- 'apps/*'
|
||||||
|
- 'packages/*'
|
||||||
Reference in New Issue
Block a user