commit af4de6b86a21ad39136f307427fe3450371a4dee Author: fischer Date: Mon May 25 09:50:16 2026 +0800 feat: FischerX开发底座初始化提交 - Monorepo架构(pnpm + Turborepo) - 前端:Next.js + TypeScript + Tailwind CSS + Shadcn UI - 后端:NestJS + Prisma + PostgreSQL + Redis - 核心模块:用户管理、认证授权、权限控制、文件存储 - 业务模块:支付系统、消息通知、内容管理 - 基础设施:Docker、K8s、Terraform、CI/CD - 监控告警:Prometheus + Grafana + Loki + Jaeger - CLI工具:@fischerx/cli - 文档体系:9大类30+文档 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8691b78 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab + +[*.{json,yml,yaml}] +indent_size = 2 + +[*.{ts,tsx,js,jsx}] +indent_size = 2 diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..2711a31 --- /dev/null +++ b/.env.example @@ -0,0 +1,25 @@ +NODE_ENV=development + +DB_HOST=postgres +DB_PORT=5432 +DB_USER=fischerx +DB_PASSWORD=fischerx +DB_NAME=fischerx + +REDIS_HOST=redis +REDIS_PORT=6379 +REDIS_PASSWORD= + +API_PORT=3001 +WEB_PORT=3000 + +NEXT_PUBLIC_API_URL=http://localhost:3001 + +JWT_SECRET=your-super-secret-jwt-key-change-in-production +JWT_EXPIRES_IN=7d + +ALIBABA_CLOUD_ACCESS_KEY_ID= +ALIBABA_CLOUD_ACCESS_KEY_SECRET= +OSS_REGION= +OSS_BUCKET= +OSS_ENDPOINT= diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..d2b80c9 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,24 @@ +module.exports = { + root: true, + env: { + node: true, + es2020: true, + }, + parser: "@typescript-eslint/parser", + parserOptions: { + ecmaVersion: 2020, + sourceType: "module", + }, + plugins: ["@typescript-eslint"], + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + ], + rules: { + "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-explicit-any": "warn", + }, + ignorePatterns: ["node_modules", "dist", ".next", "coverage"], +}; diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..56203ed --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,44 @@ +version: 2 + +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + timezone: "Asia/Shanghai" + open-pull-requests-limit: 10 + reviewers: + - "your-team-member" + labels: + - "dependencies" + - "npm" + allow: + - dependency-type: "direct" + ignore: + - dependency-name: "*" + update-types: ["version-update:semver-major"] + commit-message: + prefix: "deps" + include: "scope" + groups: + production-dependencies: + dependency-type: "production" + development-dependencies: + dependency-type: "development" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + timezone: "Asia/Shanghai" + open-pull-requests-limit: 5 + labels: + - "dependencies" + - "github-actions" + commit-message: + prefix: "ci" + include: "scope" diff --git a/.github/release-please.yml b/.github/release-please.yml new file mode 100644 index 0000000..3baf3a7 --- /dev/null +++ b/.github/release-please.yml @@ -0,0 +1,37 @@ +release-type: node +package-name: fischerx +bump-minor-pre-major: true +bump-patch-for-minor-pre-major: true +changelog-type: "markdown" +include-v-in-tag: true +changelog-file: CHANGELOG.md +skip-github-release: false +skip-git-push: false +signoff: "false" +draft: false +prerelease: false +pull-request-title-pattern: "chore: release ${version}" +labels: + - "release" + +changelog-sections: + - type: feat + section: Features + - type: fix + section: Bug Fixes + - type: perf + section: Performance Improvements + - type: refactor + section: Refactors + - type: docs + section: Documentation + - type: style + section: Style + - type: test + section: Tests + - type: ci + section: CI/CD + - type: build + section: Build + - type: chore + section: Chores diff --git a/.github/semantic.yml b/.github/semantic.yml new file mode 100644 index 0000000..ef976ba --- /dev/null +++ b/.github/semantic.yml @@ -0,0 +1,33 @@ +titleAndCommits: true +alwaysValidate: true +allowMergeCommits: false +allowRevertCommits: false + +enabled: true + +types: + - feat + - fix + - docs + - style + - refactor + - perf + - test + - build + - ci + - chore + - revert + +scopes: + - api + - web + - admin + - core + - infra + - docs + - ci + - build + - deps + - release + +allowTicketNumberPrefix: false diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..a5047ab --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,131 @@ +name: Build and Docker + +on: + push: + branches: [main, develop] + tags: + - 'v*' + pull_request: + branches: [main, develop] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +env: + REGISTRY: registry.cn-hangzhou.aliyuncs.com + IMAGE_NAME: ${{ github.repository }} + +jobs: + build: + name: Build Project + runs-on: ubuntu-latest + timeout-minutes: 30 + outputs: + image_tag: ${{ steps.meta.outputs.tags }} + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'pnpm' + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Setup pnpm cache + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Setup Turbo cache + uses: actions/cache@v4 + with: + path: .turbo + key: ${{ runner.os }}-turbo-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-turbo- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build project + run: pnpm build + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: build-artifacts + path: | + apps/**/dist + apps/**/.next + services/**/dist + packages/**/dist + retention-days: 7 + + docker: + name: Build and Push Docker Image + needs: build + runs-on: ubuntu-latest + if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' || startsWith(github.ref, 'refs/tags/v')) + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: build-artifacts + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Aliyun Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.ALIYUN_REGISTRY_USERNAME }} + password: ${{ secrets.ALIYUN_REGISTRY_PASSWORD }} + + - name: Extract metadata for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml new file mode 100644 index 0000000..5eccc20 --- /dev/null +++ b/.github/workflows/deploy-dev.yml @@ -0,0 +1,75 @@ +name: Deploy to Development Environment + +on: + push: + branches: [develop] + workflow_dispatch: + +concurrency: + group: deploy-dev + cancel-in-progress: false + +env: + ENVIRONMENT: development + REGISTRY: registry.cn-hangzhou.aliyuncs.com + IMAGE_NAME: ${{ github.repository }} + +jobs: + deploy: + name: Deploy to Dev + runs-on: ubuntu-latest + environment: + name: development + url: https://dev.fischerx.com + timeout-minutes: 30 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup kubectl + uses: azure/setup-kubectl@v4 + with: + version: 'v1.28.0' + + - name: Configure Kubernetes credentials + run: | + mkdir -p ~/.kube + echo "${{ secrets.KUBE_CONFIG_DEV }}" | base64 -d > ~/.kube/config + chmod 600 ~/.kube/config + + - name: Verify Kubernetes connection + run: kubectl cluster-info + + - name: Log in to Aliyun Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.ALIYUN_REGISTRY_USERNAME }} + password: ${{ secrets.ALIYUN_REGISTRY_PASSWORD }} + + - name: Deploy to Kubernetes + run: | + echo "Deploying to development environment..." + # 这里可以添加具体的部署脚本,比如使用 kubectl apply 或 helm + # 示例: + # kubectl set image deployment/fischerx-api fischerx-api=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:develop + # kubectl rollout status deployment/fischerx-api + + - name: Run database migrations + run: | + echo "Running database migrations..." + # 这里可以添加数据库迁移命令 + + - name: Health check + run: | + echo "Running health checks..." + # 这里可以添加健康检查脚本 + + - name: Send deployment notification + if: always() + uses: 8398a7/action-slack@v3 + with: + status: ${{ job.status }} + text: 'Deployment to development environment ${{ job.status }}' + webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml new file mode 100644 index 0000000..070050e --- /dev/null +++ b/.github/workflows/deploy-prod.yml @@ -0,0 +1,99 @@ +name: Deploy to Production Environment + +on: + push: + tags: + - 'v*-prod' + workflow_dispatch: + +concurrency: + group: deploy-prod + cancel-in-progress: false + +env: + ENVIRONMENT: production + REGISTRY: registry.cn-hangzhou.aliyuncs.com + IMAGE_NAME: ${{ github.repository }} + +jobs: + approval: + name: Approval Required + runs-on: ubuntu-latest + environment: + name: production + url: https://fischerx.com + steps: + - name: Wait for approval + run: echo "Deployment waiting for manual approval..." + + deploy: + name: Deploy to Production + needs: approval + runs-on: ubuntu-latest + environment: + name: production + url: https://fischerx.com + timeout-minutes: 60 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup kubectl + uses: azure/setup-kubectl@v4 + with: + version: 'v1.28.0' + + - name: Configure Kubernetes credentials + run: | + mkdir -p ~/.kube + echo "${{ secrets.KUBE_CONFIG_PROD }}" | base64 -d > ~/.kube/config + chmod 600 ~/.kube/config + + - name: Verify Kubernetes connection + run: kubectl cluster-info + + - name: Log in to Aliyun Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.ALIYUN_REGISTRY_USERNAME }} + password: ${{ secrets.ALIYUN_REGISTRY_PASSWORD }} + + - name: Extract tag version + id: extract_version + run: | + TAG=${GITHUB_REF#refs/tags/} + VERSION=${TAG%%-prod} + echo "VERSION=$VERSION" >> $GITHUB_OUTPUT + + - name: Run pre-deployment checks + run: | + echo "Running pre-deployment checks..." + # 这里添加部署前检查 + + - name: Deploy to Kubernetes (Canary/Blue-Green) + run: | + echo "Deploying version ${{ steps.extract_version.outputs.VERSION }} to production..." + # 这里添加具体的部署脚本,支持 Canary 或 Blue-Green 部署 + # 示例: + # kubectl set image deployment/fischerx-api fischerx-api=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.extract_version.outputs.VERSION }} + # kubectl rollout status deployment/fischerx-api + + - name: Run database migrations + run: | + echo "Running database migrations..." + # 这里添加数据库迁移命令 + + - name: Health check + run: | + echo "Running health checks..." + # 这里添加健康检查脚本 + + - name: Send deployment notification + if: always() + uses: 8398a7/action-slack@v3 + with: + status: ${{ job.status }} + text: 'Deployment to production environment ${{ job.status }}' + webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/deploy-test.yml b/.github/workflows/deploy-test.yml new file mode 100644 index 0000000..00fbda1 --- /dev/null +++ b/.github/workflows/deploy-test.yml @@ -0,0 +1,88 @@ +name: Deploy to Test Environment + +on: + push: + tags: + - 'v*-test' + workflow_dispatch: + +concurrency: + group: deploy-test + cancel-in-progress: false + +env: + ENVIRONMENT: test + REGISTRY: registry.cn-hangzhou.aliyuncs.com + IMAGE_NAME: ${{ github.repository }} + +jobs: + deploy: + name: Deploy to Test + runs-on: ubuntu-latest + environment: + name: test + url: https://test.fischerx.com + timeout-minutes: 45 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup kubectl + uses: azure/setup-kubectl@v4 + with: + version: 'v1.28.0' + + - name: Configure Kubernetes credentials + run: | + mkdir -p ~/.kube + echo "${{ secrets.KUBE_CONFIG_TEST }}" | base64 -d > ~/.kube/config + chmod 600 ~/.kube/config + + - name: Verify Kubernetes connection + run: kubectl cluster-info + + - name: Log in to Aliyun Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ secrets.ALIYUN_REGISTRY_USERNAME }} + password: ${{ secrets.ALIYUN_REGISTRY_PASSWORD }} + + - name: Extract tag version + id: extract_version + run: | + TAG=${GITHUB_REF#refs/tags/} + VERSION=${TAG%%-test} + echo "VERSION=$VERSION" >> $GITHUB_OUTPUT + + - name: Deploy to Kubernetes + run: | + echo "Deploying version ${{ steps.extract_version.outputs.VERSION }} to test environment..." + # 这里添加具体的部署脚本 + # 示例: + # kubectl set image deployment/fischerx-api fischerx-api=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.extract_version.outputs.VERSION }} + # kubectl rollout status deployment/fischerx-api + + - name: Run database migrations + run: | + echo "Running database migrations..." + # 这里添加数据库迁移命令 + + - name: Run integration tests + run: | + echo "Running integration tests..." + # 这里添加集成测试命令 + + - name: Health check + run: | + echo "Running health checks..." + # 这里添加健康检查脚本 + + - name: Send deployment notification + if: always() + uses: 8398a7/action-slack@v3 + with: + status: ${{ job.status }} + text: 'Deployment to test environment ${{ job.status }}' + webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..b1e1c63 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,72 @@ +name: Lint and Code Quality Check + +on: + push: + branches: [main, develop] + paths-ignore: + - '**/*.md' + - '**/*.gitignore' + - '**/*.gitattributes' + pull_request: + branches: [main, develop] + paths-ignore: + - '**/*.md' + - '**/*.gitignore' + - '**/*.gitattributes' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + lint: + name: Lint Check + runs-on: ubuntu-latest + timeout-minutes: 15 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'pnpm' + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Setup pnpm cache + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: TypeScript type check + run: pnpm exec tsc --noEmit + + - name: ESLint check + run: pnpm lint + + - name: Prettier format check + run: pnpm format --check + + - name: Check commit messages (PR only) + if: github.event_name == 'pull_request' + uses: wagoid/commitlint-github-action@v5 diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 0000000..2c20a8c --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,20 @@ +name: Release Please + +on: + push: + branches: [main] + +permissions: + contents: write + pull-requests: write + +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - name: Release Please + uses: google-github-actions/release-please-action@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + release-type: node + package-name: fischerx diff --git a/.github/workflows/semantic-pr.yml b/.github/workflows/semantic-pr.yml new file mode 100644 index 0000000..182a985 --- /dev/null +++ b/.github/workflows/semantic-pr.yml @@ -0,0 +1,25 @@ +name: Semantic PR + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + - labeled + - unlabeled + +permissions: + pull-requests: read + +jobs: + main: + name: Validate PR title + runs-on: ubuntu-latest + steps: + - name: Semantic Pull Request + uses: amannn/action-semantic-pull-request@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + configPath: .github/semantic.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..dcd218c --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,82 @@ +name: Test and Coverage + +on: + push: + branches: [main, develop] + paths-ignore: + - '**/*.md' + pull_request: + branches: [main, develop] + paths-ignore: + - '**/*.md' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + test: + name: Run Tests + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + matrix: + node-version: [18, 20] + fail-fast: false + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: 'pnpm' + + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Setup pnpm cache + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build project for test + run: pnpm build + + - name: Run tests with coverage + run: pnpm test -- --coverage + + - name: Upload coverage to Codecov + if: matrix.node-version == 20 + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage/lcov.info + flags: unittests + name: codecov-umbrella + fail_ci_if_error: false + + - name: Upload coverage artifacts + uses: actions/upload-artifact@v4 + with: + name: coverage-report-${{ matrix.node-version }} + path: coverage/ + retention-days: 30 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0bca663 --- /dev/null +++ b/.gitignore @@ -0,0 +1,54 @@ +# Dependencies +node_modules/ +.pnp +.pnp.js + +# Build outputs +dist/ +build/ +.next/ +out/ + +# Testing +coverage/ +.nyc_output/ + +# Environment variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +# Turbo +.turbo/ + +# Prisma +packages/core/prisma/migrations/ + +# Documentation generated +docs/api/generated/ + +# Temporary files +*.tmp +*.temp +.cache/ diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..59bd680 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,11 @@ +{ + "semi": true, + "trailingComma": "es5", + "singleQuote": false, + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "bracketSpacing": true, + "arrowParens": "always", + "endOfLine": "lf" +} diff --git a/.trae/specs/initialize-fischerx-foundation/checklist.md b/.trae/specs/initialize-fischerx-foundation/checklist.md new file mode 100644 index 0000000..644f03b --- /dev/null +++ b/.trae/specs/initialize-fischerx-foundation/checklist.md @@ -0,0 +1,282 @@ +# FischerX 开发底座验收清单 + +## 第一阶段验收标准:基础架构搭建 + +### 项目架构验收 +- [ ] Monorepo项目结构完整创建(apps、packages、services、infra、docs、tools目录) +- [ ] pnpm工作空间配置正确,依赖管理正常 +- [ ] Turborepo构建系统配置正确,增量构建工作正常 +- [ ] ESLint、Prettier、TypeScript配置正确,代码规范检查通过 +- [ ] README.md文档完整,包含项目介绍、快速开始、开发指南 + +### 前端应用验收 +- [ ] Next.js 14+ Web应用创建成功,App Router配置正确 +- [ ] TypeScript配置正确,类型检查通过(npx tsc --noEmit) +- [ ] Tailwind CSS配置正确,样式系统工作正常 +- [ ] Shadcn UI组件库集成成功,组件可正常使用 +- [ ] Zustand状态管理配置正确,状态管理功能正常 +- [ ] React Query配置正确,数据获取功能正常 +- [ ] Vitest和Playwright测试框架配置正确,测试可正常运行 +- [ ] 前端应用可正常启动(npm run dev),页面可正常访问 + +### 后端API服务验收 +- [ ] NestJS API服务创建成功,服务可正常启动 +- [ ] Prisma ORM配置正确,数据库连接正常 +- [ ] 数据库Schema设计完整(用户、权限、文件等基础表) +- [ ] API路由和控制器结构清晰,符合RESTful规范 +- [ ] JWT认证中间件配置正确,Token生成和验证正常 +- [ ] Redis缓存连接正常,缓存功能可用 +- [ ] 后端服务可正常启动(npm run start:dev),API可正常访问 + +### 共享包验收 +- [ ] packages/core核心业务逻辑包创建成功 +- [ ] packages/ui共享UI组件包创建成功,组件可复用 +- [ ] packages/utils工具函数包创建成功,函数可复用 +- [ ] packages/types类型定义包创建成功,类型可共享 +- [ ] packages/config配置管理包创建成功,配置可共享 +- [ ] packages/constants常量定义包创建成功,常量可共享 + +### 用户管理模块验收 +- [ ] 用户注册功能正常(手机号、邮箱注册) +- [ ] 用户登录功能正常(验证码登录、密码登录) +- [ ] 用户信息管理功能正常(查询、更新、删除) +- [ ] 用户头像上传和管理功能正常 +- [ ] 用户管理前端页面正常显示,功能完整 +- [ ] 用户管理单元测试通过,覆盖率>80% + +### 认证授权模块验收 +- [ ] JWT Token生成和验证功能正常 +- [ ] Session管理功能正常(创建、刷新、销毁) +- [ ] 手机号验证码登录功能正常(阿里云短信集成) +- [ ] 微信OAuth登录功能正常 +- [ ] 支付宝OAuth登录功能正常 +- [ ] 实名认证功能正常(阿里云实名认证集成) +- [ ] 登录注册前端页面正常显示,功能完整 +- [ ] 认证授权单元测试通过,覆盖率>80% + +### 权限控制模块验收 +- [ ] RBAC权限模型设计完整(角色、权限、资源) +- [ ] 角色管理功能正常(创建、更新、删除) +- [ ] 权限分配功能正常 +- [ ] 权限验证中间件工作正常,未授权访问被拒绝 +- [ ] 动态权限检查功能正常 +- [ ] 权限管理前端页面正常显示,功能完整 +- [ ] 权限控制单元测试通过,覆盖率>80% + +### 文件存储模块验收 +- [ ] 阿里云OSS存储适配器实现正确,上传下载功能正常 +- [ ] 腾讯云COS存储适配器实现正确(备选方案) +- [ ] MinIO私有化存储适配器实现正确(备选方案) +- [ ] 文件上传功能正常(单文件、多文件) +- [ ] 文件下载和删除功能正常 +- [ ] 图片处理功能正常(压缩、裁剪、水印) +- [ ] CDN加速配置正确,访问速度优化 +- [ ] 文件管理前端页面正常显示,功能完整 +- [ ] 文件存储单元测试通过,覆盖率>80% + +### 基础设施验收 +- [ ] Docker配置文件正确,容器可正常构建和运行 +- [ ] Kubernetes配置文件正确,Pod可正常部署 +- [ ] 阿里云ACK集群配置正确,集群可正常访问 +- [ ] 阿里云RDS PostgreSQL数据库配置正确,数据库可正常访问 +- [ ] 阿里云Redis缓存配置正确,缓存可正常访问 +- [ ] 阿里云OSS对象存储配置正确,存储可正常访问 +- [ ] 阿里云CDN加速配置正确,加速功能正常 +- [ ] 阿里云DNS解析配置正确,域名解析正常 + +### CI/CD流程验收 +- [ ] 阿里云云效CI/CD流程配置正确,流程可正常运行 +- [ ] 代码规范检查流程正常,检查结果准确 +- [ ] 单元测试流程正常,测试结果准确 +- [ ] 构建流程正常,构建产物正确 +- [ ] 自动部署流程正常,部署成功 +- [ ] 代码提交钩子正常,钩子触发正确 + +### 开发文档验收 +- [ ] 架构设计文档完整,包含架构图和说明 +- [ ] 快速开始指南完整,开发者可快速上手 +- [ ] 开发规范文档完整,规范清晰明确 +- [ ] API接口文档完整,接口说明清晰 +- [ ] 部署指南完整,部署步骤清晰 +- [ ] 常见问题解答完整,问题覆盖全面 +- [ ] 底座使用方式指南完整,使用方式清晰明确 + +### CLI工具验收 +- [ ] CLI工具框架创建成功,工具可正常运行 +- [ ] create-app命令功能正常,新应用创建成功 +- [ ] init命令功能正常,独立项目初始化成功 +- [ ] deploy-service命令功能正常,共享服务部署成功 +- [ ] update命令功能正常,底座版本更新成功 +- [ ] generate-module命令功能正常,业务模块生成成功 +- [ ] 项目模板创建完整(standalone、monorepo、lightweight) +- [ ] CLI工具文档完整,使用指南清晰 + +### 底座使用方式验收 +- [ ] Monorepo模式使用正常,新应用可正常创建和运行 +- [ ] 独立项目模式使用正常,独立项目可正常创建和运行 +- [ ] API服务模式使用正常,共享服务可正常部署和调用 +- [ ] 核心功能共享策略明确,共享功能划分清晰 +- [ ] 版本管理和更新策略完善,更新流程清晰 +- [ ] 配置化驱动功能正常,配置定制功能可用 + +## 第二阶段验收标准:业务模块开发 + +### 支付系统模块验收 +- [ ] 微信支付集成正确,扫码支付、H5支付、小程序支付功能正常 +- [ ] 支付宝支付集成正确,扫码支付、H5支付功能正常 +- [ ] 银联支付集成正确(备选方案) +- [ ] 订单管理功能正常(创建、查询、状态管理) +- [ ] 退款处理功能正常 +- [ ] 支付回调处理正确,回调验证成功 +- [ ] 支付管理前端页面正常显示,功能完整 +- [ ] 支付系统单元测试通过,覆盖率>80% + +### 消息通知模块验收 +- [ ] 阿里云短信服务集成正确,验证码、通知短信发送正常 +- [ ] 邮件通知功能正常,邮件发送成功 +- [ ] 小程序推送通知功能正常,推送成功 +- [ ] App推送通知功能正常(阿里云移动推送),推送成功 +- [ ] 站内消息功能正常,消息发送和接收正常 +- [ ] 消息通知管理前端页面正常显示,功能完整 +- [ ] 消息通知单元测试通过,覆盖率>80% + +### 内容管理模块验收 +- [ ] 内容发布功能正常(文章、图片、视频) +- [ ] 内容审核功能正常(阿里云内容审核集成),审核结果准确 +- [ ] 评论管理功能正常,评论发布和管理正常 +- [ ] 标签分类功能正常,标签创建和管理正常 +- [ ] 内容搜索功能正常,搜索结果准确 +- [ ] 内容管理前端页面正常显示,功能完整 +- [ ] 内容管理单元测试通过,覆盖率>80% + +### 订单系统模块验收 +- [ ] 订单创建功能正常,订单创建成功 +- [ ] 订单状态管理功能正常,状态流转正确 +- [ ] 订单查询功能正常,查询结果准确 +- [ ] 订单统计功能正常,统计数据准确 +- [ ] 订单管理前端页面正常显示,功能完整 +- [ ] 订单系统单元测试通过,覆盖率>80% + +### 第三方服务集成验收 +- [ ] 高德地图服务集成正确,地图功能正常 +- [ ] 百度AI服务集成正确(OCR、人脸识别),AI功能正常 +- [ ] 阿里云AI服务集成正确(备选方案) +- [ ] 实名认证服务集成正确(阿里云、腾讯云),认证功能正常 +- [ ] OCR识别服务集成正确(身份证、银行卡),识别功能正常 +- [ ] 第三方服务集成单元测试通过,覆盖率>80% + +### 监控告警系统验收 +- [ ] 阿里云ARMS应用监控配置正确,监控数据准确 +- [ ] Prometheus + Grafana监控配置正确(备选方案) +- [ ] Sentry错误追踪配置正确,错误追踪正常 +- [ ] 性能指标监控正常,监控数据准确 +- [ ] 业务指标监控正常,监控数据准确 +- [ ] 告警规则配置正确,告警触发正常 +- [ ] 监控仪表盘前端页面正常显示,数据可视化清晰 + +### 日志服务验收 +- [ ] 阿里云SLS日志服务配置正确,日志收集正常 +- [ ] 日志收集功能正常,日志完整收集 +- [ ] 日志分析功能正常,日志查询和统计准确 +- [ ] 日志告警功能正常,告警触发正确 +- [ ] 日志留存策略配置正确,留存时间>6个月 + +### 测试完善验收 +- [ ] 前端单元测试覆盖率>80% +- [ ] 后端单元测试覆盖率>80% +- [ ] 集成测试通过,测试结果准确 +- [ ] E2E测试通过,测试结果准确 +- [ ] 测试报告生成正常,报告清晰完整 +- [ ] 测试覆盖率报告生成正常,覆盖率数据准确 + +## 第三阶段验收标准:优化和上线 + +### 性能优化验收 +- [ ] 前端性能优化完成,首屏加载时间<3秒 +- [ ] 后端性能优化完成,API响应时间<200ms +- [ ] CDN加速优化完成,静态资源加载速度提升 +- [ ] 负载均衡配置正确,流量分发正常 +- [ ] 数据库索引优化完成,查询性能提升 +- [ ] 性能测试通过,性能指标达标 +- [ ] 压力测试通过,系统稳定性达标 + +### 安全加固验收 +- [ ] 安全审计完成,无高危漏洞 +- [ ] 漏洞扫描完成,漏洞已修复 +- [ ] 数据加密完成,敏感数据加密存储 +- [ ] SQL注入防护完成,注入攻击被阻止 +- [ ] XSS防护完成,XSS攻击被阻止 +- [ ] CSRF防护完成,CSRF攻击被阻止 +- [ ] API访问频率限制完成,频率限制正常 + +### 合规性检查验收 +- [ ] ICP备案申请完成,备案成功 +- [ ] 数据本地化存储配置完成,数据存储在国内 +- [ ] 实名认证流程完善,认证流程合规 +- [ ] 内容审核流程完善,审核流程合规 +- [ ] 数据安全法合规检查完成,合规达标 +- [ ] 个人信息保护法合规检查完成,合规达标 + +### 生产环境部署验收 +- [ ] 生产环境资源配置完成,资源充足 +- [ ] 生产环境配置文件准备完成,配置正确 +- [ ] 数据迁移脚本编写完成,迁移脚本正确 +- [ ] 灰度发布配置完成,灰度发布正常 +- [ ] 全量上线部署完成,部署成功 +- [ ] 上线后验证测试通过,功能正常 + +### 运维体系验收 +- [ ] 监控告警完善,监控覆盖全面 +- [ ] 日志分析系统完善,日志分析准确 +- [ ] 故障响应流程建立,流程清晰明确 +- [ ] 备份恢复机制建立,备份恢复正常 +- [ ] 运维文档编写完成,文档完整清晰 +- [ ] 运维培训完成,培训效果良好 + +## 整体验收标准 + +### 功能完整性验收 +- [ ] 所有核心功能模块实现完整,功能可用 +- [ ] 所有业务功能模块实现完整,功能可用 +- [ ] 所有第三方服务集成完整,服务可用 +- [ ] 所有前端页面实现完整,页面可用 + +### 性能指标验收 +- [ ] 前端首屏加载时间<3秒 +- [ ] API响应时间<200ms(P95) +- [ ] 系统吞吐量>1000 QPS +- [ ] 系统可用性>99.9% + +### 安全性验收 +- [ ] 无高危安全漏洞 +- [ ] 数据加密存储 +- [ ] 访问控制完善 +- [ ] 安全审计通过 + +### 合规性验收 +- [ ] ICP备案完成 +- [ ] 数据本地化存储 +- [ ] 实名认证合规 +- [ ] 内容审核合规 +- [ ] 数据安全法合规 +- [ ] 个人信息保护法合规 + +### 文档完整性验收 +- [ ] 架构设计文档完整 +- [ ] API文档完整 +- [ ] 开发指南完整 +- [ ] 部署指南完整 +- [ ] 运维文档完整 + +### 测试覆盖率验收 +- [ ] 前端单元测试覆盖率>80% +- [ ] 后端单元测试覆盖率>80% +- [ ] 集成测试覆盖完整 +- [ ] E2E测试覆盖完整 + +### 可维护性验收 +- [ ] 代码规范统一 +- [ ] 模块划分清晰 +- [ ] 文档完善 +- [ ] 监控告警完善 +- [ ] 日志系统完善 \ No newline at end of file diff --git a/.trae/specs/initialize-fischerx-foundation/spec.md b/.trae/specs/initialize-fischerx-foundation/spec.md new file mode 100644 index 0000000..a8398e9 --- /dev/null +++ b/.trae/specs/initialize-fischerx-foundation/spec.md @@ -0,0 +1,333 @@ +# FischerX 开发底座初始化 Spec + +## Why + +Fischer公司需要一个适配国内运行环境的开发底座,类似John Rush的Mars Stack/Mars Foundation理念,用于快速构建业务模块,降低开发成本,提升开发效率。当前项目为全新项目,需要先明确整体架构和未来使用方式,然后根据国内环境逐一完善功能模块。 + +## What Changes + +- 创建完整的Monorepo项目架构 +- 搭建基础开发框架(前端、后端、数据库) +- 实现核心基础模块(用户管理、认证授权、权限控制、文件存储) +- 集成国内云服务和第三方服务(阿里云、微信支付、支付宝等) +- 建立完整的开发文档和规范体系 +- 配置CI/CD流程和基础设施 + +## Impact + +- Affected specs: 全新项目,无现有spec +- Affected code: 全新项目,需要从零开始构建 + +## ADDED Requirements + +### Requirement: 项目架构设计 + +系统SHALL采用Monorepo架构,支持多应用、多包的统一管理。 + +#### Scenario: Monorepo架构搭建 +- **WHEN** 项目初始化时 +- **THEN** 系统应创建以下目录结构: + - apps/:应用层(web、admin、mobile、miniapp) + - packages/:共享包(core、ui、utils、types、config) + - services/:后端服务(api、worker、realtime) + - infra/:基础设施配置 + - docs/:文档目录 + - tools/:开发工具(包含CLI工具) + +#### Scenario: 技术栈选择 +- **WHEN** 选择技术栈时 +- **THEN** 系统应采用以下技术组合(推荐Node.js全栈方案): + - 前端:Next.js 14+ + TypeScript + Tailwind CSS + Shadcn UI + - 后端:NestJS + Prisma + PostgreSQL + - 缓存:Redis + - 消息队列:RabbitMQ + - 存储:阿里云OSS + - 部署:Docker + Kubernetes + 阿里云ACK + +### Requirement: 底座使用方式设计 + +系统SHALL提供灵活的底座使用方式,支持多种业务场景。 + +#### Scenario: Monorepo模式使用(适合同一团队的多项目) +- **WHEN** Fischer公司内部开发新业务系统时 +- **THEN** 系统应支持: + - 在FischerX Monorepo中创建新应用(apps/) + - 自动继承packages中的共享包(core、ui、utils等) + - 共享基础设施配置和CI/CD流程 + - 统一维护和升级核心功能 + +#### Scenario: 独立项目模式使用(适合不同客户的项目) +- **WHEN** 为客户开发定制系统时 +- **THEN** 系统应支持: + - 从FischerX模板创建独立项目 + - 复制核心包到新项目(packages/core、packages/ui等) + - 自由定制业务功能,不影响其他项目 + - 选择性更新底座功能 + +#### Scenario: API服务模式使用(适合轻量级集成) +- **WHEN** 需要快速集成底座功能时 +- **THEN** 系统应支持: + - 部署FischerX作为共享服务(auth-service、file-service等) + - 新业务系统通过API调用底座功能 + - 使用客户端SDK简化集成(@fischerx/client-sdk) + - 统一维护底座服务,自动升级 + +#### Scenario: CLI工具支持 +- **WHEN** 开发者需要创建新项目或应用时 +- **THEN** 系统应提供CLI工具(fischerx-cli),支持: + - 创建新应用:`fischerx-cli create-app --type=web|admin|mobile|miniapp` + - 初始化独立项目:`fischerx-cli init --template=standalone|monorepo|lightweight` + - 部署共享服务:`fischerx-cli deploy-service --services=` + - 更新底座版本:`fischerx-cli update --scope=core|ui|all` + - 生成业务模块:`fischerx-cli generate-module --template=crud|cms|ecommerce` + +#### Scenario: 核心功能共享策略 +- **WHEN** 设计底座功能模块时 +- **THEN** 系统应明确区分: + - **核心共享功能**(packages/core):用户管理、认证授权、权限控制、文件存储、消息通知 + - **可选共享功能**(packages/ui、packages/utils):UI组件、工具函数、类型定义 + - **业务独立功能**(apps//src):业务逻辑、特定UI、定制功能 + - **配置化驱动**:通过配置而非代码实现业务定制 + +#### Scenario: 版本管理和更新策略 +- **WHEN** 底座功能更新时 +- **THEN** 系统应支持: + - Monorepo模式:自动更新所有应用 + - 独立项目模式:选择性更新(通过CLI工具) + - API服务模式:自动更新所有调用方 + - 版本兼容性检查和迁移指南 + +### Requirement: 用户管理模块 + +系统SHALL提供完整的用户管理功能,支持国内主流认证方式。 + +#### Scenario: 用户注册登录 +- **WHEN** 用户需要注册或登录时 +- **THEN** 系统应支持以下认证方式: + - 手机号验证码登录(阿里云短信) + - 微信登录(OAuth) + - 支付宝登录(OAuth) + - 传统邮箱密码登录 + +#### Scenario: 实名认证 +- **WHEN** 用户需要进行实名认证时 +- **THEN** 系统应集成阿里云实名认证服务,支持: + - 身份证信息验证 + - 人脸识别验证 + - 身份证OCR识别 + +### Requirement: 权限控制模块 + +系统SHALL提供基于RBAC的权限控制机制。 + +#### Scenario: 角色权限管理 +- **WHEN** 管理员需要配置权限时 +- **THEN** 系统应支持: + - 角色创建和管理 + - 权限分配和继承 + - 资源访问控制 + - 动态权限检查 + +#### Scenario: 权限验证 +- **WHEN** 用户访问受保护资源时 +- **THEN** 系统应验证用户权限,拒绝未授权访问 + +### Requirement: 认证授权模块 + +系统SHALL提供安全的认证授权机制。 + +#### Scenario: JWT Token管理 +- **WHEN** 用户登录成功时 +- **THEN** 系统应生成JWT Token,包含: + - 用户基本信息 + - 权限信息 + - 过期时间 + - 签名验证 + +#### Scenario: Session管理 +- **WHEN** 用户活跃时 +- **THEN** 系统应管理用户会话,支持: + - 会话创建和销毁 + - 会话刷新 + - 多设备登录管理 + - 登录状态同步 + +### Requirement: 文件存储模块 + +系统SHALL提供统一的文件存储服务,适配国内云存储。 + +#### Scenario: 对象存储集成 +- **WHEN** 用户上传文件时 +- **THEN** 系统应支持: + - 阿里云OSS存储 + - 腾讯云COS存储(备选) + - MinIO私有化部署(备选) + - 文件上传、下载、删除 + - 图片处理(压缩、裁剪、水印) + - CDN加速 + +#### Scenario: 文件访问控制 +- **WHEN** 用户访问文件时 +- **THEN** 系统应验证访问权限,生成临时访问URL + +### Requirement: 支付系统模块 + +系统SHALL集成国内主流支付渠道。 + +#### Scenario: 微信支付集成 +- **WHEN** 用户选择微信支付时 +- **THEN** 系统应支持: + - 扫码支付 + - H5支付 + - 小程序支付 + - 订单创建和查询 + - 退款处理 + +#### Scenario: 支付宝支付集成 +- **WHEN** 用户选择支付宝支付时 +- **THEN** 系统应支持: + - 扫码支付 + - H5支付 + - 订单创建和查询 + - 退款处理 + +### Requirement: 消息通知模块 + +系统SHALL提供多渠道消息通知服务。 + +#### Scenario: 短信通知 +- **WHEN** 需要发送短信通知时 +- **THEN** 系统应集成阿里云短信服务,支持: + - 验证码发送 + - 通知短信发送 + - 营销短信发送(需审核) + - 发送记录查询 + +#### Scenario: 推送通知 +- **WHEN** 需要发送推送通知时 +- **THEN** 系统应支持: + - 小程序推送 + - App推送(阿里云移动推送) + - 站内消息推送 + +### Requirement: 内容审核模块 + +系统SHALL提供内容审核服务,满足国内合规要求。 + +#### Scenario: 文本审核 +- **WHEN** 用户提交文本内容时 +- **THEN** 系统应调用阿里云内容审核服务,检测: + - 敏感词过滤 + - 政治敏感内容 + - 色情暴力内容 + - 广告垃圾内容 + +#### Scenario: 图片审核 +- **WHEN** 用户上传图片时 +- **THEN** 系统应调用阿里云图片审核服务,检测: + - 色情图片 + - 暴力图片 + - 政治敏感图片 + - 广告图片 + +### Requirement: 监控告警模块 + +系统SHALL提供完善的监控告警体系。 + +#### Scenario: 性能监控 +- **WHEN** 系统运行时 +- **THEN** 系统应监控: + - 应用性能指标(响应时间、吞吐量) + - 资源使用情况(CPU、内存、磁盘) + - 错误率和异常情况 + - 用户行为数据 + +#### Scenario: 告警通知 +- **WHEN** 监控指标异常时 +- **THEN** 系统应发送告警通知: + - 邀请相关人员 + - 提供告警详情 + - 建议处理方案 + +### Requirement: 开发文档体系 + +系统SHALL提供完整的开发文档。 + +#### Scenario: 架构文档 +- **WHEN** 开发者需要了解架构时 +- **THEN** 系统应提供: + - 整体架构设计文档 + - 模块划分说明 + - 技术选型说明 + - 数据流图 + +#### Scenario: API文档 +- **WHEN** 开发者需要调用API时 +- **THEN** 系统应提供: + - API接口文档 + - 参数说明 + - 返回值说明 + - 错误码说明 + - 示例代码 + +#### Scenario: 开发指南 +- **WHEN** 新开发者加入时 +- **THEN** 系统应提供: + - 快速开始指南 + - 开发规范文档 + - 最佳实践指南 + - 常见问题解答 + +### Requirement: CI/CD流程 + +系统SHALL建立自动化CI/CD流程。 + +#### Scenario: 代码提交 +- **WHEN** 开发者提交代码时 +- **THEN** 系统应自动执行: + - 代码规范检查 + - 类型检查 + - 单元测试 + - 构建验证 + +#### Scenario: 自动部署 +- **WHEN** 代码合并到主分支时 +- **THEN** 系统应自动部署: + - 开发环境部署 + - 测试环境部署 + - 生产环境部署(需审批) + +### Requirement: 国内环境适配 + +系统SHALL全面适配国内运行环境。 + +#### Scenario: 云服务适配 +- **WHEN** 使用云服务时 +- **THEN** 系统应优先使用国内云服务: + - 阿里云(首选) + - 腾讯云(备选) + - 华为云(备选) + +#### Scenario: 网络环境适配 +- **WHEN** 部署应用时 +- **THEN** 系统应优化国内网络: + - 使用国内CDN加速 + - 配置国内DNS解析 + - 多地域部署(华北、华东、华南) + +#### Scenario: 合规性适配 +- **WHEN** 系统上线时 +- **THEN** 系统应满足国内合规要求: + - ICP备案 + - 数据本地化存储 + - 实名认证要求 + - 内容审核要求 + - 数据安全法要求 + +## MODIFIED Requirements + +无修改需求(全新项目) + +## REMOVED Requirements + +无删除需求(全新项目) \ No newline at end of file diff --git a/.trae/specs/initialize-fischerx-foundation/tasks.md b/.trae/specs/initialize-fischerx-foundation/tasks.md new file mode 100644 index 0000000..0539af6 --- /dev/null +++ b/.trae/specs/initialize-fischerx-foundation/tasks.md @@ -0,0 +1,248 @@ +# Tasks + +## 第一阶段:基础架构搭建(1-2个月) + +- [x] Task 1: 项目初始化和Monorepo架构搭建 + - [x] SubTask 1.1: 创建Monorepo项目结构(apps、packages、services、infra、docs、tools目录) + - [x] SubTask 1.2: 配置pnpm工作空间和Turborepo构建系统 + - [x] SubTask 1.3: 初始化package.json和基础配置文件 + - [x] SubTask 1.4: 配置ESLint、Prettier、TypeScript等开发工具 + - [x] SubTask 1.5: 创建README.md和基础文档结构 + +- [x] Task 2: 前端应用框架搭建 + - [x] SubTask 2.1: 创建Next.js 14+ Web应用(apps/web) + - [x] SubTask 2.2: 配置TypeScript和Tailwind CSS + - [x] SubTask 2.3: 集成Shadcn UI组件库 + - [x] SubTask 2.4: 配置Zustand状态管理和React Query + - [x] SubTask 2.5: 创建基础页面布局和路由结构 + - [x] SubTask 2.6: 配置Vitest和Playwright测试框架 + +- [x] Task 3: 后端API服务框架搭建 + - [x] SubTask 3.1: 创建NestJS API服务(services/api) + - [x] SubTask 3.2: 配置Prisma ORM和数据库连接 + - [x] SubTask 3.3: 设计数据库Schema(用户、权限、文件等基础表) + - [x] SubTask 3.4: 创建基础API路由和控制器结构 + - [x] SubTask 3.5: 配置JWT认证中间件 + - [x] SubTask 3.6: 配置Redis缓存连接 + +- [x] Task 4: 共享包开发 + - [x] SubTask 4.1: 创建核心业务逻辑包(packages/core) + - [x] SubTask 4.2: 创建共享UI组件包(packages/ui) + - [x] SubTask 4.3: 创建工具函数包(packages/utils) + - [x] SubTask 4.4: 创建类型定义包(packages/types) + - [x] SubTask 4.5: 创建配置管理包(packages/config) + - [x] SubTask 4.6: 创建常量定义包(packages/constants) + +- [x] Task 5: 用户管理模块开发 + - [x] SubTask 5.1: 实现用户注册功能(手机号、邮箱) + - [x] SubTask 5.2: 实现用户登录功能(验证码、密码) + - [x] SubTask 5.3: 实现用户信息管理(查询、更新、删除) + - [x] SubTask 5.4: 实现用户头像上传和管理 + - [x] SubTask 5.5: 创建用户管理前端页面 + - [x] SubTask 5.6: 编写用户管理单元测试 + +- [x] Task 6: 认证授权模块开发 + - [x] SubTask 6.1: 实现JWT Token生成和验证 + - [x] SubTask 6.2: 实现Session管理(创建、刷新、销毁) + - [x] SubTask 6.3: 实现手机号验证码登录(集成阿里云短信) + - [x] SubTask 6.4: 实现微信OAuth登录 + - [x] SubTask 6.5: 实现支付宝OAuth登录 + - [x] SubTask 6.6: 实现实名认证功能(集成阿里云实名认证) + - [x] SubTask 6.7: 创建登录注册前端页面 + - [x] SubTask 6.8: 编写认证授权单元测试 + +- [x] Task 7: 权限控制模块开发 + - [x] SubTask 7.1: 设计RBAC权限模型(角色、权限、资源) + - [x] SubTask 7.2: 实现角色管理功能(创建、更新、删除) + - [x] SubTask 7.3: 实现权限分配功能 + - [x] SubTask 7.4: 实现权限验证中间件 + - [x] SubTask 7.5: 实现动态权限检查 + - [x] SubTask 7.6: 创建权限管理前端页面 + - [x] SubTask 7.7: 编写权限控制单元测试 + +- [x] Task 8: 文件存储模块开发 + - [x] SubTask 8.1: 实现阿里云OSS存储适配器 + - [x] SubTask 8.2: 实现腾讯云COS存储适配器(备选) + - [x] SubTask 8.3: 实现MinIO私有化存储适配器(备选) + - [x] SubTask 8.4: 实现文件上传功能(单文件、多文件) + - [x] SubTask 8.5: 实现文件下载和删除功能 + - [x] SubTask 8.6: 实现图片处理功能(压缩、裁剪、水印) + - [x] SubTask 8.7: 实现CDN加速配置 + - [x] SubTask 8.8: 创建文件管理前端页面 + - [x] SubTask 8.9: 编写文件存储单元测试 + +- [ ] Task 9: 基础设施搭建 + - [ ] SubTask 9.1: 创建Docker配置文件(Dockerfile、docker-compose.yml) + - [ ] SubTask 9.2: 创建Kubernetes配置文件(Deployment、Service、ConfigMap) + - [ ] SubTask 9.3: 配置阿里云ACK集群 + - [ ] SubTask 9.4: 配置阿里云RDS PostgreSQL数据库 + - [ ] SubTask 9.5: 配置阿里云Redis缓存 + - [ ] SubTask 9.6: 配置阿里云OSS对象存储 + - [ ] SubTask 9.7: 配置阿里云CDN加速 + - [ ] SubTask 9.8: 配置阿里云DNS解析 + +- [ ] Task 10: CI/CD流程配置 + - [ ] SubTask 10.1: 配置阿里云云效CI/CD流程 + - [ ] SubTask 10.2: 创建代码规范检查流程(ESLint、TypeScript) + - [ ] SubTask 10.3: 创建单元测试流程 + - [ ] SubTask 10.4: 创建构建流程 + - [ ] SubTask 10.5: 创建自动部署流程(开发、测试、生产环境) + - [ ] SubTask 10.6: 配置代码提交钩子(pre-commit、pre-push) + +- [ ] Task 11: CLI工具开发 + - [ ] SubTask 11.1: 创建CLI工具框架(tools/cli) + - [ ] SubTask 11.2: 实现create-app命令(创建新应用) + - [ ] SubTask 11.3: 实现init命令(初始化独立项目) + - [ ] SubTask 11.4: 实现deploy-service命令(部署共享服务) + - [ ] SubTask 11.5: 实现update命令(更新底座版本) + - [ ] SubTask 11.6: 实现generate-module命令(生成业务模块) + - [ ] SubTask 11.7: 创建项目模板(standalone、monorepo、lightweight) + - [ ] SubTask 11.8: 编写CLI工具文档和使用指南 + +- [ ] Task 12: 开发文档编写 + - [ ] SubTask 12.1: 编写架构设计文档(docs/architecture) + - [ ] SubTask 12.2: 编写快速开始指南(docs/development/quick-start.md) + - [ ] SubTask 12.3: 编写开发规范文档(docs/development/standards.md) + - [ ] SubTask 12.4: 编写API接口文档(docs/api) + - [ ] SubTask 12.5: 编写部署指南(docs/deployment) + - [ ] SubTask 12.6: 编写常见问题解答(docs/FAQ.md) + - [ ] SubTask 12.7: 编写底座使用方式指南(docs/usage-guide.md) + +## 第二阶段:业务模块开发(2-3个月) + +- [ ] Task 12: 支付系统模块开发 + - [ ] SubTask 12.1: 实现微信支付集成(扫码支付、H5支付、小程序支付) + - [ ] SubTask 12.2: 实现支付宝支付集成(扫码支付、H5支付) + - [ ] SubTask 12.3: 实现银联支付集成(备选) + - [ ] SubTask 12.4: 实现订单管理功能(创建、查询、状态管理) + - [ ] SubTask 12.5: 实现退款处理功能 + - [ ] SubTask 12.6: 实现支付回调处理 + - [ ] SubTask 12.7: 创建支付管理前端页面 + - [ ] SubTask 12.8: 编写支付系统单元测试 + +- [ ] Task 13: 消息通知模块开发 + - [ ] SubTask 13.1: 实现阿里云短信服务集成(验证码、通知短信) + - [ ] SubTask 13.2: 实现邮件通知功能 + - [ ] SubTask 13.3: 实现小程序推送通知 + - [ ] SubTask 13.4: 实现App推送通知(阿里云移动推送) + - [ ] SubTask 13.5: 实现站内消息功能 + - [ ] SubTask 13.6: 创建消息通知管理前端页面 + - [ ] SubTask 13.7: 编写消息通知单元测试 + +- [ ] Task 14: 内容管理模块开发 + - [ ] SubTask 14.1: 实现内容发布功能(文章、图片、视频) + - [ ] SubTask 14.2: 实现内容审核功能(集成阿里云内容审核) + - [ ] SubTask 14.3: 实现评论管理功能 + - [ ] SubTask 14.4: 实现标签分类功能 + - [ ] SubTask 14.5: 实现内容搜索功能 + - [ ] SubTask 14.6: 创建内容管理前端页面 + - [ ] SubTask 14.7: 编写内容管理单元测试 + +- [ ] Task 15: 订单系统模块开发 + - [ ] SubTask 15.1: 实现订单创建功能 + - [ ] SubTask 15.2: 实现订单状态管理(待支付、已支付、已完成、已取消) + - [ ] SubTask 15.3: 实现订单查询功能(用户订单、商家订单) + - [ ] SubTask 15.4: 实现订单统计功能(销售额、订单量) + - [ ] SubTask 15.5: 创建订单管理前端页面 + - [ ] SubTask 15.6: 编写订单系统单元测试 + +- [ ] Task 16: 第三方服务集成 + - [ ] SubTask 16.1: 实现高德地图服务集成 + - [ ] SubTask 16.2: 实现百度AI服务集成(OCR、人脸识别) + - [ ] SubTask 16.3: 实现阿里云AI服务集成(备选) + - [ ] SubTask 16.4: 实现实名认证服务集成(阿里云、腾讯云) + - [ ] SubTask 16.5: 实现OCR识别服务集成(身份证、银行卡) + - [ ] SubTask 16.6: 编写第三方服务集成单元测试 + +- [ ] Task 17: 监控告警系统搭建 + - [ ] SubTask 17.1: 配置阿里云ARMS应用监控 + - [ ] SubTask 17.2: 配置Prometheus + Grafana监控(备选) + - [ ] SubTask 17.3: 配置Sentry错误追踪 + - [ ] SubTask 17.4: 实现性能指标监控(响应时间、吞吐量) + - [ ] SubTask 17.5: 实现业务指标监控(用户量、订单量、支付量) + - [ ] SubTask 17.6: 配置告警规则和通知渠道 + - [ ] SubTask 17.7: 创建监控仪表盘前端页面 + +- [ ] Task 18: 日志服务搭建 + - [ ] SubTask 18.1: 配置阿里云SLS日志服务 + - [ ] SubTask 18.2: 实现日志收集功能(应用日志、系统日志) + - [ ] SubTask 18.3: 实现日志分析功能(日志查询、日志统计) + - [ ] SubTask 18.4: 实现日志告警功能 + - [ ] SubTask 18.5: 配置日志留存策略(6个月以上) + +- [ ] Task 19: 测试完善 + - [ ] SubTask 19.1: 编写前端单元测试(覆盖率>80%) + - [ ] SubTask 19.2: 编写后端单元测试(覆盖率>80%) + - [ ] SubTask 19.3: 编写集成测试 + - [ ] SubTask 19.4: 编写E2E测试 + - [ ] SubTask 19.5: 配置测试报告生成 + - [ ] SubTask 19.6: 配置测试覆盖率报告 + +## 第三阶段:优化和上线(1-2个月) + +- [ ] Task 20: 性能优化 + - [ ] SubTask 20.1: 前端性能优化(代码分割、懒加载、图片优化) + - [ ] SubTask 20.2: 后端性能优化(缓存优化、数据库查询优化) + - [ ] SubTask 20.3: CDN加速优化 + - [ ] SubTask 20.4: 负载均衡配置 + - [ ] SubTask 20.5: 数据库索引优化 + - [ ] SubTask 20.6: 性能测试和压力测试 + +- [ ] Task 21: 安全加固 + - [ ] SubTask 21.1: 安全审计(代码审计、配置审计) + - [ ] SubTask 21.2: 漏洞扫描和修复 + - [ ] SubTask 21.3: 数据加密(敏感数据加密存储) + - [ ] SubTask 21.4: SQL注入防护 + - [ ] SubTask 21.5: XSS防护 + - [ ] SubTask 21.6: CSRF防护 + - [ ] SubTask 21.7: API访问频率限制 + +- [ ] Task 22: 合规性检查 + - [ ] SubTask 22.1: ICP备案申请 + - [ ] SubTask 22.2: 数据本地化存储配置 + - [ ] SubTask 22.3: 实名认证流程完善 + - [ ] SubTask 22.4: 内容审核流程完善 + - [ ] SubTask 22.5: 数据安全法合规检查 + - [ ] SubTask 22.6: 个人信息保护法合规检查 + +- [ ] Task 23: 生产环境部署 + - [ ] SubTask 23.1: 生产环境资源配置(服务器、数据库、缓存) + - [ ] SubTask 23.2: 生产环境配置文件准备 + - [ ] SubTask 23.3: 数据迁移脚本编写 + - [ ] SubTask 23.4: 灰度发布配置 + - [ ] SubTask 23.5: 全量上线部署 + - [ ] SubTask 23.6: 上线后验证测试 + +- [ ] Task 24: 运维体系建立 + - [ ] SubTask 24.1: 监控告警完善 + - [ ] SubTask 24.2: 日志分析系统完善 + - [ ] SubTask 24.3: 故障响应流程建立 + - [ ] SubTask 24.4: 备份恢复机制建立 + - [ ] SubTask 24.5: 运维文档编写 + - [ ] SubTask 24.6: 运维培训 + +# Task Dependencies + +- [Task 2] depends on [Task 1] +- [Task 3] depends on [Task 1] +- [Task 4] depends on [Task 1] +- [Task 5] depends on [Task 2, Task 3, Task 4] +- [Task 6] depends on [Task 5] +- [Task 7] depends on [Task 5, Task 6] +- [Task 8] depends on [Task 3, Task 4] +- [Task 9] depends on [Task 1] +- [Task 10] depends on [Task 1, Task 9] +- [Task 11] depends on [Task 1] +- [Task 12] depends on [Task 5, Task 6, Task 9] +- [Task 13] depends on [Task 5, Task 9] +- [Task 14] depends on [Task 5, Task 8, Task 9] +- [Task 15] depends on [Task 12] +- [Task 16] depends on [Task 6, Task 9] +- [Task 17] depends on [Task 9] +- [Task 18] depends on [Task 9] +- [Task 19] depends on [Task 5, Task 6, Task 7, Task 8, Task 12, Task 13, Task 14, Task 15] +- [Task 20] depends on [Task 19] +- [Task 21] depends on [Task 19] +- [Task 22] depends on [Task 21] +- [Task 23] depends on [Task 20, Task 21, Task 22] +- [Task 24] depends on [Task 23] \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..dfabe14 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,49 @@ +# Changelog + +## [0.1.0] - 2026-05-25 + +### Added + +- 初始化项目结构 +- Monorepo 架构 (Turborepo + pnpm) +- 前端应用 (Next.js 16 + Tailwind CSS) +- API 服务 (NestJS 11 + Prisma) +- 共享包 (types, constants, utils, config, ui, core) +- Docker Compose 配置 +- 完整的开发文档 + - 快速开始指南 + - 项目结构说明 + - 开发规范 + - 最佳实践 + - 常见问题解答 + - 贡献指南 + - 技术栈文档 + - 迁移指南 +- 架构文档 + - 技术选型文档 + - 架构决策记录 (ADR) 目录 + +### Changed + +- 无 + +### Deprecated + +- 无 + +### Removed + +- 无 + +### Fixed + +- 无 + +### Security + +- 无 + +--- + +格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/) +版本遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/) diff --git a/FischerX开发计划.md b/FischerX开发计划.md new file mode 100644 index 0000000..6bbbc9b --- /dev/null +++ b/FischerX开发计划.md @@ -0,0 +1,1279 @@ +# FischerX 开发底座项目 - 详细开发计划 + +> **项目名称**: FischerX 开发底座 +> **文档版本**: v1.0 +> **创建日期**: 2026-05-24 +> **项目负责人**: 技术负责人 +> **预计总工期**: 6-10个月 + +--- + +## 目录 + +- [一、项目概述](#一项目概述) +- [二、分阶段实施计划](#二分阶段实施计划) +- [三、详细任务清单](#三详细任务清单) +- [四、团队配置建议](#四团队配置建议) +- [五、里程碑和交付物](#五里程碑和交付物) +- [六、风险和应对策略](#六风险和应对策略) +- [七、开发流程和规范](#七开发流程和规范) +- [八、附录](#八附录) + +--- + +## 一、项目概述 + +### 1.1 项目背景 + +FischerX是一个适配国内运行环境的开发底座,采用混合模式(Monorepo模式、独立项目模式、API服务模式),提供CLI工具支持。项目旨在为Fischer公司内部业务开发提供开箱即用的基础设施,降低开发成本,提升开发效率。 + +### 1.2 技术栈 + +| 层级 | 技术选型 | 说明 | +|------|---------|------| +| **前端** | Next.js 14+ + TypeScript + Tailwind CSS + Shadcn UI | 现代化React全栈框架 | +| **后端** | NestJS + Prisma + PostgreSQL | 企业级Node.js框架 | +| **缓存** | Redis 7+ | 分布式缓存、会话存储 | +| **消息队列** | RabbitMQ | 可靠消息传递 | +| **存储** | 阿里云OSS | 国内对象存储首选 | +| **部署** | Docker + Kubernetes + 阿里云ACK | 容器化部署 | + +### 1.3 核心模块 + +| 序号 | 模块名称 | 优先级 | 说明 | +|------|---------|--------|------| +| 1 | 用户管理模块 | P0 | 用户注册/登录、实名认证 | +| 2 | 认证授权模块 | P0 | JWT、Session、OAuth | +| 3 | 权限控制模块 | P0 | RBAC权限模型 | +| 4 | 文件存储模块 | P1 | 对象存储、图片处理 | +| 5 | 支付系统模块 | P1 | 微信支付、支付宝 | +| 6 | 消息通知模块 | P1 | 短信、邮件、推送 | +| 7 | 内容管理模块 | P2 | 内容发布、审核 | +| 8 | 订单系统模块 | P1 | 订单创建、状态管理 | +| 9 | 监控告警模块 | P2 | 性能监控、错误追踪 | +| 10 | CLI工具 | P1 | 项目创建、模块生成 | + +### 1.4 项目架构 + +``` +FischerX/ +├── apps/ # 应用层 +│ ├── web/ # Web应用 +│ ├── admin/ # 管理后台 +│ ├── mobile/ # 移动应用 +│ └── miniapp/ # 小程序 +├── packages/ # 共享包 +│ ├── core/ # 核心业务逻辑 +│ ├── ui/ # 共享UI组件 +│ ├── utils/ # 工具函数 +│ ├── types/ # 类型定义 +│ ├── config/ # 配置管理 +│ └── constants/ # 常量定义 +├── services/ # 后端服务 +│ ├── api/ # API服务 +│ ├── worker/ # 后台任务服务 +│ └── realtime/ # 实时通信服务 +├── infra/ # 基础设施 +│ ├── docker/ # Docker配置 +│ ├── k8s/ # Kubernetes配置 +│ └── scripts/ # 部署脚本 +├── docs/ # 文档 +├── tools/ # 开发工具 +│ └── cli/ # CLI工具 +└── package.json # Monorepo配置 +``` + +--- + +## 二、分阶段实施计划 + +### 第一阶段:基础架构搭建(第1-8周,约2个月) + +**目标**: 搭建基础开发框架和核心基础模块 + +**核心任务**: +- Monorepo架构搭建 +- 前端/后端框架初始化 +- 用户管理、认证授权、权限控制、文件存储模块开发 +- 基础设施搭建(Docker、K8s、阿里云资源) +- CI/CD流程配置 +- CLI工具基础功能开发 +- **文档管理体系建立**(文档目录结构、编写规范、维护流程、工具链配置) +- 开发文档编写 + +**关键依赖**: 无(项目启动阶段) + +**验收标准**: +- [ ] Monorepo项目结构完整,可正常构建 +- [ ] 前端应用可运行,基础页面布局完成 +- [ ] 后端API服务可运行,基础接口可用 +- [ ] 用户注册/登录功能完整(手机号、微信、支付宝) +- [ ] JWT认证和Session管理正常工作 +- [ ] RBAC权限控制模块可用 +- [ ] 文件上传/下载功能正常(阿里云OSS) +- [ ] Docker容器化配置完成 +- [ ] CI/CD流程可自动构建和测试 +- [ ] CLI工具支持create-app和init命令 +- [ ] **文档管理体系建立完成**(目录结构、编写规范、维护流程、工具链) +- [ ] 开发文档完整(架构、快速开始、规范) + +--- + +### 第二阶段:核心业务模块开发(第9-20周,约3个月) + +**目标**: 开发核心业务模块和第三方服务集成 + +**核心任务**: +- 支付系统模块(微信支付、支付宝) +- 消息通知模块(短信、邮件、推送) +- 内容管理模块(发布、审核、评论) +- 订单系统模块(创建、状态管理、统计) +- 第三方服务集成(地图、AI、实名认证) +- 监控告警系统搭建 +- 日志服务搭建 +- 测试完善(单元、集成、E2E) + +**关键依赖**: 第一阶段完成 + +**验收标准**: +- [ ] 微信支付、支付宝支付功能完整 +- [ ] 订单创建、支付、退款流程完整 +- [ ] 短信验证码发送正常 +- [ ] 内容发布和审核流程完整 +- [ ] 第三方服务集成可用 +- [ ] 监控仪表盘可展示关键指标 +- [ ] 日志收集和查询功能正常 +- [ ] 单元测试覆盖率 > 80% +- [ ] 集成测试覆盖核心业务流程 +- [ ] E2E测试覆盖关键用户路径 + +--- + +### 第三阶段:业务模块完善和优化(第21-30周,约2.5个月) + +**目标**: 完善业务模块,进行性能优化和安全加固 + +**核心任务**: +- 数据分析模块开发 +- 前端性能优化(代码分割、懒加载) +- 后端性能优化(缓存、数据库优化) +- CDN加速和负载均衡配置 +- 安全审计和漏洞修复 +- 数据加密和合规性检查 +- 压力测试和性能调优 + +**关键依赖**: 第二阶段完成 + +**验收标准**: +- [ ] 数据分析模块可用,支持基础报表 +- [ ] 前端首屏加载时间 < 2秒 +- [ ] API响应时间 P95 < 200ms +- [ ] 系统支持并发用户数 > 1000 +- [ ] 安全审计通过,无高危漏洞 +- [ ] 敏感数据加密存储 +- [ ] 通过压力测试,系统稳定运行 + +--- + +### 第四阶段:生产部署和上线(第31-36周,约1.5个月) + +**目标**: 生产环境部署,系统上线,运维体系建立 + +**核心任务**: +- 生产环境资源配置 +- 数据迁移和灰度发布 +- ICP备案和合规性完善 +- 监控告警完善 +- 故障响应流程建立 +- 备份恢复机制建立 +- 运维文档编写和培训 +- 正式上线 + +**关键依赖**: 第三阶段完成 + +**验收标准**: +- [ ] 生产环境部署完成 +- [ ] 数据迁移成功,数据完整性验证通过 +- [ ] 灰度发布验证通过 +- [ ] ICP备案完成 +- [ ] 监控告警系统正常运行 +- [ ] 备份恢复机制验证通过 +- [ ] 运维文档完整 +- [ ] 系统正式上线,运行稳定 + +--- + +## 三、详细任务清单 + +### 第一阶段:基础架构搭建(第1-8周) + +#### Task 1: 项目初始化和Monorepo架构搭建 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 创建Monorepo项目结构,配置开发工具链 | +| **预计工时** | 5人天 | +| **优先级** | 高(P0) | +| **依赖关系** | 无 | +| **负责人** | 后端开发 + DevOps | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 1.1 | 创建Monorepo项目结构(apps、packages、services、infra、docs、tools) | 1天 | 目录结构符合架构设计 | +| 1.2 | 配置pnpm工作空间和Turborepo构建系统 | 1天 | pnpm install成功,turbo build可运行 | +| 1.3 | 初始化package.json和基础配置文件 | 0.5天 | 配置文件完整,版本锁定 | +| 1.4 | 配置ESLint、Prettier、TypeScript | 1.5天 | 代码规范检查通过 | +| 1.5 | 创建README.md和基础文档结构 | 1天 | 文档目录完整,README清晰 | + +--- + +#### Task 2: 前端应用框架搭建 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 搭建Next.js前端应用,配置UI组件库和状态管理 | +| **预计工时** | 8人天 | +| **优先级** | 高(P0) | +| **依赖关系** | Task 1 | +| **负责人** | 前端开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 2.1 | 创建Next.js 14+ Web应用(apps/web) | 1天 | 应用可启动,首页可访问 | +| 2.2 | 配置TypeScript和Tailwind CSS | 1天 | TS编译通过,Tailwind样式生效 | +| 2.3 | 集成Shadcn UI组件库 | 2天 | 基础组件可用,主题配置完成 | +| 2.4 | 配置Zustand状态管理和React Query | 2天 | 状态管理可用,数据请求封装完成 | +| 2.5 | 创建基础页面布局和路由结构 | 1.5天 | 导航、侧边栏、内容区布局完成 | +| 2.6 | 配置Vitest和Playwright测试框架 | 0.5天 | 测试框架可运行 | + +--- + +#### Task 3: 后端API服务框架搭建 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 搭建NestJS后端服务,配置数据库和缓存 | +| **预计工时** | 8人天 | +| **优先级** | 高(P0) | +| **依赖关系** | Task 1 | +| **负责人** | 后端开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 3.1 | 创建NestJS API服务(services/api) | 1天 | 服务可启动,健康检查接口可用 | +| 3.2 | 配置Prisma ORM和数据库连接 | 2天 | 数据库连接成功,Migration可执行 | +| 3.3 | 设计数据库Schema(用户、权限、文件等基础表) | 2天 | Schema设计合理,索引配置完成 | +| 3.4 | 创建基础API路由和控制器结构 | 1天 | 路由结构清晰,控制器规范 | +| 3.5 | 配置JWT认证中间件 | 1.5天 | JWT生成和验证正常 | +| 3.6 | 配置Redis缓存连接 | 0.5天 | Redis连接成功,缓存读写正常 | + +--- + +#### Task 4: 共享包开发 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 开发共享包(core、ui、utils、types、config、constants) | +| **预计工时** | 10人天 | +| **优先级** | 高(P0) | +| **依赖关系** | Task 1 | +| **负责人** | 前端开发 + 后端开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 4.1 | 创建核心业务逻辑包(packages/core) | 3天 | 核心接口定义完成,可被其他包引用 | +| 4.2 | 创建共享UI组件包(packages/ui) | 3天 | 基础组件封装完成,支持主题 | +| 4.3 | 创建工具函数包(packages/utils) | 1.5天 | 常用工具函数完整,类型安全 | +| 4.4 | 创建类型定义包(packages/types) | 1天 | 前后端共享类型定义完整 | +| 4.5 | 创建配置管理包(packages/config) | 0.5天 | 环境配置管理完善 | +| 4.6 | 创建常量定义包(packages/constants) | 1天 | 业务常量定义完整 | + +--- + +#### Task 5: 用户管理模块开发 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 实现用户注册、登录、信息管理功能 | +| **预计工时** | 10人天 | +| **优先级** | 高(P0) | +| **依赖关系** | Task 2, Task 3, Task 4 | +| **负责人** | 前端开发 + 后端开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 5.1 | 实现用户注册功能(手机号、邮箱) | 2天 | 注册接口可用,参数验证完整 | +| 5.2 | 实现用户登录功能(验证码、密码) | 2天 | 登录接口可用,错误处理完善 | +| 5.3 | 实现用户信息管理(查询、更新、删除) | 2天 | CRUD接口完整,权限控制 | +| 5.4 | 实现用户头像上传和管理 | 1.5天 | 头像上传成功,图片处理正常 | +| 5.5 | 创建用户管理前端页面 | 1.5天 | 页面交互流畅,表单验证完善 | +| 5.6 | 编写用户管理单元测试 | 1天 | 测试覆盖率 > 80% | + +--- + +#### Task 6: 认证授权模块开发 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 实现JWT、Session、OAuth登录、实名认证 | +| **预计工时** | 12人天 | +| **优先级** | 高(P0) | +| **依赖关系** | Task 5 | +| **负责人** | 后端开发 + 前端开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 6.1 | 实现JWT Token生成和验证 | 1.5天 | Token生成正常,过期刷新可用 | +| 6.2 | 实现Session管理(创建、刷新、销毁) | 1.5天 | Session存储Redis,多设备管理 | +| 6.3 | 实现手机号验证码登录(集成阿里云短信) | 2天 | 验证码发送和验证正常 | +| 6.4 | 实现微信OAuth登录 | 2天 | 微信登录流程完整 | +| 6.5 | 实现支付宝OAuth登录 | 2天 | 支付宝登录流程完整 | +| 6.6 | 实现实名认证功能(集成阿里云实名认证) | 1.5天 | 身份证验证和人脸识别可用 | +| 6.7 | 创建登录注册前端页面 | 1天 | 页面美观,交互流畅 | +| 6.8 | 编写认证授权单元测试 | 1天 | 测试覆盖率 > 80% | + +--- + +#### Task 7: 权限控制模块开发 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 实现RBAC权限模型,角色管理和权限验证 | +| **预计工时** | 10人天 | +| **优先级** | 高(P0) | +| **依赖关系** | Task 5, Task 6 | +| **负责人** | 后端开发 + 前端开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 7.1 | 设计RBAC权限模型(角色、权限、资源) | 2天 | 数据模型设计合理,支持继承 | +| 7.2 | 实现角色管理功能(创建、更新、删除) | 1.5天 | 角色CRUD接口完整 | +| 7.3 | 实现权限分配功能 | 1.5天 | 权限分配和回收正常 | +| 7.4 | 实现权限验证中间件 | 2天 | 中间件拦截准确,性能良好 | +| 7.5 | 实现动态权限检查 | 1.5天 | 权限检查实时生效 | +| 7.6 | 创建权限管理前端页面 | 1天 | 权限配置界面友好 | +| 7.7 | 编写权限控制单元测试 | 1天 | 测试覆盖率 > 80% | + +--- + +#### Task 8: 文件存储模块开发 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 实现对象存储集成,文件上传下载和图片处理 | +| **预计工时** | 10人天 | +| **优先级** | 中(P1) | +| **依赖关系** | Task 3, Task 4 | +| **负责人** | 后端开发 + 前端开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 8.1 | 实现阿里云OSS存储适配器 | 2天 | 上传下载正常,错误处理完善 | +| 8.2 | 实现腾讯云COS存储适配器(备选) | 1.5天 | 适配器接口统一,可切换 | +| 8.3 | 实现MinIO私有化存储适配器(备选) | 1.5天 | 私有化部署可用 | +| 8.4 | 实现文件上传功能(单文件、多文件) | 1.5天 | 上传进度显示,断点续传 | +| 8.5 | 实现文件下载和删除功能 | 1天 | 下载权限控制,删除安全 | +| 8.6 | 实现图片处理功能(压缩、裁剪、水印) | 1.5天 | 图片处理质量达标 | +| 8.7 | 实现CDN加速配置 | 0.5天 | CDN缓存策略合理 | +| 8.8 | 创建文件管理前端页面 | 1天 | 文件列表、上传、预览功能 | +| 8.9 | 编写文件存储单元测试 | 1天 | 测试覆盖率 > 80% | + +--- + +#### Task 9: 基础设施搭建 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 配置Docker、Kubernetes、阿里云资源 | +| **预计工时** | 10人天 | +| **优先级** | 高(P0) | +| **依赖关系** | Task 1 | +| **负责人** | DevOps | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 9.1 | 创建Docker配置文件(Dockerfile、docker-compose.yml) | 2天 | 容器可启动,服务间通信正常 | +| 9.2 | 创建Kubernetes配置文件(Deployment、Service、ConfigMap) | 2天 | K8s部署成功,服务可访问 | +| 9.3 | 配置阿里云ACK集群 | 1.5天 | 集群创建成功,节点健康 | +| 9.4 | 配置阿里云RDS PostgreSQL数据库 | 1天 | 数据库实例可用,备份配置 | +| 9.5 | 配置阿里云Redis缓存 | 0.5天 | Redis实例可用,网络连通 | +| 9.6 | 配置阿里云OSS对象存储 | 1天 | Bucket创建,权限配置 | +| 9.7 | 配置阿里云CDN加速 | 1天 | CDN域名配置,缓存规则 | +| 9.8 | 配置阿里云DNS解析 | 1天 | 域名解析正常,SSL证书 | + +--- + +#### Task 10: CI/CD流程配置 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 配置自动化构建、测试、部署流程 | +| **预计工时** | 6人天 | +| **优先级** | 高(P0) | +| **依赖关系** | Task 1, Task 9 | +| **负责人** | DevOps | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 10.1 | 配置阿里云云效CI/CD流程 | 1.5天 | 流水线创建成功 | +| 10.2 | 创建代码规范检查流程(ESLint、TypeScript) | 1天 | 提交自动检查,失败阻断 | +| 10.3 | 创建单元测试流程 | 1天 | 测试自动运行,覆盖率报告 | +| 10.4 | 创建构建流程 | 1天 | 构建产物正确,缓存优化 | +| 10.5 | 创建自动部署流程(开发、测试、生产环境) | 1天 | 部署自动化,环境隔离 | +| 10.6 | 配置代码提交钩子(pre-commit、pre-push) | 0.5天 | 钩子生效,规范检查 | + +--- + +#### Task 11: CLI工具开发 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 开发FischerX CLI工具,支持项目创建和模块生成 | +| **预计工时** | 10人天 | +| **优先级** | 中(P1) | +| **依赖关系** | Task 1 | +| **负责人** | 后端开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 11.1 | 创建CLI工具框架(tools/cli) | 1.5天 | 命令框架搭建,帮助文档 | +| 11.2 | 实现create-app命令(创建新应用) | 2天 | 命令可用,模板正确 | +| 11.3 | 实现init命令(初始化独立项目) | 2天 | 项目初始化成功,依赖安装 | +| 11.4 | 实现deploy-service命令(部署共享服务) | 1.5天 | 服务部署成功,状态查询 | +| 11.5 | 实现update命令(更新底座版本) | 1.5天 | 版本检查,平滑升级 | +| 11.6 | 实现generate-module命令(生成业务模块) | 1.5天 | 模块生成正确,代码规范 | +| 11.7 | 创建项目模板(standalone、monorepo、lightweight) | 1天 | 模板完整,可直接使用 | +| 11.8 | 编写CLI工具文档和使用指南 | 1天 | 文档清晰,示例完整 | + +--- + +#### Task 12: 文档管理体系建立 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 建立完整的文档管理体系,包括目录结构、编写规范、维护流程、工具链配置 | +| **预计工时** | 8人天 | +| **优先级** | 高(P0) | +| **依赖关系** | Task 1 | +| **负责人** | 技术负责人 + 全体开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 12.1 | 创建文档目录结构(docs/下9大类文档分类) | 1天 | 目录结构完整,分类清晰 | +| 12.2 | 制定文档编写规范(模板、命名、格式、版本控制) | 1.5天 | 规范文档完整,示例清晰 | +| 12.3 | 建立文档维护流程(创建、更新、审核、发布、归档) | 1.5天 | 流程文档完整,可操作 | +| 12.4 | 配置文档工具链(TypeDoc、Swagger、markdownlint) | 2天 | 工具配置完成,可自动生成文档 | +| 12.5 | 创建文档模板(架构、需求、设计、API、测试等) | 1天 | 模板完整,可直接使用 | +| 12.6 | 配置CI/CD文档检查流程 | 1天 | 文档检查自动化,失败阻断 | + +--- + +#### Task 13: 开发文档编写 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 编写完整的开发文档体系 | +| **预计工时** | 8人天 | +| **优先级** | 高(P0) | +| **依赖关系** | Task 1-12 | +| **负责人** | 技术负责人 + 全体开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 12.1 | 编写架构设计文档(docs/architecture) | 2天 | 架构图清晰,设计说明完整 | +| 12.2 | 编写快速开始指南(docs/development/quick-start.md) | 1.5天 | 新手可按文档完成环境搭建 | +| 12.3 | 编写开发规范文档(docs/development/standards.md) | 1.5天 | 规范明确,示例清晰 | +| 12.4 | 编写API接口文档(docs/api) | 1.5天 | 接口文档完整,示例可用 | +| 12.5 | 编写部署指南(docs/deployment) | 1天 | 部署步骤清晰,问题排查 | +| 12.6 | 编写常见问题解答(docs/FAQ.md) | 0.5天 | 常见问题覆盖 | +| 12.7 | 编写底座使用方式指南(docs/usage-guide.md) | 1天 | 三种使用模式说明清晰 | + +--- + +### 第二阶段:核心业务模块开发(第9-20周) + +#### Task 14: 支付系统模块开发 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 集成微信支付、支付宝支付,实现订单支付和退款 | +| **预计工时** | 15人天 | +| **优先级** | 高(P1) | +| **依赖关系** | Task 5, Task 6, Task 9 | +| **负责人** | 后端开发 + 前端开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 13.1 | 实现微信支付集成(扫码支付、H5支付、小程序支付) | 4天 | 支付流程完整,回调处理正确 | +| 13.2 | 实现支付宝支付集成(扫码支付、H5支付) | 3天 | 支付流程完整,回调处理正确 | +| 13.3 | 实现银联支付集成(备选) | 2天 | 支付接口统一,可切换 | +| 13.4 | 实现订单管理功能(创建、查询、状态管理) | 2天 | 订单CRUD完整,状态流转正确 | +| 13.5 | 实现退款处理功能 | 1.5天 | 退款流程完整,状态同步 | +| 13.6 | 实现支付回调处理 | 1天 | 回调处理可靠,幂等性保证 | +| 13.7 | 创建支付管理前端页面 | 1天 | 支付页面美观,状态展示 | +| 13.8 | 编写支付系统单元测试 | 1.5天 | 测试覆盖率 > 80% | + +--- + +#### Task 15: 消息通知模块开发 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 实现多渠道消息通知(短信、邮件、推送、站内消息) | +| **预计工时** | 12人天 | +| **优先级** | 高(P1) | +| **依赖关系** | Task 5, Task 9 | +| **负责人** | 后端开发 + 前端开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 14.1 | 实现阿里云短信服务集成(验证码、通知短信) | 2.5天 | 短信发送成功,模板管理 | +| 14.2 | 实现邮件通知功能 | 1.5天 | 邮件发送成功,模板支持 | +| 14.3 | 实现小程序推送通知 | 2天 | 推送到达率高,权限处理 | +| 14.4 | 实现App推送通知(阿里云移动推送) | 2天 | 推送服务集成,设备管理 | +| 14.5 | 实现站内消息功能 | 2天 | 消息收发正常,未读统计 | +| 14.6 | 创建消息通知管理前端页面 | 1.5天 | 消息列表、发送、统计 | +| 14.7 | 编写消息通知单元测试 | 1天 | 测试覆盖率 > 80% | + +--- + +#### Task 16: 内容管理模块开发 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 实现内容发布、审核、评论、标签分类功能 | +| **预计工时** | 12人天 | +| **优先级** | 中(P2) | +| **依赖关系** | Task 5, Task 8, Task 9 | +| **负责人** | 前端开发 + 后端开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 15.1 | 实现内容发布功能(文章、图片、视频) | 2.5天 | 富文本编辑器,多媒体支持 | +| 15.2 | 实现内容审核功能(集成阿里云内容审核) | 2.5天 | 自动审核+人工审核流程 | +| 15.3 | 实现评论管理功能 | 1.5天 | 评论CRUD,审核机制 | +| 15.4 | 实现标签分类功能 | 1.5天 | 标签管理,分类树 | +| 15.5 | 实现内容搜索功能 | 1.5天 | 全文搜索,结果排序 | +| 15.6 | 创建内容管理前端页面 | 1.5天 | 内容列表、编辑、预览 | +| 15.7 | 编写内容管理单元测试 | 1天 | 测试覆盖率 > 80% | + +--- + +#### Task 17: 订单系统模块开发 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 实现订单创建、状态管理、查询、统计功能 | +| **预计工时** | 10人天 | +| **优先级** | 高(P1) | +| **依赖关系** | Task 13 | +| **负责人** | 后端开发 + 前端开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 16.1 | 实现订单创建功能 | 2天 | 订单创建流程完整,库存检查 | +| 16.2 | 实现订单状态管理(待支付、已支付、已完成、已取消) | 2天 | 状态流转正确,超时处理 | +| 16.3 | 实现订单查询功能(用户订单、商家订单) | 1.5天 | 多条件查询,分页支持 | +| 16.4 | 实现订单统计功能(销售额、订单量) | 1.5天 | 统计准确,图表展示 | +| 16.5 | 创建订单管理前端页面 | 2天 | 订单列表、详情、操作 | +| 16.6 | 编写订单系统单元测试 | 1天 | 测试覆盖率 > 80% | + +--- + +#### Task 18: 第三方服务集成 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 集成地图、AI、实名认证、OCR等第三方服务 | +| **预计工时** | 12人天 | +| **优先级** | 中(P2) | +| **依赖关系** | Task 6, Task 9 | +| **负责人** | 后端开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 17.1 | 实现高德地图服务集成 | 2天 | 地图显示,定位,路径规划 | +| 17.2 | 实现百度AI服务集成(OCR、人脸识别) | 3天 | OCR识别准确,人脸比对 | +| 17.3 | 实现阿里云AI服务集成(备选) | 2天 | 服务接口统一,可切换 | +| 17.4 | 实现实名认证服务集成(阿里云、腾讯云) | 2.5天 | 实名认证流程完整 | +| 17.5 | 实现OCR识别服务集成(身份证、银行卡) | 2天 | 识别准确率高,错误处理 | +| 17.6 | 编写第三方服务集成单元测试 | 1.5天 | 测试覆盖率 > 80% | + +--- + +#### Task 19: 监控告警系统搭建 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 配置应用监控、错误追踪、业务指标监控和告警 | +| **预计工时** | 10人天 | +| **优先级** | 中(P2) | +| **依赖关系** | Task 9 | +| **负责人** | DevOps + 后端开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 18.1 | 配置阿里云ARMS应用监控 | 2天 | 应用性能指标采集 | +| 18.2 | 配置Prometheus + Grafana监控(备选) | 2天 | 监控面板可用 | +| 18.3 | 配置Sentry错误追踪 | 1.5天 | 错误捕获,堆栈追踪 | +| 18.4 | 实现性能指标监控(响应时间、吞吐量) | 1.5天 | 指标采集准确 | +| 18.5 | 实现业务指标监控(用户量、订单量、支付量) | 1.5天 | 业务数据可视化 | +| 18.6 | 配置告警规则和通知渠道 | 1天 | 告警触发准确,通知及时 | +| 18.7 | 创建监控仪表盘前端页面 | 1天 | 仪表盘展示清晰 | + +--- + +#### Task 20: 日志服务搭建 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 配置日志收集、分析、查询和告警功能 | +| **预计工时** | 8人天 | +| **优先级** | 中(P2) | +| **依赖关系** | Task 9 | +| **负责人** | DevOps | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 19.1 | 配置阿里云SLS日志服务 | 2天 | 日志采集配置完成 | +| 19.2 | 实现日志收集功能(应用日志、系统日志) | 1.5天 | 日志格式统一,采集完整 | +| 19.3 | 实现日志分析功能(日志查询、日志统计) | 1.5天 | 查询功能可用,统计准确 | +| 19.4 | 实现日志告警功能 | 1天 | 异常日志告警触发 | +| 19.5 | 配置日志留存策略(6个月以上) | 1天 | 留存策略生效,合规 | +| 19.6 | 编写日志服务使用文档 | 1天 | 文档清晰,示例完整 | + +--- + +#### Task 21: 测试完善 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 完善单元测试、集成测试、E2E测试,提升测试覆盖率 | +| **预计工时** | 15人天 | +| **优先级** | 高(P1) | +| **依赖关系** | Task 5-17 | +| **负责人** | 测试工程师 + 全体开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 20.1 | 编写前端单元测试(覆盖率>80%) | 4天 | 组件测试完整,覆盖率达标 | +| 20.2 | 编写后端单元测试(覆盖率>80%) | 4天 | 服务层测试完整,覆盖率达标 | +| 20.3 | 编写集成测试 | 3天 | 模块间集成测试覆盖 | +| 20.4 | 编写E2E测试 | 2天 | 关键用户路径覆盖 | +| 20.5 | 配置测试报告生成 | 1天 | 报告自动生成,可视化 | +| 20.6 | 配置测试覆盖率报告 | 1天 | 覆盖率报告生成,阈值检查 | + +--- + +### 第三阶段:业务模块完善和优化(第21-30周) + +#### Task 22: 性能优化 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 前端和后端性能优化,CDN和负载均衡配置 | +| **预计工时** | 12人天 | +| **优先级** | 高(P1) | +| **依赖关系** | Task 20 | +| **负责人** | 前端开发 + 后端开发 + DevOps | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 21.1 | 前端性能优化(代码分割、懒加载、图片优化) | 3天 | 首屏加载 < 2秒 | +| 21.2 | 后端性能优化(缓存优化、数据库查询优化) | 3天 | API响应 P95 < 200ms | +| 21.3 | CDN加速优化 | 1.5天 | 静态资源缓存命中率高 | +| 21.4 | 负载均衡配置 | 1.5天 | 流量分发均匀,健康检查 | +| 21.5 | 数据库索引优化 | 2天 | 慢查询消除,索引合理 | +| 21.6 | 性能测试和压力测试 | 2天 | 并发 > 1000,系统稳定 | + +--- + +#### Task 23: 安全加固 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 安全审计、漏洞修复、数据加密、防护机制 | +| **预计工时** | 10人天 | +| **优先级** | 高(P0) | +| **依赖关系** | Task 20 | +| **负责人** | 后端开发 + DevOps | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 22.1 | 安全审计(代码审计、配置审计) | 2天 | 审计报告完整,问题清单 | +| 22.2 | 漏洞扫描和修复 | 2天 | 高危漏洞修复完成 | +| 22.3 | 数据加密(敏感数据加密存储) | 1.5天 | 敏感数据加密,密钥管理 | +| 22.4 | SQL注入防护 | 1天 | ORM参数化,无注入风险 | +| 22.5 | XSS防护 | 1天 | 输入过滤,输出转义 | +| 22.6 | CSRF防护 | 1天 | Token验证,同源策略 | +| 22.7 | API访问频率限制 | 1.5天 | 限流策略生效,防刷 | + +--- + +#### Task 24: 合规性检查 + +| 属性 | 内容 | +|------|------| +| **任务描述** | ICP备案、数据本地化、实名认证、内容审核合规 | +| **预计工时** | 8人天 | +| **优先级** | 高(P0) | +| **依赖关系** | Task 22 | +| **负责人** | 技术负责人 + DevOps | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 23.1 | ICP备案申请 | 2天 | 备案提交,跟踪进度 | +| 23.2 | 数据本地化存储配置 | 1.5天 | 数据存储在国内,合规 | +| 23.3 | 实名认证流程完善 | 1.5天 | 实名认证覆盖所有场景 | +| 23.4 | 内容审核流程完善 | 1.5天 | 审核流程合规,记录留存 | +| 23.5 | 数据安全法合规检查 | 1天 | 合规检查通过 | +| 23.6 | 个人信息保护法合规检查 | 1天 | 隐私政策完善,用户授权 | + +--- + +### 第四阶段:生产部署和上线(第31-36周) + +#### Task 25: 生产环境部署 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 生产环境资源配置、数据迁移、灰度发布、全量上线 | +| **预计工时** | 10人天 | +| **优先级** | 高(P0) | +| **依赖关系** | Task 21, Task 22, Task 23 | +| **负责人** | DevOps + 全体开发 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 24.1 | 生产环境资源配置(服务器、数据库、缓存) | 2天 | 资源到位,网络配置 | +| 24.2 | 生产环境配置文件准备 | 1.5天 | 配置正确,环境变量 | +| 24.3 | 数据迁移脚本编写 | 1.5天 | 迁移脚本测试通过 | +| 24.4 | 灰度发布配置 | 1.5天 | 灰度策略配置,流量控制 | +| 24.5 | 全量上线部署 | 1.5天 | 部署成功,服务正常 | +| 24.6 | 上线后验证测试 | 2天 | 功能验证通过,性能达标 | + +--- + +#### Task 26: 运维体系建立 + +| 属性 | 内容 | +|------|------| +| **任务描述** | 监控告警完善、日志分析、故障响应、备份恢复、运维文档 | +| **预计工时** | 10人天 | +| **优先级** | 高(P0) | +| **依赖关系** | Task 24 | +| **负责人** | DevOps + 技术负责人 | + +**子任务清单**: + +| 序号 | 子任务 | 工时 | 验收标准 | +|------|--------|------|---------| +| 25.1 | 监控告警完善 | 2天 | 告警规则优化,通知渠道 | +| 25.2 | 日志分析系统完善 | 1.5天 | 日志查询优化,分析报表 | +| 25.3 | 故障响应流程建立 | 1.5天 | 响应流程文档,演练 | +| 25.4 | 备份恢复机制建立 | 2天 | 备份策略,恢复演练 | +| 25.5 | 运维文档编写 | 2天 | 运维手册完整 | +| 25.6 | 运维培训 | 1天 | 培训完成,考核通过 | + +--- + +## 四、团队配置建议 + +### 4.1 核心团队配置 + +| 角色 | 人数 | 技能要求 | 主要职责 | +|------|------|---------|---------| +| **技术负责人** | 1人 | - 8年以上全栈开发经验
- 熟悉Next.js、NestJS
- 架构设计能力
- 团队管理经验 | - 技术决策和架构设计
- 代码审查和质量把控
- 技术难题攻关
- 团队协调和进度管理 | +| **前端开发工程师** | 2-3人 | - 3年以上React开发经验
- 熟悉Next.js、TypeScript
- 熟悉Tailwind CSS、Shadcn UI
- 了解性能优化 | - Web应用和管理后台开发
- UI组件库开发和维护
- 前端性能优化
- 前端测试编写 | +| **后端开发工程师** | 2-3人 | - 3年以上Node.js开发经验
- 熟悉NestJS、Prisma
- 熟悉PostgreSQL、Redis
- 了解微服务架构 | - API服务开发和维护
- 数据库设计和优化
- 第三方服务集成
- 后端测试编写 | +| **DevOps工程师** | 1人 | - 熟悉Docker、Kubernetes
- 熟悉阿里云服务
- 熟悉CI/CD流程
- 了解监控和日志系统 | - 基础设施搭建和维护
- CI/CD流程配置
- 监控告警系统搭建
- 生产环境部署和运维 | +| **测试工程师** | 1人 | - 熟悉自动化测试
- 熟悉Playwright、Vitest
- 了解性能测试工具
- 了解安全测试 | - 测试策略制定
- 自动化测试编写
- 性能和安全测试
- 质量把控和报告 | + +### 4.2 扩展团队配置(可选) + +| 角色 | 人数 | 技能要求 | 主要职责 | +|------|------|---------|---------| +| **移动端开发工程师** | 1-2人 | - 熟悉React Native或Flutter
- 熟悉小程序开发
- 了解移动端性能优化 | - 移动应用开发
- 小程序开发
- 移动端适配和优化 | +| **UI/UX设计师** | 1人 | - 熟悉Figma、Sketch
- 了解设计系统
- 了解用户体验设计原则 | - 界面设计和交互设计
- 设计系统维护
- 用户体验优化 | +| **产品经理** | 1人 | - 熟悉敏捷开发
- 了解技术实现
- 良好的沟通能力 | - 需求分析和产品规划
- 迭代计划和优先级
- 用户反馈收集和分析 | + +### 4.3 团队配置建议 + +**最小可行团队(5人)**: +- 技术负责人 1人(兼后端开发) +- 前端开发 2人 +- 后端开发 1人 +- DevOps 1人(兼测试) + +**推荐团队(8人)**: +- 技术负责人 1人 +- 前端开发 2人 +- 后端开发 2人 +- DevOps 1人 +- 测试工程师 1人 +- UI设计师 1人 + +**完整团队(10人)**: +- 技术负责人 1人 +- 前端开发 3人 +- 后端开发 3人 +- DevOps 1人 +- 测试工程师 1人 +- 产品经理 1人 + +--- + +## 五、里程碑和交付物 + +### 5.1 关键里程碑 + +| 里程碑 | 时间节点 | 关键交付物 | 验收标准 | +|--------|---------|-----------|---------| +| **M1: 基础框架完成** | 第4周 | - Monorepo项目结构
- 前端/后端框架
- 开发工具链配置 | - 项目可构建和运行
- 代码规范检查通过
- 基础页面可访问 | +| **M2: 核心模块完成** | 第8周 | - 用户管理模块
- 认证授权模块
- 权限控制模块
- 文件存储模块
- CLI工具基础功能
- **文档管理体系**
- 开发文档 | - 用户注册/登录可用
- JWT认证正常
- RBAC权限控制可用
- 文件上传下载正常
- CLI工具可用
- **文档管理体系建立完成**
- 文档完整 | +| **M3: 业务模块完成** | 第20周 | - 支付系统模块
- 消息通知模块
- 内容管理模块
- 订单系统模块
- 第三方服务集成
- 监控告警系统
- 测试覆盖 | - 支付流程完整
- 消息通知可用
- 内容管理可用
- 订单系统可用
- 第三方服务集成可用
- 监控告警正常
- 测试覆盖率 > 80% | +| **M4: 优化完成** | 第30周 | - 性能优化报告
- 安全审计报告
- 合规性检查报告
- 压力测试报告 | - 性能指标达标
- 无高危漏洞
- 合规检查通过
- 压力测试通过 | +| **M5: 正式上线** | 第36周 | - 生产环境部署
- 运维体系
- 运维文档
- 上线报告 | - 系统运行稳定
- 监控告警正常
- 备份恢复可用
- 运维文档完整 | + +### 5.2 每个阶段的交付物 + +#### 第一阶段交付物(第8周) + +| 交付物 | 说明 | 验收标准 | +|--------|------|---------| +| **项目代码库** | 完整的Monorepo项目代码 | 代码规范,可构建运行 | +| **基础框架** | 前端Next.js应用 + 后端NestJS服务 | 应用可访问,服务可调用 | +| **核心模块** | 用户、认证、权限、文件存储模块 | 功能完整,测试通过 | +| **基础设施** | Docker、K8s、阿里云资源配置 | 容器化部署,服务可用 | +| **CI/CD流程** | 自动化构建、测试、部署流程 | 流水线运行正常 | +| **CLI工具** | 基础CLI工具(create-app、init) | 命令可用,模板正确 | +| **文档管理体系** | 文档目录、规范、流程、工具链 | 体系完整,可操作 | +| **开发文档** | 架构、快速开始、规范、API文档 | 文档完整,清晰易懂 | + +#### 第二阶段交付物(第20周) + +| 交付物 | 说明 | 验收标准 | +|--------|------|---------| +| **业务模块代码** | 支付、消息、内容、订单模块代码 | 代码规范,功能完整 | +| **第三方服务集成** | 地图、AI、实名认证、OCR集成 | 服务可用,接口统一 | +| **监控告警系统** | ARMS、Sentry、Grafana配置 | 监控正常,告警及时 | +| **日志服务** | SLS日志收集、分析、查询 | 日志完整,查询可用 | +| **测试报告** | 单元、集成、E2E测试报告 | 覆盖率 > 80%,测试通过 | + +#### 第三阶段交付物(第30周) + +| 交付物 | 说明 | 验收标准 | +|--------|------|---------| +| **性能优化报告** | 前端、后端、数据库优化结果 | 性能指标达标 | +| **安全审计报告** | 代码审计、漏洞扫描结果 | 无高危漏洞 | +| **合规性检查报告** | ICP备案、数据安全、隐私合规 | 合规检查通过 | +| **压力测试报告** | 并发、负载、稳定性测试结果 | 系统稳定,指标达标 | + +#### 第四阶段交付物(第36周) + +| 交付物 | 说明 | 验收标准 | +|--------|------|---------| +| **生产环境** | 生产环境部署完成 | 服务正常运行 | +| **运维体系** | 监控、日志、告警、备份完善 | 体系完整,运行正常 | +| **运维文档** | 运维手册、故障响应流程 | 文档完整,可操作 | +| **上线报告** | 上线验证结果、运行状态 | 验证通过,运行稳定 | + +--- + +## 六、风险和应对策略 + +### 6.1 技术风险 + +| 风险项 | 风险描述 | 影响程度 | 发生概率 | 应对策略 | +|--------|---------|---------|---------|---------| +| **技术栈选择风险** | Next.js 14+、NestJS等新技术栈团队不熟悉 | 高 | 中 | - 技术预研和原型验证
- 组织技术培训和分享
- 邀请外部专家指导
- 建立技术决策评审机制 | +| **性能风险** | 高并发场景下系统性能不达标 | 高 | 中 | - 早期进行性能测试
- 设计阶段考虑性能
- 使用缓存和异步处理
- 定期进行压力测试 | +| **安全风险** | 系统存在安全漏洞,被攻击或数据泄露 | 高 | 低 | - 安全编码规范培训
- 定期安全审计
- 使用安全扫描工具
- 建立安全响应机制 | +| **第三方服务依赖风险** | 微信、支付宝、阿里云等服务不稳定或API变更 | 中 | 中 | - 设计服务降级方案
- 多服务商备份
- 接口抽象层设计
- 监控第三方服务状态 | +| **数据库性能风险** | PostgreSQL在高并发下性能瓶颈 | 中 | 低 | - 合理设计索引
- 使用读写分离
- 定期优化慢查询
- 考虑分库分表方案 | + +### 6.2 进度风险 + +| 风险项 | 风险描述 | 影响程度 | 发生概率 | 应对策略 | +|--------|---------|---------|---------|---------| +| **需求变更风险** | 开发过程中需求频繁变更 | 高 | 高 | - 建立需求变更流程
- 迭代开发,敏捷响应
- 需求评审和确认
- 预留缓冲时间 | +| **人员流动风险** | 核心开发人员离职或调岗 | 高 | 中 | - 完善文档和知识共享
- 代码规范和注释
- 结对编程和代码审查
- 建立人才储备 | +| **技能不足风险** | 团队成员技能不匹配项目需求 | 中 | 中 | - 技术培训和学习
- 代码评审和结对编程
- 引入外部专家
- 调整任务分配 | +| **协作效率风险** | 团队协作不畅,沟通成本高 | 中 | 中 | - 建立协作流程和工具
- 定期站会和同步
- 明确职责和接口
- 使用项目管理工具 | +| **第三方审核风险** | ICP备案、支付接口审核等外部审核周期长 | 中 | 高 | - 提前准备审核材料
- 预留审核时间
- 并行推进其他任务
- 建立审核跟踪机制 | + +### 6.3 质量风险 + +| 风险项 | 风险描述 | 影响程度 | 发生概率 | 应对策略 | +|--------|---------|---------|---------|---------| +| **代码质量风险** | 代码质量差,难以维护和扩展 | 高 | 中 | - 代码规范和审查
- 自动化测试覆盖
- 代码质量工具
- 定期重构和优化 | +| **测试覆盖风险** | 测试覆盖率不足,bug流入生产 | 高 | 中 | - 设定覆盖率阈值
- 测试驱动开发
- 自动化测试流程
- 测试用例评审 | +| **文档质量风险** | 文档不完整或过时,影响开发效率 | 中 | 高 | - 文档即代码
- 文档审查流程
- 定期更新文档
- 文档自动化生成 | +| **部署质量风险** | 部署流程不完善,导致生产事故 | 高 | 低 | - 自动化部署流程
- 灰度发布策略
- 回滚机制
- 部署验证测试 | + +### 6.4 风险应对总则 + +| 策略 | 说明 | 执行时机 | +|------|------|---------| +| **风险识别** | 定期识别和评估项目风险 | 每周站会、迭代回顾 | +| **风险评估** | 评估风险影响程度和发生概率 | 风险识别后 | +| **风险应对** | 制定和执行风险应对措施 | 风险评估后 | +| **风险监控** | 持续监控风险状态和应对措施效果 | 整个项目周期 | +| **风险沟通** | 及时向相关方沟通风险状态 | 定期报告、异常情况 | + +--- + +## 七、开发流程和规范 + +### 7.1 代码管理流程 + +#### 7.1.1 分支策略 + +采用 **Git Flow** 分支策略: + +``` +main (生产分支) + └── release/* (发布分支) + └── develop (开发分支) + └── feature/* (功能分支) + └── bugfix/* (修复分支) + └── hotfix/* (热修复分支) +``` + +| 分支类型 | 命名规范 | 说明 | 生命周期 | +|---------|---------|------|---------| +| **main** | `main` | 生产环境代码,受保护 | 永久 | +| **develop** | `develop` | 开发环境代码,集成最新功能 | 永久 | +| **feature** | `feature/<模块>-<功能描述>` | 新功能开发 | 临时 | +| **bugfix** | `bugfix/<模块>-<问题描述>` | Bug修复 | 临时 | +| **release** | `release/v<版本号>` | 发布准备 | 临时 | +| **hotfix** | `hotfix/<问题描述>` | 生产紧急修复 | 临时 | + +#### 7.1.2 提交规范 + +采用 **Conventional Commits** 规范: + +``` +(): + +[optional body] + +[optional footer(s)] +``` + +| Type | 说明 | 示例 | +|------|------|------| +| `feat` | 新功能 | `feat(auth): add wechat login` | +| `fix` | Bug修复 | `fix(payment): fix refund callback` | +| `docs` | 文档更新 | `docs(api): update user endpoints` | +| `style` | 代码格式 | `style(ui): format components` | +| `refactor` | 重构 | `refactor(core): simplify auth logic` | +| `test` | 测试 | `test(user): add registration tests` | +| `chore` | 构建/工具 | `chore(ci): add lint workflow` | + +#### 7.1.3 代码审查流程 + +``` +开发者创建PR → 自动化检查 → 代码审查 → 修改 → 合并 +``` + +| 步骤 | 说明 | 负责人 | +|------|------|--------| +| **创建PR** | 功能开发完成,创建Pull Request | 开发者 | +| **自动化检查** | CI流程自动执行Lint、TypeCheck、Test | CI系统 | +| **代码审查** | 至少1名Reviewer审查代码 | 团队成员 | +| **修改** | 根据审查意见修改代码 | 开发者 | +| **合并** | 审查通过,合并到develop分支 | 技术负责人 | + +### 7.2 代码审查流程 + +#### 7.2.1 审查清单 + +| 检查项 | 说明 | 优先级 | +|--------|------|--------| +| **功能正确性** | 代码是否实现预期功能 | 高 | +| **代码规范** | 是否符合编码规范 | 高 | +| **类型安全** | TypeScript类型是否正确 | 高 | +| **错误处理** | 异常和错误是否妥善处理 | 高 | +| **性能考虑** | 是否有性能问题 | 中 | +| **安全性** | 是否有安全风险 | 高 | +| **测试覆盖** | 是否有相应测试 | 高 | +| **文档更新** | 是否更新相关文档 | 中 | +| **代码复用** | 是否有重复代码 | 中 | +| **可维护性** | 代码是否易于理解和维护 | 中 | + +#### 7.2.2 审查工具 + +| 工具 | 用途 | 配置 | +|------|------|------| +| **ESLint** | JavaScript/TypeScript代码规范 | 项目根目录.eslintrc | +| **Prettier** | 代码格式化 | 项目根目录.prettierrc | +| **TypeScript** | 类型检查 | tsconfig.json | +| **Husky** | Git钩子 | .husky/目录 | +| **GitHub/Gitee PR** | 代码审查平台 | 分支保护规则 | + +### 7.3 测试流程 + +#### 7.3.1 测试层级 + +``` +┌─────────────────────────────────────┐ +│ E2E测试 (Playwright) │ 用户场景 +├─────────────────────────────────────┤ +│ 集成测试 (Vitest + Supertest) │ 模块交互 +├─────────────────────────────────────┤ +│ 单元测试 (Vitest / Jest) │ 函数/组件 +└─────────────────────────────────────┘ +``` + +| 测试类型 | 工具 | 覆盖率要求 | 执行时机 | +|---------|------|-----------|---------| +| **单元测试** | Vitest (前端) / Jest (后端) | > 80% | 每次提交 | +| **集成测试** | Vitest + Supertest | > 70% | 每次提交 | +| **E2E测试** | Playwright | 关键路径100% | 合并前 | +| **性能测试** | k6 / Artillery | 性能指标达标 | 发布前 | +| **安全测试** | OWASP ZAP / SonarQube | 无高危漏洞 | 发布前 | + +#### 7.3.2 测试命名规范 + +``` +describe('<模块名>', () => { + describe('<功能名>', () => { + it('should <预期行为> when <条件>', () => { + // 测试代码 + }); + }); +}); +``` + +#### 7.3.3 测试执行流程 + +``` +本地开发 → 提交代码 → CI自动测试 → 测试通过 → 合并 + ↓ + 测试失败 → 修复 → 重新提交 +``` + +### 7.4 部署流程 + +#### 7.4.1 环境划分 + +| 环境 | 用途 | 部署触发 | 负责人 | +|------|------|---------|--------| +| **开发环境** | 日常开发调试 | 合并到develop自动部署 | DevOps | +| **测试环境** | 功能测试和集成测试 | 合并到develop自动部署 | DevOps | +| **预发布环境** | 上线前验证 | 创建release分支手动部署 | DevOps | +| **生产环境** | 线上服务 | release分支审批后部署 | DevOps + 技术负责人 | + +#### 7.4.2 部署流程 + +``` +开发完成 → 合并develop → 自动部署开发/测试环境 + ↓ + 测试通过 + ↓ + 创建release分支 → 部署预发布环境 + ↓ + 预发布验证 + ↓ + 审批通过 → 部署生产环境 + ↓ + 上线验证 +``` + +#### 7.4.3 部署检查清单 + +| 检查项 | 说明 | 负责人 | +|--------|------|--------| +| **代码审查** | 所有PR已审查并合并 | 技术负责人 | +| **测试通过** | 所有测试通过,覆盖率达标 | 测试工程师 | +| **数据库迁移** | Migration脚本已执行 | 后端开发 | +| **配置更新** | 环境变量和配置已更新 | DevOps | +| **备份完成** | 数据库和文件已备份 | DevOps | +| **回滚方案** | 回滚方案已准备 | DevOps | +| **监控就绪** | 监控和告警已配置 | DevOps | +| **通知相关方** | 上线通知已发送 | 技术负责人 | + +#### 7.4.4 回滚策略 + +| 场景 | 回滚方式 | 负责人 | +|------|---------|--------| +| **代码问题** | 回滚到上一个稳定版本 | DevOps | +| **数据库问题** | 执行反向Migration | 后端开发 | +| **配置问题** | 恢复配置备份 | DevOps | +| **数据问题** | 从备份恢复数据 | DevOps | + +### 7.5 开发规范 + +#### 7.5.1 前端开发规范 + +| 规范项 | 要求 | +|--------|------| +| **组件命名** | PascalCase,如 `UserProfile.tsx` | +| **文件组织** | 按功能模块组织,每个模块包含组件、hooks、types | +| **样式规范** | 使用Tailwind CSS,避免内联样式 | +| **状态管理** | 服务端状态用React Query,客户端状态用Zustand | +| **类型定义** | 所有Props和State必须有TypeScript类型 | +| **错误边界** | 关键组件使用Error Boundary | +| **性能优化** | 使用React.memo、useMemo、useCallback优化渲染 | + +#### 7.5.2 后端开发规范 + +| 规范项 | 要求 | +|--------|------| +| **模块命名** | kebab-case,如 `user-management` | +| **控制器命名** | PascalCase + Controller后缀,如 `UserController` | +| **服务命名** | PascalCase + Service后缀,如 `UserService` | +| **DTO规范** | 使用class-validator进行参数验证 | +| **异常处理** | 使用统一异常过滤器,返回标准错误格式 | +| **日志规范** | 使用统一日志服务,包含请求ID、用户ID | +| **API规范** | RESTful设计,版本控制,统一响应格式 | + +#### 7.5.3 数据库规范 + +| 规范项 | 要求 | +|--------|------| +| **表命名** | snake_case,如 `user_profiles` | +| **字段命名** | snake_case,如 `created_at` | +| **主键** | 使用UUID或自增ID | +| **时间字段** | 使用 `created_at`、`updated_at` | +| **软删除** | 使用 `deleted_at` 字段 | +| **索引** | 外键、查询频繁字段建立索引 | +| **迁移** | 所有数据库变更通过Prisma Migration管理 | + +--- + +## 八、附录 + +### 8.1 工时汇总 + +| 阶段 | 任务数 | 总工时(人天) | 预计周期 | +|------|--------|---------------|---------| +| **第一阶段** | 13 | 115 | 第1-8周(2个月) | +| **第二阶段** | 8 | 94 | 第9-20周(3个月) | +| **第三阶段** | 3 | 30 | 第21-30周(2.5个月) | +| **第四阶段** | 2 | 20 | 第31-36周(1.5个月) | +| **总计** | 26 | 259 | 第1-36周(9个月) | + +### 8.2 任务依赖关系图 + +``` +Task 1 (项目初始化) + ├── Task 2 (前端框架) ──┐ + ├── Task 3 (后端框架) ──┼── Task 5 (用户管理) ──┐ + ├── Task 4 (共享包) ────┘ │ + ├── Task 9 (基础设施) ──┬── Task 10 (CI/CD) │ + │ ├── Task 11 (CLI工具) ├── Task 6 (认证授权) ──┐ + │ ├── Task 17 (监控) │ │ + │ └── Task 18 (日志) ├── Task 7 (权限控制) │ + │ │ │ + └── Task 8 (文件存储) ──────────────────────────┘ ├── Task 13 (支付) ── Task 16 (订单) + │ + ├── Task 14 (消息) + │ + ├── Task 15 (内容) + │ + └── Task 17 (第三方) + +Task 5-17 ── Task 20 (测试) ──┬── Task 21 (性能优化) ──┐ + ├── Task 22 (安全加固) ──┼── Task 24 (生产部署) ── Task 25 (运维) + └── Task 23 (合规检查) ──┘ +``` + +### 8.3 关键路径 + +``` +项目启动 → Task 1 → Task 3 → Task 5 → Task 6 → Task 13 → Task 16 → Task 20 → Task 21 → Task 24 → Task 25 → 项目完成 + ↓ ↓ ↓ + Task 4 Task 7 Task 14 + ↓ ↓ ↓ + Task 8 Task 15 Task 17 + ↓ + Task 22 + ↓ + Task 23 +``` + +### 8.4 术语表 + +| 术语 | 说明 | +|------|------| +| **Monorepo** | 单一代码仓库管理多个项目或包 | +| **RBAC** | Role-Based Access Control,基于角色的访问控制 | +| **JWT** | JSON Web Token,一种认证令牌格式 | +| **OAuth** | Open Authorization,开放授权协议 | +| **CI/CD** | Continuous Integration/Continuous Deployment,持续集成/持续部署 | +| **ACK** | Alibaba Cloud Container Service for Kubernetes,阿里云容器服务 | +| **OSS** | Object Storage Service,对象存储服务 | +| **RDS** | Relational Database Service,关系型数据库服务 | +| **SLS** | Simple Log Service,日志服务 | +| **ARMS** | Application Real-Time Monitoring Service,应用实时监控 | +| **P0/P1/P2** | 优先级等级,P0最高,P2最低 | +| **P95** | 95百分位,表示95%的请求响应时间 | +| **SSR** | Server-Side Rendering,服务端渲染 | +| **SSG** | Static Site Generation,静态站点生成 | +| **ORM** | Object-Relational Mapping,对象关系映射 | +| **DTO** | Data Transfer Object,数据传输对象 | +| **E2E** | End-to-End,端到端测试 | + +### 8.5 参考文档 + +- [FischerX架构设计方案.md](file:///Users/Chiguyong/Code/FischerX/FischerX架构设计方案.md) - 详细架构设计文档 +- [spec.md](file:///Users/Chiguyong/Code/FischerX/.trae/specs/initialize-fischerx-foundation/spec.md) - 项目规格说明 +- [tasks.md](file:///Users/Chiguyong/Code/FischerX/.trae/specs/initialize-fischerx-foundation/tasks.md) - 初始任务清单 + +--- + +> **文档维护**: 本文档由技术负责人维护,定期更新 +> **最后更新**: 2026-05-24 +> **文档状态**: 初版完成 \ No newline at end of file diff --git a/FischerX文档管理规范.md b/FischerX文档管理规范.md new file mode 100644 index 0000000..a79a177 --- /dev/null +++ b/FischerX文档管理规范.md @@ -0,0 +1,1549 @@ +# FischerX 文档管理规范 + +> **项目名称**: FischerX 开发底座 +> **文档版本**: v1.0.0 +> **创建日期**: 2026-05-24 +> **文档负责人**: 技术负责人 +> **文档状态**: 正式发布 +> **适用范围**: FischerX项目全体开发人员、测试人员、运维人员、产品经理 + +--- + +## 目录 + +- [一、文档管理概述](#一文档管理概述) + - [1.1 目的](#11-目的) + - [1.2 适用范围](#12-适用范围) + - [1.3 文档管理原则](#13-文档管理原则) + - [1.4 角色与职责](#14-角色与职责) +- [二、文档目录结构设计](#二文档目录结构设计) + - [2.1 整体目录结构](#21-整体目录结构) + - [2.2 目录说明](#22-目录说明) + - [2.3 文档分类体系](#23-文档分类体系) +- [三、文档分类和职责](#三文档分类和职责) + - [3.1 架构文档](#31-架构文档) + - [3.2 需求文档](#32-需求文档) + - [3.3 设计文档](#33-设计文档) + - [3.4 开发文档](#34-开发文档) + - [3.5 API文档](#35-api文档) + - [3.6 测试文档](#36-测试文档) + - [3.7 部署文档](#37-部署文档) + - [3.8 运维文档](#38-运维文档) + - [3.9 用户文档](#39-用户文档) +- [四、文档编写规范](#四文档编写规范) + - [4.1 文档模板](#41-文档模板) + - [4.2 命名规范](#42-命名规范) + - [4.3 格式规范](#43-格式规范) + - [4.4 版本控制](#44-版本控制) + - [4.5 图表规范](#45-图表规范) +- [五、文档维护流程](#五文档维护流程) + - [5.1 文档创建流程](#51-文档创建流程) + - [5.2 文档更新流程](#52-文档更新流程) + - [5.3 文档审核流程](#53-文档审核流程) + - [5.4 文档发布流程](#54-文档发布流程) + - [5.5 文档归档流程](#55-文档归档流程) + - [5.6 文档过期处理](#56-文档过期处理) +- [六、文档与代码同步策略](#六文档与代码同步策略) + - [6.1 同步原则](#61-同步原则) + - [6.2 代码变更时同步更新文档](#62-代码变更时同步更新文档) + - [6.3 CI/CD流程中集成文档检查](#63-cicd流程中集成文档检查) + - [6.4 文档版本与代码版本对应](#64-文档版本与代码版本对应) + - [6.5 自动化文档生成](#65-自动化文档生成) +- [七、文档工具链](#七文档工具链) + - [7.1 文档生成工具](#71-文档生成工具) + - [7.2 文档检查工具](#72-文档检查工具) + - [7.3 文档搜索工具](#73-文档搜索工具) + - [7.4 文档协作平台](#74-文档协作平台) + - [7.5 工具配置示例](#75-工具配置示例) +- [八、文档质量保障](#八文档质量保障) + - [8.1 文档审查清单](#81-文档审查清单) + - [8.2 文档质量指标](#82-文档质量指标) + - [8.3 定期文档审计](#83-定期文档审计) + - [8.4 文档反馈机制](#84-文档反馈机制) +- [九、附录](#九附录) + - [9.1 文档状态说明](#91-文档状态说明) + - [9.2 版本号规范](#92-版本号规范) + - [9.3 术语表](#93-术语表) + - [9.4 参考文档](#94-参考文档) + +--- + +## 一、文档管理概述 + +### 1.1 目的 + +建立FischerX项目文档管理体系,确保文档的完整性、准确性、一致性和可维护性,实现文档与代码同步更新,提升团队协作效率和项目可维护性。 + +### 1.2 适用范围 + +本规范适用于FischerX项目的所有文档,包括但不限于: +- 架构设计文档 +- 需求规格文档 +- 技术设计文档 +- 开发指南文档 +- API接口文档 +- 测试文档 +- 部署运维文档 +- 用户使用文档 + +### 1.3 文档管理原则 + +| 原则 | 说明 | +|------|------| +| **文档即代码** | 文档与代码同等重要,使用Git进行版本管理 | +| **单一数据源** | 每个信息只在一个地方维护,避免信息不一致 | +| **及时更新** | 代码变更时同步更新相关文档 | +| **清晰易懂** | 文档结构清晰,语言简洁,示例完整 | +| **可追溯性** | 文档变更可追溯,版本可回溯 | +| **自动化优先** | 尽可能使用工具自动生成文档 | + +### 1.4 角色与职责 + +| 角色 | 职责 | 权限 | +|------|------|------| +| **文档负责人** | 制定文档规范,审核重要文档,组织文档审计 | 文档规范制定、文档审核、文档归档 | +| **技术负责人** | 审核架构文档、设计文档、API文档 | 技术文档审核、技术决策记录 | +| **开发人员** | 编写和更新开发文档、API文档、设计文档 | 编写、更新自己负责的文档 | +| **测试人员** | 编写和更新测试文档 | 测试文档编写和更新 | +| **运维人员** | 编写和更新部署文档、运维文档 | 部署运维文档编写和更新 | +| **产品经理** | 编写和更新需求文档、用户文档 | 需求文档编写和更新 | +| **全体团队成员** | 阅读文档,反馈文档问题 | 文档反馈、文档建议 | + +--- + +## 二、文档目录结构设计 + +### 2.1 整体目录结构 + +``` +FischerX/ +├── docs/ # 文档根目录 +│ ├── architecture/ # 架构文档 +│ │ ├── overview.md # 整体架构概述 +│ │ ├── technology-selection.md # 技术选型文档 +│ │ ├── module-design.md # 模块划分设计 +│ │ ├── design-decisions/ # 架构决策记录(ADR) +│ │ │ ├── ADR-001-monorepo-structure.md +│ │ │ ├── ADR-002-nestjs-framework.md +│ │ │ └── ADR-003-postgresql-database.md +│ │ └── diagrams/ # 架构图 +│ │ ├── system-architecture.png +│ │ └── module-dependency.png +│ │ +│ ├── requirements/ # 需求文档 +│ │ ├── product/ # 产品需求 +│ │ │ ├── prd-v1.0.md # 产品需求文档 +│ │ │ └── user-stories/ # 用户故事 +│ │ │ ├── auth-user-stories.md +│ │ │ └── payment-user-stories.md +│ │ ├── features/ # 功能规格 +│ │ │ ├── auth-spec.md # 认证功能规格 +│ │ │ ├── payment-spec.md # 支付功能规格 +│ │ │ └── permission-spec.md # 权限功能规格 +│ │ └── changelog/ # 需求变更记录 +│ │ └── requirements-changelog.md +│ │ +│ ├── design/ # 设计文档 +│ │ ├── database/ # 数据库设计 +│ │ │ ├── schema-design.md # 数据库Schema设计 +│ │ │ ├── migration-guide.md # 数据库迁移指南 +│ │ │ └── er-diagrams/ # ER图 +│ │ ├── api/ # API设计 +│ │ │ ├── api-design-guidelines.md +│ │ │ └── restful-conventions.md +│ │ ├── ui/ # UI设计 +│ │ │ ├── design-system.md # 设计系统 +│ │ │ ├── component-library.md # 组件库设计 +│ │ │ └── assets/ # UI设计资源 +│ │ └── integration/ # 集成设计 +│ │ ├── wechat-integration.md +│ │ └── alipay-integration.md +│ │ +│ ├── development/ # 开发文档 +│ │ ├── quick-start.md # 快速开始指南 +│ │ ├── standards/ # 开发规范 +│ │ │ ├── coding-standards.md # 编码规范 +│ │ │ ├── git-workflow.md # Git工作流 +│ │ │ ├── commit-conventions.md # 提交规范 +│ │ │ └── code-review-guide.md # 代码审查指南 +│ │ ├── best-practices/ # 最佳实践 +│ │ │ ├── react-best-practices.md +│ │ │ ├── nestjs-best-practices.md +│ │ │ └── database-best-practices.md +│ │ ├── guides/ # 开发指南 +│ │ │ ├── adding-new-module.md # 如何添加新模块 +│ │ │ ├── adding-new-api.md # 如何添加新API +│ │ │ └── debugging-guide.md # 调试指南 +│ │ └── faq.md # 常见问题解答 +│ │ +│ ├── api/ # API文档 +│ │ ├── README.md # API文档索引 +│ │ ├── authentication/ # 认证相关API +│ │ │ ├── login.md +│ │ │ ├── register.md +│ │ │ └── token-refresh.md +│ │ ├── user/ # 用户相关API +│ │ │ ├── get-user.md +│ │ │ ├── update-user.md +│ │ │ └── delete-user.md +│ │ ├── payment/ # 支付相关API +│ │ │ ├── create-order.md +│ │ │ ├── query-order.md +│ │ │ └── refund.md +│ │ ├── error-codes.md # 错误码说明 +│ │ └── sdk/ # SDK文档 +│ │ ├── javascript-sdk.md +│ │ └── typescript-sdk.md +│ │ +│ ├── testing/ # 测试文档 +│ │ ├── test-plan.md # 测试计划 +│ │ ├── test-strategy.md # 测试策略 +│ │ ├── test-cases/ # 测试用例 +│ │ │ ├── auth-test-cases.md +│ │ │ ├── payment-test-cases.md +│ │ │ └── permission-test-cases.md +│ │ ├── test-reports/ # 测试报告 +│ │ │ ├── test-report-v1.0.md +│ │ │ └── performance-test-report.md +│ │ └── coverage-report.md # 覆盖率报告 +│ │ +│ ├── deployment/ # 部署文档 +│ │ ├── environment-setup.md # 环境配置 +│ │ ├── docker-guide.md # Docker部署指南 +│ │ ├── kubernetes-guide.md # Kubernetes部署指南 +│ │ ├── aliyun-guide.md # 阿里云部署指南 +│ │ ├── ci-cd-pipeline.md # CI/CD流程 +│ │ └── migration-guide.md # 数据迁移指南 +│ │ +│ ├── operations/ # 运维文档 +│ │ ├── monitoring/ # 监控告警 +│ │ │ ├── monitoring-setup.md # 监控配置 +│ │ │ ├── alert-rules.md # 告警规则 +│ │ │ └── dashboard-guide.md # 仪表盘配置 +│ │ ├── logging/ # 日志管理 +│ │ │ ├── log-collection.md # 日志收集 +│ │ │ ├── log-analysis.md # 日志分析 +│ │ │ └── log-retention.md # 日志留存策略 +│ │ ├── troubleshooting/ # 故障处理 +│ │ │ ├── common-issues.md # 常见问题排查 +│ │ │ ├── emergency-response.md # 应急响应流程 +│ │ │ └── incident-reports/ # 故障报告 +│ │ └── backup-restore/ # 备份恢复 +│ │ ├── backup-strategy.md # 备份策略 +│ │ └── restore-guide.md # 恢复指南 +│ │ +│ ├── user/ # 用户文档 +│ │ ├── getting-started.md # 入门指南 +│ │ ├── user-manual.md # 用户手册 +│ │ ├── usage-guide/ # 使用指南 +│ │ │ ├── monorepo-usage.md # Monorepo模式使用 +│ │ │ ├── standalone-usage.md # 独立项目模式使用 +│ │ │ └── api-service-usage.md # API服务模式使用 +│ │ ├── cli-guide.md # CLI工具使用指南 +│ │ └── faq.md # 用户常见问题 +│ │ +│ ├── templates/ # 文档模板 +│ │ ├── architecture-template.md # 架构文档模板 +│ │ ├── design-template.md # 设计文档模板 +│ │ ├── api-template.md # API文档模板 +│ │ ├── test-case-template.md # 测试用例模板 +│ │ └── adr-template.md # 架构决策记录模板 +│ │ +│ └── README.md # 文档索引和导航 +│ +├── apps/ # 应用层 +├── packages/ # 共享包 +├── services/ # 后端服务 +├── infra/ # 基础设施 +├── tools/ # 开发工具 +└── package.json # Monorepo配置 +``` + +### 2.2 目录说明 + +| 目录 | 用途 | 负责人 | 更新频率 | +|------|------|--------|---------| +| `docs/architecture/` | 架构设计、技术选型、模块划分、架构决策 | 技术负责人 | 重大变更时 | +| `docs/requirements/` | 产品需求、功能规格、用户故事、需求变更 | 产品经理 | 迭代周期 | +| `docs/design/` | 数据库设计、API设计、UI设计、集成设计 | 开发人员 | 功能开发时 | +| `docs/development/` | 开发规范、快速开始、最佳实践、FAQ | 全体开发 | 持续更新 | +| `docs/api/` | API接口文档、SDK文档、错误码说明 | 后端开发 | API变更时 | +| `docs/testing/` | 测试计划、测试用例、测试报告、覆盖率报告 | 测试人员 | 测试周期 | +| `docs/deployment/` | 部署指南、环境配置、CI/CD流程、数据迁移 | DevOps | 部署变更时 | +| `docs/operations/` | 监控告警、日志管理、故障处理、备份恢复 | 运维人员 | 运维变更时 | +| `docs/user/` | 用户手册、使用指南、CLI工具指南、FAQ | 产品经理+开发 | 功能发布时 | +| `docs/templates/` | 各类文档模板 | 文档负责人 | 按需更新 | + +### 2.3 文档分类体系 + +文档按以下维度分类: + +#### 2.3.1 按受众分类 + +| 分类 | 目标受众 | 文档类型 | +|------|---------|---------| +| **技术文档** | 开发人员、架构师 | 架构、设计、开发、API文档 | +| **测试文档** | 测试人员、开发人员 | 测试计划、测试用例、测试报告 | +| **运维文档** | 运维人员、DevOps | 部署、监控、故障处理文档 | +| **业务文档** | 产品经理、业务人员 | 需求文档、用户故事 | +| **用户文档** | 最终用户、使用者 | 用户手册、使用指南、FAQ | + +#### 2.3.2 按生命周期分类 + +| 阶段 | 文档类型 | 示例 | +|------|---------|------| +| **规划阶段** | 需求文档、架构文档 | PRD、架构设计、技术选型 | +| **设计阶段** | 设计文档 | 数据库设计、API设计、UI设计 | +| **开发阶段** | 开发文档、API文档 | 开发规范、API接口文档 | +| **测试阶段** | 测试文档 | 测试计划、测试用例、测试报告 | +| **部署阶段** | 部署文档 | 部署指南、CI/CD流程 | +| **运维阶段** | 运维文档 | 监控配置、故障处理、备份恢复 | +| **使用阶段** | 用户文档 | 用户手册、使用指南、FAQ | + +#### 2.3.3 按稳定性分类 + +| 分类 | 说明 | 更新频率 | 示例 | +|------|------|---------|------| +| **稳定文档** | 内容相对稳定,变更较少 | 季度/半年 | 架构概述、开发规范 | +| **活跃文档** | 内容频繁更新 | 每周/每月 | API文档、FAQ | +| **临时文档** | 一次性或短期使用 | 按需 | 故障报告、测试报告 | + +--- + +## 三、文档分类和职责 + +### 3.1 架构文档 + +**目录**: `docs/architecture/` + +**职责**: 记录系统整体架构设计、技术选型决策、模块划分和架构演进。 + +**文档清单**: + +| 文档 | 说明 | 负责人 | 更新时机 | +|------|------|--------|---------| +| `overview.md` | 整体架构概述,包含架构图、层次结构、技术栈 | 技术负责人 | 架构重大变更 | +| `technology-selection.md` | 技术选型对比和决策依据 | 技术负责人 | 技术栈变更 | +| `module-design.md` | 模块划分、模块职责、模块依赖关系 | 技术负责人 | 模块结构调整 | +| `design-decisions/` | 架构决策记录(ADR),记录重要技术决策 | 技术负责人 | 每次重要决策 | + +**架构决策记录(ADR)规范**: + +每个ADR文件应包含: +- **标题**: ADR-XXX-简短描述 +- **状态**: 提议/接受/废弃/替代 +- **上下文**: 决策背景和问题描述 +- **决策**: 具体决策内容 +- **后果**: 决策带来的正面和负面影响 +- **替代方案**: 考虑过的其他方案 + +### 3.2 需求文档 + +**目录**: `docs/requirements/` + +**职责**: 记录产品需求、功能规格、用户故事和需求变更。 + +**文档清单**: + +| 文档 | 说明 | 负责人 | 更新时机 | +|------|------|--------|---------| +| `product/prd-v*.md` | 产品需求文档,包含产品愿景、目标、功能列表 | 产品经理 | 版本发布 | +| `product/user-stories/` | 用户故事,按模块分类 | 产品经理 | 迭代规划 | +| `features/*-spec.md` | 功能规格说明,详细描述功能需求 | 产品经理+开发 | 功能开发前 | +| `changelog/` | 需求变更记录,跟踪需求变更历史 | 产品经理 | 需求变更 | + +**需求文档规范**: + +每个需求文档应包含: +- **需求背景**: 为什么需要这个功能 +- **用户故事**: 作为[角色],我希望[功能],以便[价值] +- **功能描述**: 详细的功能说明 +- **验收标准**: 功能完成的判断标准 +- **优先级**: P0/P1/P2 +- **依赖关系**: 与其他功能的依赖 +- **非功能需求**: 性能、安全、兼容性要求 + +### 3.3 设计文档 + +**目录**: `docs/design/` + +**职责**: 记录数据库设计、API设计、UI设计和第三方集成设计。 + +**文档清单**: + +| 文档 | 说明 | 负责人 | 更新时机 | +|------|------|--------|---------| +| `database/schema-design.md` | 数据库Schema设计,包含表结构、索引、关系 | 后端开发 | 数据库变更 | +| `database/migration-guide.md` | 数据库迁移指南,包含迁移步骤和回滚方案 | 后端开发 | 数据库迁移 | +| `api/api-design-guidelines.md` | API设计指南,包含RESTful规范、命名规范 | 后端开发 | API规范变更 | +| `ui/design-system.md` | 设计系统,包含颜色、字体、间距、组件规范 | 前端开发+UI | 设计系统更新 | +| `integration/*-integration.md` | 第三方服务集成设计 | 后端开发 | 集成新服务 | + +**数据库设计规范**: + +每个数据库设计文档应包含: +- **ER图**: 实体关系图 +- **表结构**: 表名、字段、类型、约束、索引 +- **关系说明**: 表之间的关系和关联方式 +- **设计决策**: 为什么这样设计 +- **性能考虑**: 索引策略、查询优化 +- **迁移方案**: 如何从旧版本迁移 + +### 3.4 开发文档 + +**目录**: `docs/development/` + +**职责**: 提供开发规范、快速开始指南、最佳实践和常见问题解答。 + +**文档清单**: + +| 文档 | 说明 | 负责人 | 更新时机 | +|------|------|--------|---------| +| `quick-start.md` | 快速开始指南,包含环境搭建、项目运行 | 全体开发 | 环境变更 | +| `standards/` | 开发规范,包含编码规范、Git工作流、提交规范 | 技术负责人 | 规范变更 | +| `best-practices/` | 最佳实践,按技术栈分类 | 资深开发 | 经验积累 | +| `guides/` | 开发指南,包含常见开发任务步骤 | 全体开发 | 新任务类型 | +| `faq.md` | 常见问题解答 | 全体开发 | 问题积累 | + +**快速开始指南规范**: + +快速开始指南应包含: +- **前置条件**: 需要的软件和环境 +- **环境搭建**: 详细的安装和配置步骤 +- **项目克隆**: 如何获取代码 +- **依赖安装**: 如何安装依赖 +- **项目运行**: 如何启动项目 +- **验证步骤**: 如何验证环境正确 +- **常见问题**: 环境搭建常见问题 + +### 3.5 API文档 + +**目录**: `docs/api/` + +**职责**: 提供API接口文档、SDK文档和错误码说明。 + +**文档清单**: + +| 文档 | 说明 | 负责人 | 更新时机 | +|------|------|--------|---------| +| `README.md` | API文档索引,包含API概览和导航 | 后端开发 | API结构调整 | +| `*/` | 按模块分类的API接口文档 | 后端开发 | API变更 | +| `error-codes.md` | 错误码说明,包含错误码、含义、解决方案 | 后端开发 | 新增错误码 | +| `sdk/` | SDK使用文档,包含安装、配置、示例 | 后端开发 | SDK更新 | + +**API文档规范**: + +每个API接口文档应包含: +- **接口路径**: HTTP方法和URL +- **接口描述**: 接口功能说明 +- **请求参数**: 路径参数、查询参数、请求体 +- **响应格式**: 响应体结构、状态码 +- **请求示例**: curl或代码示例 +- **响应示例**: 成功和失败响应示例 +- **错误码**: 可能返回的错误码 +- **权限要求**: 需要的认证和权限 +- **限流策略**: 接口限流说明 + +### 3.6 测试文档 + +**目录**: `docs/testing/` + +**职责**: 提供测试计划、测试用例、测试报告和覆盖率报告。 + +**文档清单**: + +| 文档 | 说明 | 负责人 | 更新时机 | +|------|------|--------|---------| +| `test-plan.md` | 测试计划,包含测试范围、策略、资源、进度 | 测试人员 | 测试周期开始 | +| `test-strategy.md` | 测试策略,包含测试层级、工具、覆盖率要求 | 测试人员 | 测试策略变更 | +| `test-cases/` | 测试用例,按模块分类 | 测试人员 | 功能开发完成 | +| `test-reports/` | 测试报告,按版本分类 | 测试人员 | 测试完成 | +| `coverage-report.md` | 测试覆盖率报告 | 测试人员 | 每次测试执行 | + +**测试用例规范**: + +每个测试用例应包含: +- **用例ID**: 唯一标识 +- **用例名称**: 简洁描述 +- **前置条件**: 执行用例的前提 +- **测试步骤**: 详细的操作步骤 +- **预期结果**: 期望的结果 +- **实际结果**: 实际执行结果(执行时填写) +- **优先级**: P0/P1/P2 +- **自动化状态**: 手动/自动化 + +### 3.7 部署文档 + +**目录**: `docs/deployment/` + +**职责**: 提供部署指南、环境配置、CI/CD流程和数据迁移指南。 + +**文档清单**: + +| 文档 | 说明 | 负责人 | 更新时机 | +|------|------|--------|---------| +| `environment-setup.md` | 环境配置,包含开发、测试、生产环境配置 | DevOps | 环境变更 | +| `docker-guide.md` | Docker部署指南 | DevOps | Docker配置变更 | +| `kubernetes-guide.md` | Kubernetes部署指南 | DevOps | K8s配置变更 | +| `aliyun-guide.md` | 阿里云部署指南 | DevOps | 云资源变更 | +| `ci-cd-pipeline.md` | CI/CD流程配置 | DevOps | 流水线变更 | +| `migration-guide.md` | 数据迁移指南 | 后端开发+DevOps | 数据迁移 | + +**部署文档规范**: + +部署文档应包含: +- **环境要求**: 硬件、软件、网络要求 +- **部署步骤**: 详细的部署操作流程 +- **配置说明**: 环境变量、配置文件说明 +- **验证步骤**: 如何验证部署成功 +- **回滚方案**: 部署失败如何回滚 +- **常见问题**: 部署常见问题和解决方案 + +### 3.8 运维文档 + +**目录**: `docs/operations/` + +**职责**: 提供监控告警、日志管理、故障处理和备份恢复指南。 + +**文档清单**: + +| 文档 | 说明 | 负责人 | 更新时机 | +|------|------|--------|---------| +| `monitoring/` | 监控告警配置、告警规则、仪表盘配置 | 运维人员 | 监控变更 | +| `logging/` | 日志收集、分析、留存策略 | 运维人员 | 日志策略变更 | +| `troubleshooting/` | 故障处理指南、应急响应流程、故障报告 | 运维人员 | 故障发生 | +| `backup-restore/` | 备份策略、恢复指南 | 运维人员 | 备份策略变更 | + +**故障处理文档规范**: + +故障处理文档应包含: +- **故障现象**: 故障的表现和影响范围 +- **排查步骤**: 逐步排查指南 +- **解决方案**: 具体的解决步骤 +- **预防措施**: 如何避免类似故障 +- **升级路径**: 无法解决时的升级流程 + +### 3.9 用户文档 + +**目录**: `docs/user/` + +**职责**: 提供用户手册、使用指南、CLI工具指南和常见问题解答。 + +**文档清单**: + +| 文档 | 说明 | 负责人 | 更新时机 | +|------|------|--------|---------| +| `getting-started.md` | 入门指南,快速上手 | 产品经理+开发 | 功能变更 | +| `user-manual.md` | 用户手册,详细功能说明 | 产品经理 | 版本发布 | +| `usage-guide/` | 使用指南,按使用模式分类 | 产品经理+开发 | 使用模式变更 | +| `cli-guide.md` | CLI工具使用指南 | 后端开发 | CLI更新 | +| `faq.md` | 用户常见问题 | 产品经理+开发 | 问题积累 | + +**用户文档规范**: + +用户文档应包含: +- **目标用户**: 文档面向的用户群体 +- **前置知识**: 使用产品需要的背景知识 +- **操作步骤**: 图文并茂的操作指南 +- **示例场景**: 实际使用场景示例 +- **常见问题**: 使用过程中常见问题 +- **获取帮助**: 如何获取技术支持 + +--- + +## 四、文档编写规范 + +### 4.1 文档模板 + +#### 4.1.1 文档头部信息 + +每个文档开头必须包含以下元信息: + +```markdown +# 文档标题 + +> **文档版本**: v1.0.0 +> **创建日期**: YYYY-MM-DD +> **最后更新**: YYYY-MM-DD +> **文档作者**: 作者姓名 +> **文档审核**: 审核人姓名 +> **文档状态**: 草稿/评审中/已发布/已归档/已废弃 +> **适用范围**: 适用的人员或场景 +``` + +#### 4.1.2 文档目录 + +文档超过3个章节时,必须提供目录: + +```markdown +## 目录 + +- [一、章节一](#一章节一) +- [二、章节二](#二章节二) +- [三、章节三](#三章节三) +``` + +#### 4.1.3 文档尾部信息 + +文档结尾应包含: + +```markdown +--- + +> **文档维护**: 本文档由[角色]维护,定期更新 +> **反馈渠道**: 如有问题,请提交Issue或联系[联系方式] +> **最后更新**: YYYY-MM-DD +> **文档状态**: 当前状态 +``` + +### 4.2 命名规范 + +#### 4.2.1 文件命名 + +| 规则 | 说明 | 示例 | +|------|------|------| +| **使用kebab-case** | 小写字母,单词间用连字符连接 | `quick-start.md` | +| **语义化命名** | 文件名应清晰表达内容 | `technology-selection.md` | +| **避免特殊字符** | 只使用小写字母、数字、连字符 | `ci-cd-pipeline.md` | +| **版本号文件** | 使用v前缀和语义化版本号 | `prd-v1.0.md` | +| **ADR文件** | 使用ADR-序号-描述格式 | `ADR-001-monorepo-structure.md` | + +#### 4.2.2 目录命名 + +| 规则 | 说明 | 示例 | +|------|------|------| +| **使用kebab-case** | 小写字母,单词间用连字符 | `design-decisions/` | +| **复数形式** | 集合目录使用复数形式 | `test-cases/`, `test-reports/` | +| **语义化命名** | 目录名应清晰表达内容分类 | `best-practices/` | + +#### 4.2.3 标题命名 + +| 规则 | 说明 | 示例 | +|------|------|------| +| **使用中文数字** | 一级标题使用一、二、三 | `## 一、文档管理概述` | +| **层级清晰** | 使用##、###、####表示层级 | `## 1.1 目的` | +| **简洁明了** | 标题应简洁表达内容 | `### 4.1 文档模板` | + +### 4.3 格式规范 + +#### 4.3.1 Markdown格式 + +| 元素 | 格式 | 示例 | +|------|------|------| +| **一级标题** | `# 标题` | `# FischerX 文档管理规范` | +| **二级标题** | `## 标题` | `## 一、文档管理概述` | +| **三级标题** | `### 标题` | `### 1.1 目的` | +| **粗体** | `**文本**` | `**重要**` | +| **斜体** | `*文本*` | `*说明*` | +| **代码** | `` `代码` `` | `` `npm install` `` | +| **代码块** | ` ```语言\n代码\n``` ` | 见下方示例 | +| **链接** | `[文本](URL)` | `[架构设计](docs/architecture/overview.md)` | +| **图片** | `![描述](路径)` | `![架构图](diagrams/architecture.png)` | +| **表格** | 使用Markdown表格语法 | 见下方示例 | +| **列表** | 使用-或*无序,1.有序 | 见下方示例 | + +#### 4.3.2 代码块规范 + +```markdown +```typescript +// 代码块必须指定语言 +interface User { + id: string; + name: string; + email: string; +} +``` + +```bash +# Shell命令示例 +$ npm install +$ npm run dev +``` + +```yaml +# 配置文件示例 +version: '3.8' +services: + api: + image: fischerx-api:latest +``` +``` + +#### 4.3.3 表格规范 + +- 表格必须有表头 +- 表格列应对齐 +- 表格内容应简洁明了 +- 复杂表格可拆分为多个表格 + +```markdown +| 列1 | 列2 | 列3 | +|------|------|------| +| 内容1 | 内容2 | 内容3 | +| 内容4 | 内容5 | 内容6 | +``` + +#### 4.3.4 列表规范 + +- 列表项应保持一致的缩进 +- 列表项应简洁明了 +- 复杂列表项可使用子列表 + +```markdown +- 第一项 +- 第二项 + - 子项1 + - 子项2 +- 第三项 + +1. 第一项 +2. 第二项 +3. 第三项 +``` + +#### 4.3.5 引用规范 + +```markdown +> 这是一段引用文本 +> 可以跨多行 +``` + +#### 4.3.6 链接规范 + +- 内部链接使用相对路径 +- 外部链接使用完整URL +- 链接文本应清晰表达目标 + +```markdown + +[架构设计](../architecture/overview.md) + + +[Next.js官方文档](https://nextjs.org/docs) +``` + +### 4.4 版本控制 + +#### 4.4.1 Git管理 + +- 所有文档使用Git进行版本控制 +- 文档与代码在同一仓库管理 +- 文档变更通过Pull Request审核 +- 文档提交信息遵循Conventional Commits规范 + +```bash +# 文档提交示例 +docs(architecture): update system architecture diagram +docs(api): add payment API documentation +docs(development): update quick start guide +``` + +#### 4.4.2 版本号规范 + +文档版本号遵循语义化版本规范(SemVer): + +| 版本类型 | 说明 | 示例 | +|---------|------|------| +| **主版本号** | 重大变更,不兼容的修改 | v1.0.0 → v2.0.0 | +| **次版本号** | 新增功能,向后兼容 | v1.0.0 → v1.1.0 | +| **修订号** | 修复错误,向后兼容 | v1.0.0 → v1.0.1 | + +#### 4.4.3 变更日志 + +重要文档应维护变更日志: + +```markdown +## 变更日志 + +### v1.1.0 (2026-06-01) +- 新增:添加支付模块架构设计 +- 更新:完善数据库设计文档 +- 修复:修正API文档中的错误示例 + +### v1.0.0 (2026-05-24) +- 初始版本发布 +``` + +### 4.5 图表规范 + +#### 4.5.1 架构图 + +- 使用Mermaid或PlantUML绘制(优先使用Mermaid,支持Markdown内渲染) +- 复杂图表可使用PNG/SVG格式存储在`diagrams/`目录 +- 图表应有标题和说明 + +```markdown +```mermaid +graph TD + A[前端应用] --> B[API网关] + B --> C[认证服务] + B --> D[业务服务] + C --> E[(数据库)] + D --> E + D --> F[(缓存)] +``` + +*图1: 系统架构概览* +``` + +#### 4.5.2 流程图 + +```markdown +```mermaid +sequenceDiagram + participant U as 用户 + participant F as 前端 + participant A as API + participant D as 数据库 + + U->>F: 提交登录请求 + F->>A: 发送认证请求 + A->>D: 查询用户信息 + D-->>A: 返回用户数据 + A-->>F: 返回认证结果 + F-->>U: 显示登录结果 +``` + +*图2: 用户登录流程* +``` + +#### 4.5.3 ER图 + +```markdown +```mermaid +erDiagram + USER ||--o{ ORDER : places + USER { + string id + string name + string email + } + ORDER ||--|{ ORDER_ITEM : contains + ORDER { + string id + date created_at + float total + } +``` + +*图3: 用户订单ER图* +``` + +#### 4.5.4 图片资源管理 + +- 图片资源存储在对应文档目录的`assets/`或`diagrams/`子目录 +- 图片命名使用kebab-case +- 图片格式优先使用SVG(矢量图)或PNG(位图) +- 图片大小应优化,避免过大 + +--- + +## 五、文档维护流程 + +### 5.1 文档创建流程 + +```mermaid +graph LR + A[识别文档需求] --> B[选择文档模板] + B --> C[创建文档草稿] + C --> D[编写文档内容] + D --> E[自我审查] + E --> F[提交PR审核] + F --> G[团队审查] + G --> H{审查通过?} + H -->|是| I[合并并发布] + H -->|否| J[修改文档] + J --> F + I --> K[更新文档索引] +``` + +**详细步骤**: + +| 步骤 | 操作 | 负责人 | 输出 | +|------|------|--------|------| +| 1 | 识别文档需求,确定文档类型和位置 | 需求提出者 | 文档需求说明 | +| 2 | 从`docs/templates/`选择合适模板 | 文档作者 | 文档草稿 | +| 3 | 编写文档内容,遵循文档规范 | 文档作者 | 文档初稿 | +| 4 | 自我审查,检查格式、内容、链接 | 文档作者 | 审查后的文档 | +| 5 | 提交Pull Request,指定审核人 | 文档作者 | PR | +| 6 | 团队审查,提出修改意见 | 审核人 | 审查意见 | +| 7 | 根据审查意见修改文档 | 文档作者 | 修改后的文档 | +| 8 | 审查通过,合并到主分支 | 技术负责人 | 已发布的文档 | +| 9 | 更新`docs/README.md`文档索引 | 文档作者 | 更新的索引 | + +### 5.2 文档更新流程 + +```mermaid +graph LR + A[识别更新需求] --> B{更新类型} + B -->|内容修正| C[直接修改] + B -->|内容新增| D[新增章节] + B -->|结构变更| E[调整目录结构] + C --> F[提交PR] + D --> F + E --> F + F --> G[审核] + G --> H{审核通过?} + H -->|是| I[合并并更新版本号] + H -->|否| J[修改] + J --> F + I --> K[更新变更日志] +``` + +**更新触发条件**: + +| 触发条件 | 更新类型 | 更新范围 | +|---------|---------|---------| +| 代码功能变更 | 内容修正/新增 | 相关API文档、开发文档 | +| 架构调整 | 结构变更 | 架构文档、设计文档 | +| 规范变更 | 内容修正 | 开发规范文档 | +| 发现问题 | 内容修正 | 相关文档 | +| 用户反馈 | 内容新增/修正 | 用户文档、FAQ | +| 定期审计 | 全面检查 | 所有文档 | + +**更新流程**: + +| 步骤 | 操作 | 负责人 | 输出 | +|------|------|--------|------| +| 1 | 识别更新需求,确定更新范围 | 任何人 | 更新需求说明 | +| 2 | 修改文档内容 | 文档负责人 | 修改后的文档 | +| 3 | 更新文档版本号和最后更新日期 | 文档作者 | 更新的元信息 | +| 4 | 更新变更日志 | 文档作者 | 更新的变更日志 | +| 5 | 提交PR审核 | 文档作者 | PR | +| 6 | 审核通过,合并 | 审核人 | 已更新的文档 | + +### 5.3 文档审核流程 + +```mermaid +graph TD + A[提交PR] --> B[自动化检查] + B --> C{检查通过?} + C -->|否| D[修复问题] + D --> B + C -->|是| E[人工审核] + E --> F{审核标准} + F -->|内容准确性| G[技术审核] + F -->|格式规范性| H[格式审核] + F -->|完整性| I[完整性审核] + G --> J{审核通过?} + H --> J + I --> J + J -->|是| K[合并] + J -->|否| L[修改] + L --> E +``` + +**审核清单**: + +| 审核项 | 说明 | 优先级 | +|--------|------|--------| +| **内容准确性** | 技术内容是否正确 | 高 | +| **完整性** | 是否覆盖所有必要内容 | 高 | +| **格式规范** | 是否遵循文档规范 | 高 | +| **链接有效性** | 内部和外部链接是否有效 | 中 | +| **图表清晰度** | 图表是否清晰易懂 | 中 | +| **示例可用性** | 代码示例是否可运行 | 高 | +| **版本一致性** | 文档版本与代码版本是否一致 | 高 | +| **语言流畅性** | 语言是否流畅、无错别字 | 中 | + +### 5.4 文档发布流程 + +| 步骤 | 操作 | 负责人 | 输出 | +|------|------|--------|------| +| 1 | 文档审核通过 | 审核人 | 审核通过的PR | +| 2 | 合并到主分支 | 技术负责人 | 已合并的文档 | +| 3 | 更新文档索引(docs/README.md) | 文档作者 | 更新的索引 | +| 4 | 发布通知(如重要文档) | 文档负责人 | 发布通知 | +| 5 | 更新文档状态为"已发布" | 文档作者 | 已发布的文档 | + +### 5.5 文档归档流程 + +**归档条件**: + +| 条件 | 说明 | +|------|------| +| **功能废弃** | 相关功能已废弃,文档不再适用 | +| **版本过期** | 文档对应的版本已不再支持 | +| **内容替代** | 文档内容已被新文档替代 | +| **长期未更新** | 文档超过1年未更新且确认过时 | + +**归档流程**: + +| 步骤 | 操作 | 负责人 | 输出 | +|------|------|--------|------| +| 1 | 识别归档需求 | 任何人 | 归档需求说明 | +| 2 | 确认归档条件 | 文档负责人 | 归档确认 | +| 3 | 移动文档到`docs/archive/`目录 | 文档作者 | 归档的文档 | +| 4 | 更新文档状态为"已归档" | 文档作者 | 更新的元信息 | +| 5 | 更新文档索引,移除归档文档 | 文档作者 | 更新的索引 | +| 6 | 提交PR审核合并 | 文档作者 | 已归档的文档 | + +### 5.6 文档过期处理 + +**过期预警机制**: + +| 文档类型 | 检查周期 | 过期条件 | +|---------|---------|---------| +| **架构文档** | 每季度 | 超过6个月未更新 | +| **API文档** | 每月 | 超过1个月未更新 | +| **开发文档** | 每季度 | 超过3个月未更新 | +| **部署文档** | 每季度 | 超过3个月未更新 | +| **用户文档** | 每季度 | 超过3个月未更新 | + +**过期处理流程**: + +| 步骤 | 操作 | 负责人 | 输出 | +|------|------|--------|------| +| 1 | 定期检查文档更新时间 | 文档负责人/自动化脚本 | 过期文档列表 | +| 2 | 通知文档负责人 | 文档负责人 | 通知 | +| 3 | 评估文档是否仍适用 | 文档负责人 | 评估结果 | +| 4a | 如适用:更新文档 | 文档负责人 | 更新的文档 | +| 4b | 如不适用:标记为过期或归档 | 文档负责人 | 标记/归档的文档 | +| 5 | 记录处理结果 | 文档负责人 | 处理记录 | + +--- + +## 六、文档与代码同步策略 + +### 6.1 同步原则 + +| 原则 | 说明 | +|------|------| +| **代码变更,文档先行** | 代码变更前先更新相关文档 | +| **文档即代码** | 文档变更与代码变更同等重要 | +| **自动化优先** | 尽可能使用工具自动生成文档 | +| **同步审核** | 代码审核时同步审核相关文档 | +| **版本对应** | 文档版本与代码版本严格对应 | + +### 6.2 代码变更时同步更新文档 + +#### 6.2.1 变更影响分析 + +代码变更时,开发者应分析对相关文档的影响: + +| 代码变更类型 | 影响的文档 | 更新要求 | +|-------------|-----------|---------| +| **新增API接口** | API文档、错误码文档 | 必须更新 | +| **修改API接口** | API文档、错误码文档 | 必须更新 | +| **删除API接口** | API文档 | 必须更新 | +| **数据库Schema变更** | 数据库设计文档、迁移指南 | 必须更新 | +| **架构调整** | 架构文档、模块设计文档 | 必须更新 | +| **新增功能模块** | 开发文档、用户文档 | 必须更新 | +| **修改开发规范** | 开发规范文档 | 必须更新 | +| **部署配置变更** | 部署文档、运维文档 | 必须更新 | +| **Bug修复** | FAQ、故障处理文档 | 建议更新 | + +#### 6.2.2 PR模板中的文档检查 + +在Pull Request模板中添加文档检查清单: + +```markdown +## 文档更新检查 + +- [ ] 已更新相关API文档 +- [ ] 已更新数据库设计文档(如适用) +- [ ] 已更新开发文档(如适用) +- [ ] 已更新部署文档(如适用) +- [ ] 已更新用户文档(如适用) +- [ ] 已更新变更日志 +- [ ] 文档链接有效 +- [ ] 代码示例可运行 +``` + +#### 6.2.3 代码审查中的文档审核 + +代码审查时,审查人应同时审核: + +| 审核项 | 说明 | +|--------|------| +| **文档是否更新** | 相关文档是否同步更新 | +| **文档准确性** | 文档内容是否准确反映代码变更 | +| **示例代码** | 文档中的示例代码是否与变更一致 | +| **变更日志** | 是否更新相关文档的变更日志 | + +### 6.3 CI/CD流程中集成文档检查 + +#### 6.3.1 文档检查项 + +| 检查项 | 工具 | 说明 | +|--------|------|------| +| **Markdown格式检查** | markdownlint | 检查Markdown格式规范 | +| **链接有效性检查** | markdown-link-check | 检查文档链接是否有效 | +| **拼写检查** | cspell/vale | 检查拼写错误 | +| **文档结构检查** | 自定义脚本 | 检查文档头部信息是否完整 | +| **代码示例检查** | 自定义脚本 | 检查代码示例是否可运行 | + +#### 6.3.2 CI配置示例 + +```yaml +# .github/workflows/docs-check.yml +name: Documentation Check + +on: + push: + paths: + - 'docs/**' + - '**/*.md' + pull_request: + paths: + - 'docs/**' + - '**/*.md' + +jobs: + docs-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Markdown Lint + uses: DavidAnson/markdownlint-cli2-action@v15 + with: + globs: 'docs/**/*.md' + + - name: Link Check + uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + use-quiet-mode: 'yes' + config-file: '.markdown-link-check.json' + + - name: Spell Check + uses: streetsidesoftware/cspell-action@v6 + with: + files: 'docs/**/*.md' + + - name: Check Document Headers + run: | + # 自定义脚本检查文档头部信息 + node scripts/check-doc-headers.js +``` + +### 6.4 文档版本与代码版本对应 + +#### 6.4.1 版本对应策略 + +| 代码版本 | 文档版本 | 说明 | +|---------|---------|------| +| v1.0.0 | v1.0.0 | 初始版本 | +| v1.1.0 | v1.1.0 | 功能更新 | +| v1.0.1 | v1.0.1 | 修复更新 | +| v2.0.0 | v2.0.0 | 重大变更 | + +#### 6.4.2 版本标记 + +在重要文档中使用版本标记: + +```markdown +> **适用版本**: v1.0.0+ +> **最后更新**: 2026-05-24 +> **对应代码版本**: v1.0.0 +``` + +#### 6.4.3 版本分支管理 + +| 分支 | 文档版本 | 说明 | +|------|---------|------| +| `main` | 最新稳定版 | 生产环境对应文档 | +| `develop` | 开发版 | 开发环境对应文档 | +| `release/*` | 发布候选版 | 预发布环境对应文档 | +| `docs/*` | 文档专项分支 | 文档重构等专项工作 | + +### 6.5 自动化文档生成 + +#### 6.5.1 API文档自动生成 + +使用工具从代码注释自动生成API文档: + +| 工具 | 适用场景 | 配置 | +|------|---------|------| +| **Swagger/OpenAPI** | RESTful API文档 | 从代码注释生成OpenAPI规范 | +| **TypeDoc** | TypeScript类型文档 | 从TypeScript代码生成类型文档 | +| **JSDoc** | JavaScript函数文档 | 从JSDoc注释生成函数文档 | + +**Swagger配置示例**: + +```typescript +// services/api/src/controllers/user.controller.ts +import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; + +@ApiTags('user') +@Controller('user') +export class UserController { + @ApiOperation({ summary: '获取用户信息' }) + @ApiResponse({ status: 200, description: '成功返回用户信息' }) + @ApiResponse({ status: 404, description: '用户不存在' }) + @Get(':id') + async getUser(@Param('id') id: string) { + // ... + } +} +``` + +**TypeDoc配置示例**: + +```json +// typedoc.json +{ + "entryPoints": ["packages/core/src/index.ts"], + "out": "docs/api/typedoc", + "theme": "default", + "excludePrivate": true, + "excludeProtected": true +} +``` + +#### 6.5.2 类型文档自动生成 + +使用TypeDoc自动生成类型定义文档: + +```bash +# 生成类型文档 +$ npx typedoc --out docs/api/types packages/types/src + +# 在文档中链接生成的类型文档 +[类型文档](api/types/index.html) +``` + +#### 6.5.3 数据库文档自动生成 + +使用工具从Prisma Schema生成数据库文档: + +```bash +# 使用prisma-docs生成数据库文档 +$ npx prisma-docs --output docs/design/database/schema-docs + +# 或使用dbdocs +$ dbdocs push prisma/schema.prisma +``` + +#### 6.5.4 文档站点生成 + +使用Docusaurus或VitePress生成文档站点: + +```bash +# 使用Docusaurus初始化文档站点 +$ npx create-docusaurus@latest docs-site classic + +# 使用VitePress初始化文档站点 +$ npx create-vitepress@latest docs-site +``` + +--- + +## 七、文档工具链 + +### 7.1 文档生成工具 + +| 工具 | 用途 | 配置难度 | 推荐场景 | +|------|------|---------|---------| +| **TypeDoc** | TypeScript类型文档生成 | 低 | 类型定义文档 | +| **Swagger UI** | API文档展示 | 中 | RESTful API文档 | +| **Docusaurus** | 文档站点生成 | 中 | 完整文档站点 | +| **VitePress** | 轻量文档站点 | 低 | 快速文档站点 | +| **Mermaid** | Markdown内图表 | 低 | 架构图、流程图 | +| **PlantUML** | UML图生成 | 中 | 复杂UML图 | +| **dbdocs** | 数据库文档生成 | 低 | 数据库Schema文档 | + +### 7.2 文档检查工具 + +| 工具 | 用途 | 配置难度 | 检查项 | +|------|------|---------|--------| +| **markdownlint** | Markdown格式检查 | 低 | 格式规范 | +| **markdown-link-check** | 链接有效性检查 | 低 | 内部/外部链接 | +| **cspell** | 拼写检查 | 中 | 拼写错误 | +| **vale** | 风格检查 | 中 | 写作风格、术语 | +| **textlint** | 文本检查 | 中 | 语法、风格 | + +**markdownlint配置示例**: + +```json +// .markdownlint.json +{ + "default": true, + "MD013": false, + "MD024": { "siblings_only": true }, + "MD033": false, + "MD041": false +} +``` + +### 7.3 文档搜索工具 + +| 工具 | 用途 | 配置难度 | 特点 | +|------|------|---------|------| +| **Algolia DocSearch** | 文档搜索 | 中 | 免费、快速、准确 | +| **FlexSearch** | 客户端搜索 | 低 | 轻量、快速 | +| **Lunr.js** | 客户端搜索 | 低 | 支持多语言 | + +### 7.4 文档协作平台 + +| 平台 | 用途 | 适用场景 | +|------|------|---------| +| **飞书文档** | 文档协作、评审 | 团队内部文档协作 | +| **语雀** | 知识库管理 | 团队知识库 | +| **GitHub Wiki** | 项目文档 | 开源项目文档 | +| **Confluence** | 企业Wiki | 企业级文档管理 | + +### 7.5 工具配置示例 + +#### 7.5.1 package.json脚本 + +```json +{ + "scripts": { + "docs:lint": "markdownlint-cli2 'docs/**/*.md'", + "docs:lint:fix": "markdownlint-cli2 'docs/**/*.md' --fix", + "docs:links": "markdown-link-check docs/**/*.md", + "docs:spell": "cspell 'docs/**/*.md'", + "docs:check": "npm run docs:lint && npm run docs:links && npm run docs:spell", + "docs:dev": "docusaurus start docs-site", + "docs:build": "docusaurus build docs-site", + "docs:typedoc": "typedoc --out docs/api/types packages/types/src", + "docs:api": "swagger-cli bundle services/api/src/openapi.yaml -o docs/api/openapi.yaml", + "docs:all": "npm run docs:typedoc && npm run docs:api && npm run docs:build" + } +} +``` + +#### 7.5.2 Husky钩子配置 + +```json +// .husky/pre-commit +#!/bin/sh +npm run docs:lint +``` + +#### 7.5.3 VS Code插件推荐 + +| 插件 | 用途 | +|------|------| +| **Markdown All in One** | Markdown编辑增强 | +| **Markdown Preview Enhanced** | Markdown预览增强 | +| **markdownlint** | Markdown格式检查 | +| **Mermaid Preview** | Mermaid图表预览 | +| **PlantUML** | PlantUML图表支持 | +| **Code Spell Checker** | 拼写检查 | + +--- + +## 八、文档质量保障 + +### 8.1 文档审查清单 + +#### 8.1.1 内容审查 + +| 检查项 | 说明 | 是否通过 | +|--------|------|---------| +| **准确性** | 技术内容是否准确无误 | □ | +| **完整性** | 是否覆盖所有必要内容 | □ | +| **一致性** | 与其他文档是否一致 | □ | +| **时效性** | 内容是否最新 | □ | +| **实用性** | 内容是否对读者有用 | □ | + +#### 8.1.2 格式审查 + +| 检查项 | 说明 | 是否通过 | +|--------|------|---------| +| **头部信息** | 文档头部元信息是否完整 | □ | +| **目录结构** | 目录是否清晰完整 | □ | +| **标题层级** | 标题层级是否正确 | □ | +| **代码格式** | 代码块是否指定语言 | □ | +| **表格格式** | 表格是否规范 | □ | +| **链接有效性** | 所有链接是否有效 | □ | +| **图片显示** | 图片是否正常显示 | □ | +| **拼写语法** | 是否有拼写和语法错误 | □ | + +#### 8.1.3 示例审查 + +| 检查项 | 说明 | 是否通过 | +|--------|------|---------| +| **代码示例** | 代码示例是否可运行 | □ | +| **配置示例** | 配置示例是否完整 | □ | +| **命令示例** | 命令示例是否可执行 | □ | +| **输出示例** | 输出示例是否准确 | □ | + +### 8.2 文档质量指标 + +| 指标 | 目标值 | 测量方法 | +|------|--------|---------| +| **文档覆盖率** | > 90% | 功能数/文档数比例 | +| **文档更新及时率** | > 95% | 代码变更后7天内文档更新比例 | +| **文档准确率** | > 98% | 文档审查通过率 | +| **文档可读性** | > 80分 | 读者评分 | +| **文档搜索成功率** | > 90% | 搜索后找到目标文档比例 | +| **文档反馈响应时间** | < 3天 | 反馈到处理时间 | + +### 8.3 定期文档审计 + +#### 8.3.1 审计周期 + +| 文档类型 | 审计周期 | 负责人 | +|---------|---------|--------| +| **架构文档** | 每季度 | 技术负责人 | +| **API文档** | 每月 | 后端开发负责人 | +| **开发文档** | 每季度 | 开发负责人 | +| **部署文档** | 每季度 | DevOps负责人 | +| **用户文档** | 每季度 | 产品负责人 | +| **全部文档** | 每半年 | 文档负责人 | + +#### 8.3.2 审计流程 + +| 步骤 | 操作 | 输出 | +|------|------|------| +| 1 | 制定审计计划 | 审计计划 | +| 2 | 收集文档列表 | 文档清单 | +| 3 | 逐文档审查 | 审查记录 | +| 4 | 识别问题文档 | 问题文档列表 | +| 5 | 制定修复计划 | 修复计划 | +| 6 | 执行修复 | 修复后的文档 | +| 7 | 审计总结 | 审计报告 | + +#### 8.3.3 审计报告模板 + +```markdown +# 文档审计报告 + +> **审计周期**: YYYY-MM-DD 至 YYYY-MM-DD +> **审计人**: 审计人姓名 +> **审计日期**: YYYY-MM-DD + +## 审计范围 + +- 审计文档数量: XX篇 +- 审计文档类型: 架构、API、开发、部署、用户 + +## 审计结果 + +| 指标 | 目标值 | 实际值 | 是否达标 | +|------|--------|--------|---------| +| 文档覆盖率 | > 90% | XX% | □ | +| 文档更新及时率 | > 95% | XX% | □ | +| 文档准确率 | > 98% | XX% | □ | + +## 问题文档 + +| 文档 | 问题 | 优先级 | 修复计划 | +|------|------|--------|---------| +| 文档1 | 问题描述 | P0/P1/P2 | 修复日期 | +| 文档2 | 问题描述 | P0/P1/P2 | 修复日期 | + +## 改进建议 + +1. 建议1 +2. 建议2 +3. 建议3 + +## 总结 + +审计总结和下一步行动计划 +``` + +### 8.4 文档反馈机制 + +#### 8.4.1 反馈渠道 + +| 渠道 | 适用场景 | 响应时间 | +|------|---------|---------| +| **GitHub Issues** | 文档错误、缺失、建议 | 3个工作日内 | +| **飞书群** | 紧急文档问题 | 1个工作日内 | +| **邮件** | 正式文档反馈 | 3个工作日内 | +| **文档评论** | 具体章节反馈 | 3个工作日内 | + +#### 8.4.2 反馈处理流程 + +```mermaid +graph LR + A[收到反馈] --> B[分类反馈] + B --> C{反馈类型} + C -->|文档错误| D[修复文档] + C -->|内容缺失| E[补充内容] + C -->|改进建议| F[评估建议] + F --> G{是否采纳} + G -->|是| H[实施改进] + G -->|否| I[反馈原因] + D --> J[验证修复] + E --> J + H --> J + J --> K[关闭反馈] + I --> K +``` + +#### 8.4.3 反馈模板 + +```markdown +## 文档反馈 + +**文档路径**: docs/xxx/xxx.md +**反馈类型**: 错误/缺失/建议 +**优先级**: P0/P1/P2 + +### 问题描述 + +详细描述问题或建议 + +### 期望结果 + +期望的文档内容或格式 + +### 截图(可选) + +如有必要,提供截图说明 +``` + +--- + +## 九、附录 + +### 9.1 文档状态说明 + +| 状态 | 说明 | 颜色标记 | +|------|------|---------| +| **草稿** | 文档正在编写中,未完成 | 🟡 黄色 | +| **评审中** | 文档已完成,正在评审 | 🔵 蓝色 | +| **已发布** | 文档已审核发布 | 🟢 绿色 | +| **已归档** | 文档已归档,不再维护 | ⚪ 灰色 | +| **已废弃** | 文档已废弃,仅供参考 | 🔴 红色 | + +### 9.2 版本号规范 + +文档版本号遵循语义化版本规范(SemVer): + +``` +主版本号.次版本号.修订号 + +示例: v1.0.0 + +- 主版本号: 重大变更,不兼容的修改 +- 次版本号: 新增功能,向后兼容 +- 修订号: 修复错误,向后兼容 +``` + +### 9.3 术语表 + +| 术语 | 说明 | +|------|------| +| **ADR** | Architecture Decision Record,架构决策记录 | +| **PRD** | Product Requirements Document,产品需求文档 | +| **SemVer** | Semantic Versioning,语义化版本规范 | +| **CI/CD** | Continuous Integration/Continuous Deployment,持续集成/持续部署 | +| **PR** | Pull Request,拉取请求 | +| **Monorepo** | 单一代码仓库管理多个项目或包 | +| **Markdown** | 轻量级标记语言 | +| **Mermaid** | 基于JavaScript的图表生成工具 | +| **TypeDoc** | TypeScript文档生成工具 | +| **Swagger** | API文档生成工具 | + +### 9.4 参考文档 + +- [FischerX架构设计方案.md](file:///Users/Chiguyong/Code/FischerX/FischerX架构设计方案.md) - 详细架构设计文档 +- [FischerX开发计划.md](file:///Users/Chiguyong/Code/FischerX/FischerX开发计划.md) - 详细开发计划 +- [spec.md](file:///Users/Chiguyong/Code/FischerX/.trae/specs/initialize-fischerx-foundation/spec.md) - 项目规格说明 +- [Conventional Commits规范](https://www.conventionalcommits.org/) - 提交信息规范 +- [语义化版本规范2.0.0](https://semver.org/lang/zh-CN/) - 版本号规范 +- [Markdown语法指南](https://markdown.com.cn/) - Markdown语法参考 + +--- + +> **文档维护**: 本文档由文档负责人维护,每季度审计更新 +> **反馈渠道**: 如有问题,请提交GitHub Issue或联系技术负责人 +> **最后更新**: 2026-05-24 +> **文档状态**: 正式发布 diff --git a/FischerX架构设计方案.md b/FischerX架构设计方案.md new file mode 100644 index 0000000..a6723ae --- /dev/null +++ b/FischerX架构设计方案.md @@ -0,0 +1,1011 @@ +# FischerX 架构设计方案 + +## 一、现代全栈开发底座理念分析 + +### 1.1 核心设计理念 + +现代全栈开发底座(如Epic Stack、SaaS Boilerplate等)遵循以下核心设计理念: + +#### 1.1.1 模块化设计 +- **组件化架构**:将系统拆分为独立、可复用的模块,降低耦合度 +- **插件化扩展**:通过插件机制实现功能扩展,避免核心代码修改 +- **微服务化趋势**:支持从单体应用平滑过渡到微服务架构 + +#### 1.1.2 可扩展性 +- **水平扩展能力**:支持分布式部署和负载均衡 +- **垂直扩展能力**:支持功能模块的增量开发 +- **技术栈演进**:预留技术升级空间,避免技术债务 + +#### 1.1.3 快速开发 +- **开箱即用**:提供完整的基础设施配置(认证、数据库、缓存等) +- **代码生成器**:自动化生成CRUD、API文档等重复性代码 +- **开发工具链**:集成调试、测试、部署工具,提升开发效率 + +#### 1.1.4 业务复用 +- **领域模型抽象**:提取通用业务模式(用户管理、权限控制、支付流程) +- **最佳实践封装**:将行业最佳实践固化为可复用组件 +- **配置化驱动**:通过配置而非代码实现业务定制 + +#### 1.1.5 标准化 +- **代码规范**:统一的编码风格、目录结构、命名规范 +- **接口标准**:RESTful API、GraphQL等标准化接口设计 +- **数据标准**:统一的数据模型、验证规则、错误处理 + +#### 1.1.6 开发者体验 +- **文档完善**:详细的开发文档、API文档、最佳实践指南 +- **调试友好**:完善的日志系统、错误追踪、性能监控 +- **学习曲线**:渐进式学习路径,从简单到复杂 + +### 1.2 现代全栈架构特点 + +#### 1.2.1 技术栈整合 +``` +前端层:React/Next.js + TypeScript + Tailwind CSS + Shadcn UI +后端层:Node.js/Python/Java + ORM + API框架 +数据层:PostgreSQL/MySQL + Redis + MongoDB +基础设施:Docker + Kubernetes + CI/CD +``` + +#### 1.2.2 开发流程优化 +- **Monorepo架构**:统一管理多个项目,共享依赖和配置 +- **自动化测试**:单元测试、集成测试、E2E测试全覆盖 +- **持续集成**:自动化构建、测试、部署流程 + +#### 1.2.3 安全性保障 +- **认证授权**:OAuth2.0、JWT、RBAC权限控制 +- **数据安全**:加密存储、SQL注入防护、XSS防护 +- **合规性**:GDPR、数据隐私保护等合规要求 + +--- + +## 二、国内环境差异分析 + +### 2.1 云服务差异 + +| 维度 | 国外环境 | 国内环境 | 适配策略 | +|------|---------|---------|---------| +| **云服务商** | AWS、GCP、Azure | 阿里云、腾讯云、华为云 | 多云适配层设计 | +| **CDN服务** | Cloudflare、Fastly | 阿里云CDN、腾讯云CDN | 国内CDN优先策略 | +| **对象存储** | S3、GCS | OSS、COS、OBS | 统一存储接口抽象 | +| **域名解析** | Route53、CloudDNS | 阿里云DNS、DNSPod | 国内DNS服务集成 | +| **负载均衡** | ELB、Cloud Load Balancing | SLB、CLB | 负载均衡适配层 | + +### 2.2 认证体系差异 + +#### 2.2.1 身份认证 +- **国外**:Google OAuth、Facebook Login、Apple Sign In +- **国内**:微信登录、支付宝登录、手机号验证码登录 +- **适配方案**: + - 统一认证接口抽象层 + - 支持多种认证方式组合 + - 手机号作为主要身份标识 + +#### 2.2.2 实名认证 +- **国外**:SSN、护照验证(较少强制要求) +- **国内**:强制实名认证(身份证、人脸识别) +- **适配方案**: + - 集成第三方实名认证服务(阿里云、腾讯云) + - 人脸识别SDK集成 + - 身份证OCR识别 + +### 2.3 支付系统差异 + +#### 2.3.1 支付渠道 +| 国外支付 | 国内支付 | 特点 | +|---------|---------|------| +| Stripe | 微信支付 | 社交场景支付 | +| PayPal | 支付宝 | 电商场景支付 | +| Apple Pay | 银联支付 | 银行卡支付 | +| Google Pay | 云闪付 | NFC支付 | + +#### 2.3.2 适配策略 +- **支付网关抽象层**:统一支付接口,支持多渠道切换 +- **支付流程适配**: + - 国内:扫码支付、H5支付、小程序支付 + - 国外:信用卡支付、订阅支付 +- **退款流程**:国内退款流程更复杂,需要特殊处理 + +### 2.4 合规要求差异 + +#### 2.4.1 数据合规 +- **国外**:GDPR、CCPA、HIPAA +- **国内**: + - 《网络安全法》 + - 《数据安全法》 + - 《个人信息保护法》 + - ICP备案要求 + - 数据本地化存储要求 + +#### 2.4.2 内容合规 +- **内容审核**:敏感词过滤、图片审核、视频审核 +- **实名制要求**:用户发布内容需实名认证 +- **数据留存**:日志数据需留存6个月以上 + +#### 2.4.3 行业合规 +- **金融行业**:支付牌照、资金存管要求 +- **医疗行业**:医疗数据隐私保护 +- **教育行业**:未成年人保护要求 + +### 2.5 网络环境差异 + +#### 2.5.1 网络访问 +- **国外服务访问受限**:Google服务、GitHub、部分CDN +- **国内网络优化**: + - 多地域部署(华北、华东、华南) + - CDN加速优化 + - DNS智能解析 + +#### 2.5.2 适配策略 +- **镜像源使用**:npm、pip、Docker镜像使用国内源 +- **服务替代**: + - Google Maps → 高德地图/百度地图 + - Google Analytics → 百度统计/友盟 + - Firebase → 阿里云移动推送 + +### 2.6 开发工具差异 + +| 工具类型 | 国外工具 | 国内替代 | 说明 | +|---------|---------|---------|------| +| **代码托管** | GitHub | Gitee、Coding | 国内代码托管平台 | +| **CI/CD** | GitHub Actions | Jenkins、阿里云云效 | 国内CI/CD工具 | +| **监控告警** | Datadog、New Relic | 阿里云ARMS、腾讯云监控 | 国内监控服务 | +| **日志分析** | Splunk、ELK | 阿里云SLS、腾讯云CLS | 国内日志服务 | +| **文档协作** | Notion、Confluence | 语雀、飞书文档 | 国内协作工具 | + +--- + +## 三、FischerX架构设计方案 + +### 3.1 整体架构蓝图 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ FischerX 架构层次 │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ ┌───────────────────────────────────────────────────────┐ │ +│ │ 应用层 (Application Layer) │ │ +│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ +│ │ │ Web应用 │ │移动应用 │ │小程序 │ │管理后台 │ │ │ +│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ +│ └───────────────────────────────────────────────────────┘ │ +│ │ +│ ┌───────────────────────────────────────────────────────┐ │ +│ │ 业务层 (Business Layer) │ │ +│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ +│ │ │用户管理 │ │权限控制 │ │支付系统 │ │内容管理 │ │ │ +│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ +│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ +│ │ │订单系统 │ │消息通知 │ │文件存储 │ │数据分析 │ │ │ +│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ +│ └───────────────────────────────────────────────────────┘ │ +│ │ +│ ┌───────────────────────────────────────────────────────┐ │ +│ │ 服务层 (Service Layer) │ │ +│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ +│ │ │认证服务 │ │支付网关 │ │短信服务 │ │实名认证 │ │ │ +│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ +│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ +│ │ │地图服务 │ │AI服务 │ │监控服务 │ │日志服务 │ │ │ +│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ +│ └───────────────────────────────────────────────────────┘ │ +│ │ +│ ┌───────────────────────────────────────────────────────┐ │ +│ │ 数据层 (Data Layer) │ │ +│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ +│ │ │关系数据库│ │缓存系统 │ │消息队列 │ │搜索引擎 │ │ │ +│ │ │PostgreSQL│ │ Redis │ │RabbitMQ │ │Elastic │ │ │ +│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ +│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ +│ │ │对象存储 │ │文件存储 │ │时序数据库│ │ │ +│ │ │ OSS/COS │ │ NFS │ │InfluxDB │ │ │ +│ │ └─────────┘ └─────────┘ └─────────┘ │ │ +│ └───────────────────────────────────────────────────────┘ │ +│ │ +│ ┌───────────────────────────────────────────────────────┐ │ +│ │ 基础设施层 (Infrastructure Layer) │ │ +│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ +│ │ │容器编排 │ │负载均衡 │ │DNS服务 │ │CDN加速 │ │ │ +│ │ │K8s/Docker│ │ SLB/CLB │ │DNSPod │ │阿里CDN │ │ │ +│ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ +│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ +│ │ │CI/CD │ │监控告警 │ │日志收集 │ │ │ +│ │ │云效/Jenkins│ │ARMS │ │SLS │ │ │ +│ │ └─────────┘ └─────────┘ └─────────┘ │ │ +│ └───────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────┘ +``` + +### 3.2 技术栈选择 + +#### 3.2.1 前端技术栈 + +```yaml +核心框架: + - Next.js 14+ (React框架,支持SSR/SSG) + - TypeScript 5+ (类型安全) + - React 18+ (并发渲染、Suspense) + +UI组件库: + - Shadcn UI (基于Radix UI的组件库) + - Tailwind CSS 3+ (原子化CSS) + - Ant Design 5+ (企业级组件库,国内生态) + +状态管理: + - Zustand (轻量级状态管理) + - React Query (服务端状态管理) + - React Hook Form (表单管理) + +工具链: + - Vite (构建工具) + - ESLint + Prettier (代码规范) + - Vitest + Playwright (测试框架) +``` + +#### 3.2.2 后端技术栈 + +```yaml +核心框架: + - Node.js 20+ LTS + - NestJS (企业级Node.js框架) + - 或 Spring Boot 3+ (Java生态,企业级应用) + - 或 FastAPI (Python生态,AI应用) + +ORM框架: + - Prisma (Node.js ORM,类型安全) + - 或 MyBatis Plus (Java ORM) + - 或 SQLAlchemy (Python ORM) + +API设计: + - RESTful API (标准接口) + - GraphQL (灵活查询) + - tRPC (端到端类型安全) + +认证授权: + - Passport.js (Node.js认证中间件) + - 或 Spring Security (Java安全框架) + - JWT + RBAC权限控制 +``` + +#### 3.2.3 数据层技术栈 + +```yaml +关系数据库: + - PostgreSQL 15+ (主数据库,开源、功能强大) + - MySQL 8+ (备选方案,国内生态成熟) + +缓存系统: + - Redis 7+ (分布式缓存、会话存储) + - Memcached (简单缓存场景) + +消息队列: + - RabbitMQ (可靠消息传递) + - 或 Apache Kafka (高吞吐场景) + - 或 RocketMQ (阿里云生态) + +搜索引擎: + - Elasticsearch 8+ (全文搜索、日志分析) + - 或 Meilisearch (轻量级搜索) + +对象存储: + - 阿里云OSS (国内首选) + - 腾讯云COS (备选方案) + - MinIO (私有化部署) +``` + +#### 3.2.4 基础设施技术栈 + +```yaml +容器化: + - Docker (容器运行时) + - Kubernetes (容器编排) + - Helm (K8s包管理) + +CI/CD: + - 阿里云云效 (国内CI/CD平台) + - 或 Jenkins (开源CI/CD) + - GitLab CI (自托管方案) + +监控告警: + - 阿里云ARMS (应用实时监控) + - Prometheus + Grafana (开源监控) + - Sentry (错误追踪) + +日志系统: + - 阿里云SLS (日志服务) + - 或 ELK Stack (开源方案) +``` + +### 3.3 模块划分和层次结构 + +#### 3.3.1 核心模块清单 + +```yaml +基础模块: + 1. 用户管理模块 + - 用户注册/登录 + - 手机号验证码登录 + - 微信/支付宝登录 + - 实名认证 + - 用户信息管理 + + 2. 权限控制模块 + - RBAC权限模型 + - 角色管理 + - 权限分配 + - 资源访问控制 + + 3. 认证授权模块 + - JWT Token管理 + - Session管理 + - OAuth2.0集成 + - 多因素认证 + + 4. 文件存储模块 + - 对象存储集成 + - 文件上传/下载 + - 图片处理(压缩、裁剪、水印) + - CDN加速 + + 5. 消息通知模块 + - 短信通知(阿里云短信) + - 邿件通知 + - 推送通知(小程序、App) + - 站内消息 + +业务模块: + 1. 支付系统模块 + - 微信支付集成 + - 支付宝支付集成 + - 银联支付集成 + - 订单管理 + - 退款处理 + + 2. 内容管理模块 + - 内容发布 + - 内容审核(敏感词过滤) + - 评论管理 + - 标签分类 + + 3. 订单系统模块 + - 订单创建 + - 订单状态管理 + - 订单查询 + - 订单统计 + + 4. 数据分析模块 + - 用户行为分析 + - 业务数据统计 + - 数据可视化 + - 报表生成 + +服务模块: + 1. 第三方服务集成 + - 地图服务(高德地图) + - AI服务(百度AI、阿里AI) + - 实名认证服务 + - OCR识别服务 + + 2. 监控服务模块 + - 性能监控 + - 错误追踪 + - 用户行为追踪 + - 业务指标监控 + + 3. 日志服务模块 + - 日志收集 + - 日志分析 + - 日志查询 + - 日志告警 +``` + +#### 3.3.2 目录结构设计 + +``` +FischerX/ +├── apps/ # 应用层 +│ ├── web/ # Web应用 +│ │ ├── src/ +│ │ │ ├── app/ # Next.js App Router +│ │ │ ├── components/ # UI组件 +│ │ │ ├── hooks/ # React Hooks +│ │ │ ├── lib/ # 工具库 +│ │ │ └── styles/ # 样式文件 +│ │ └── public/ # 静态资源 +│ ├── admin/ # 管理后台 +│ ├── mobile/ # 移动应用(React Native) +│ └── miniapp/ # 小程序 +│ +├── packages/ # 共享包 +│ ├── core/ # 核心业务逻辑 +│ │ ├── auth/ # 认证授权 +│ │ ├── user/ # 用户管理 +│ │ ├── payment/ # 支付系统 +│ │ ├── permission/ # 权限控制 +│ │ └── notification/ # 消息通知 +│ ├── ui/ # 共享UI组件 +│ ├── utils/ # 工具函数 +│ ├── types/ # 类型定义 +│ ├── config/ # 配置管理 +│ └── constants/ # 常量定义 +│ +├── services/ # 后端服务 +│ ├── api/ # API服务 +│ │ ├── src/ +│ │ │ ├── controllers/ # 控制器 +│ │ │ ├── services/ # 业务逻辑 +│ │ │ ├── models/ # 数据模型 +│ │ │ ├── middleware/ # 中间件 +│ │ │ ├── routes/ # 路由定义 +│ │ │ └── utils/ # 工具函数 +│ │ └── prisma/ # Prisma Schema +│ ├── worker/ # 后台任务服务 +│ └── realtime/ # 实时通信服务 +│ +├── infra/ # 基础设施 +│ ├── docker/ # Docker配置 +│ ├── k8s/ # Kubernetes配置 +│ ├── terraform/ # 云资源编排 +│ └── scripts/ # 部署脚本 +│ +├── docs/ # 文档 +│ ├── architecture/ # 架构文档 +│ ├── api/ # API文档 +│ ├── development/ # 开发指南 +│ └── deployment/ # 部署指南 +│ +├── tools/ # 开发工具 +│ ├── cli/ # CLI工具 +│ ├── generators/ # 代码生成器 +│ └── testing/ # 测试工具 +│ +├── .github/ # GitHub配置(或Gitee) +│ ├── workflows/ # CI/CD工作流 +│ └── ISSUE_TEMPLATE/ # Issue模板 +│ +├── package.json # Monorepo配置 +├── turbo.json # Turborepo配置 +├── pnpm-workspace.yaml # pnpm工作空间 +└── README.md # 项目说明 +``` + +### 3.4 国内环境适配方案 + +#### 3.4.1 认证适配方案 + +```typescript +interface AuthAdapter { + wechatLogin(): Promise; + alipayLogin(): Promise; + phoneLogin(phone: string, code: string): Promise; + realNameVerify(idCard: string, name: string): Promise; +} + +class ChinaAuthProvider implements AuthAdapter { + async wechatLogin() { + const wechatService = new WeChatService(); + const userInfo = await wechatService.getUserInfo(); + return this.createSession(userInfo); + } + + async phoneLogin(phone: string, code: string) { + const smsService = new AliyunSMSService(); + const verified = await smsService.verifyCode(phone, code); + if (verified) { + return this.createSession({ phone }); + } + throw new Error('验证码错误'); + } + + async realNameVerify(idCard: string, name: string) { + const verifyService = new AliyunRealNameService(); + return verifyService.verify(idCard, name); + } +} +``` + +#### 3.4.2 支付适配方案 + +```typescript +interface PaymentGateway { + createOrder(order: Order): Promise; + queryOrder(orderId: string): Promise; + refund(orderId: string, amount: number): Promise; +} + +class WeChatPaymentGateway implements PaymentGateway { + async createOrder(order: Order) { + const wechatPay = new WeChatPaySDK({ + appId: process.env.WECHAT_APP_ID, + mchId: process.env.WECHAT_MCH_ID, + }); + + const result = await wechatPay.createOrder({ + body: order.description, + outTradeNo: order.id, + totalFee: order.amount, + notifyUrl: process.env.WECHAT_NOTIFY_URL, + }); + + return { + codeUrl: result.code_url, + orderId: order.id, + }; + } +} + +class AlipayPaymentGateway implements PaymentGateway { + async createOrder(order: Order) { + const alipay = new AlipaySDK({ + appId: process.env.ALIPAY_APP_ID, + privateKey: process.env.ALIPAY_PRIVATE_KEY, + }); + + const result = await alipay.createOrder({ + subject: order.description, + outTradeNo: order.id, + totalAmount: order.amount, + }); + + return { + payUrl: result.pay_url, + orderId: order.id, + }; + } +} + +class PaymentGatewayFactory { + static create(type: 'wechat' | 'alipay' | 'unionpay'): PaymentGateway { + switch (type) { + case 'wechat': + return new WeChatPaymentGateway(); + case 'alipay': + return new AlipayPaymentGateway(); + case 'unionpay': + return new UnionPayGateway(); + } + } +} +``` + +#### 3.4.3 云服务适配方案 + +```typescript +interface CloudStorageAdapter { + upload(file: File, options?: UploadOptions): Promise; + download(url: string): Promise; + delete(url: string): Promise; +} + +class AliyunOSSAdapter implements CloudStorageAdapter { + private ossClient: OSS; + + constructor() { + this.ossClient = new OSS({ + region: process.env.OSS_REGION, + bucket: process.env.OSS_BUCKET, + accessKeyId: process.env.OSS_ACCESS_KEY_ID, + accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET, + }); + } + + async upload(file: File, options?: UploadOptions) { + const fileName = this.generateFileName(file.name); + const result = await this.ossClient.put(fileName, file); + + return { + url: result.url, + name: fileName, + }; + } +} + +class TencentCOSAdapter implements CloudStorageAdapter { + private cosClient: COS; + + constructor() { + this.cosClient = new COS({ + SecretId: process.env.COS_SECRET_ID, + SecretKey: process.env.COS_SECRET_KEY, + }); + } + + async upload(file: File, options?: UploadOptions) { + const fileName = this.generateFileName(file.name); + const result = await this.cosClient.putObject({ + Bucket: process.env.COS_BUCKET, + Region: process.env.COS_REGION, + Key: fileName, + Body: file, + }); + + return { + url: `https://${process.env.COS_BUCKET}.cos.${process.env.COS_REGION}.myqcloud.com/${fileName}`, + name: fileName, + }; + } +} + +class CloudStorageFactory { + static create(type: 'aliyun' | 'tencent' | 'minio'): CloudStorageAdapter { + switch (type) { + case 'aliyun': + return new AliyunOSSAdapter(); + case 'tencent': + return new TencentCOSAdapter(); + case 'minio': + return new MinIOAdapter(); + } + } +} +``` + +#### 3.4.4 内容审核适配方案 + +```typescript +interface ContentReviewAdapter { + textReview(text: string): Promise; + imageReview(imageUrl: string): Promise; + videoReview(videoUrl: string): Promise; +} + +class AliyunContentReviewAdapter implements ContentReviewAdapter { + async textReview(text: string) { + const greenService = new AliyunGreenService(); + const result = await greenService.textScan(text); + + return { + passed: result.passed, + reason: result.reason, + labels: result.labels, + }; + } + + async imageReview(imageUrl: string) { + const greenService = new AliyunGreenService(); + const result = await greenService.imageScan(imageUrl); + + return { + passed: result.passed, + reason: result.reason, + labels: result.labels, + }; + } +} +``` + +--- + +## 四、技术选型建议 + +### 4.1 推荐技术栈组合 + +#### 4.1.1 Node.js全栈方案(推荐) + +```yaml +适用场景: + - 快速迭代的项目 + - 中小型团队 + - 前端团队主导 + +技术栈: + 前端: Next.js + TypeScript + Tailwind CSS + Shadcn UI + 后端: NestJS + Prisma + PostgreSQL + 缓存: Redis + 消息队列: RabbitMQ + 存储: 阿里云OSS + 部署: Docker + Kubernetes + 阿里云ACK + +优势: + - 前后端技术栈统一,降低学习成本 + - TypeScript全栈类型安全 + - 开发效率高,迭代速度快 + - 社区活跃,生态丰富 + +劣势: + - 大规模并发性能不如Java + - 企业级生态不如Java成熟 +``` + +#### 4.1.2 Java企业级方案 + +```yaml +适用场景: + - 大型企业应用 + - 高并发、高可用场景 + - 金融、政务等行业 + +技术栈: + 前端: Next.js + TypeScript + Ant Design + 后端: Spring Boot 3 + MyBatis Plus + PostgreSQL + 缓存: Redis + Spring Cache + 消息队列: RocketMQ + 存储: 阿里云OSS + 部署: Docker + Kubernetes + 阿里云ACK + +优势: + - 企业级生态成熟 + - 高并发性能优秀 + - 安全性、稳定性强 + - 国内人才储备丰富 + +劣势: + - 开发效率相对较低 + - 学习曲线陡峭 + - 前后端技术栈分离 +``` + +#### 4.1.3 Python AI方案 + +```yaml +适用场景: + - AI应用、数据分析 + - 快速原型开发 + - 算法密集型应用 + +技术栈: + 前端: Next.js + TypeScript + Tailwind CSS + 后端: FastAPI + SQLAlchemy + PostgreSQL + AI服务: 百度AI、阿里AI、腾讯AI + 缓存: Redis + 存储: 阿里云OSS + 部署: Docker + Kubernetes + +优势: + - AI生态丰富 + - 开发效率高 + - 数据处理能力强 + - 适合快速原型 + +劣势: + - 高并发性能不如Java + - 企业级生态不如Java成熟 +``` + +### 4.2 关键决策说明 + +#### 4.2.1 为什么选择Next.js? + +1. **SSR/SSG支持**:提升SEO和首屏加载速度 +2. **App Router**:现代化的路由架构 +3. **API Routes**:前后端一体化开发 +4. **国内生态**:Ant Design、国内CDN支持良好 +5. **TypeScript支持**:类型安全开发 + +#### 4.2.2 为什么选择PostgreSQL? + +1. **开源免费**:降低成本 +2. **功能强大**:JSON支持、全文搜索、地理信息 +3. **性能优秀**:复杂查询性能好 +4. **国内生态**:阿里云RDS PostgreSQL支持良好 +5. **扩展性强**:丰富的扩展插件 + +#### 4.2.3 为什么选择阿里云? + +1. **国内市场份额第一**:生态成熟 +2. **产品线完整**:计算、存储、网络、安全全覆盖 +3. **合规性强**:满足国内合规要求 +4. **技术支持**:国内技术支持响应快 +5. **成本优势**:相比AWS在国内成本更低 + +#### 4.2.4 为什么选择Monorepo? + +1. **代码共享**:前后端共享类型定义、工具函数 +2. **依赖管理**:统一管理依赖版本 +3. **构建优化**:Turborepo增量构建 +4. **团队协作**:统一代码规范、CI/CD流程 +5. **重构便利**:跨项目重构更容易 + +--- + +## 五、实施路线图建议 + +### 5.1 分阶段实施计划 + +#### 第一阶段:基础架构搭建(1-2个月) + +```yaml +目标: 搭建基础开发框架和核心模块 + +任务清单: + 1. 项目初始化 + - Monorepo架构搭建 + - 开发环境配置 + - CI/CD流程配置 + + 2. 基础模块开发 + - 用户管理模块 + - 认证授权模块 + - 权限控制模块 + - 文件存储模块 + + 3. 基础设施搭建 + - Docker容器化 + - Kubernetes集群搭建 + - 阿里云资源配置 + + 4. 文档编写 + - 架构设计文档 + - 开发指南文档 + - API文档 + +交付物: + - 可运行的基础框架 + - 核心认证授权功能 + - 基础设施配置 + - 完整的开发文档 +``` + +#### 第二阶段:业务模块开发(2-3个月) + +```yaml +目标: 开发核心业务模块和第三方服务集成 + +任务清单: + 1. 业务模块开发 + - 支付系统模块(微信支付、支付宝) + - 内容管理模块 + - 订单系统模块 + - 消息通知模块 + + 2. 第三方服务集成 + - 短信服务集成(阿里云短信) + - 实名认证服务集成 + - 地图服务集成(高德地图) + - 内容审核服务集成 + + 3. 监控告警系统 + - 性能监控配置 + - 错误追踪配置 + - 业务指标监控 + - 告警规则配置 + + 4. 测试完善 + - 单元测试覆盖 + - 集成测试覆盖 + - E2E测试覆盖 + +交付物: + - 完整的业务模块 + - 第三方服务集成 + - 监控告警系统 + - 测试覆盖率>80% +``` + +#### 第三阶段:优化和上线(1-2个月) + +```yaml +目标: 性能优化、安全加固、生产环境部署 + +任务清单: + 1. 性能优化 + - 前端性能优化(代码分割、懒加载) + - 后端性能优化(缓存、数据库优化) + - CDN加速配置 + - 负载均衡配置 + + 2. 安全加固 + - 安全审计 + - 漏洞修复 + - 数据加密 + - 合规性检查 + + 3. 生产环境部署 + - 生产环境配置 + - 数据迁移 + - 灰度发布 + - 全量上线 + + 4. 运维体系建立 + - 监控告警完善 + - 日志分析系统 + - 故障响应流程 + - 备份恢复机制 + +交付物: + - 生产环境上线 + - 性能达标 + - 安全合规 + - 运维体系完善 +``` + +### 5.2 团队配置建议 + +```yaml +核心团队配置: + - 技术负责人: 1人(架构设计、技术决策) + - 前端开发: 2-3人(Web应用、管理后台) + - 后端开发: 2-3人(API服务、业务逻辑) + - DevOps工程师: 1人(基础设施、CI/CD) + - 测试工程师: 1人(测试自动化、质量保障) + +扩展团队配置(可选): + - 移动端开发: 1-2人(React Native、小程序) + - UI设计师: 1人(界面设计、交互设计) + - 产品经理: 1人(需求分析、产品规划) +``` + +### 5.3 成本估算 + +```yaml +人力成本(按阶段): + 第一阶段: 5人 × 2个月 = 10人月 + 第二阶段: 5人 × 3个月 = 15人月 + 第三阶段: 5人 × 2个月 = 10人月 + 总计: 35人月 + +云服务成本(月度): + - ECS服务器: 2核4G × 3台 = ¥600/月 + - RDS PostgreSQL: 2核4G = ¥400/月 + - Redis: 1G = ¥200/月 + - OSS存储: 100G = ¥50/月 + - CDN流量: 100G = ¥100/月 + - 其他服务: ¥200/月 + 总计: ¥1550/月(开发环境) + +生产环境成本(月度): + - ECS服务器: 4核8G × 5台 = ¥2000/月 + - RDS PostgreSQL: 4核8G = ¥1200/月 + - Redis: 4G = ¥600/月 + - OSS存储: 500G = ¥250/月 + - CDN流量: 500G = ¥500/月 + - 其他服务: ¥500/月 + 总计: ¥5050/月(生产环境) +``` + +### 5.4 风险和应对策略 + +```yaml +技术风险: + 1. 技术栈选择风险 + - 应对: 技术预研、原型验证、技术评审 + + 2. 性能风险 + - 应对: 性能测试、压力测试、性能监控 + + 3. 安全风险 + - 应对: 安全审计、漏洞扫描、安全培训 + +业务风险: + 1. 需求变更风险 + - 应对: 需求评审、迭代开发、敏捷响应 + + 2. 第三方服务依赖风险 + - 应对: 服务降级方案、多服务商备份 + + 3. 合规性风险 + - 应对: 合规咨询、合规审计、合规培训 + +团队风险: + 1. 人员流动风险 + - 应对: 文档完善、知识共享、代码规范 + + 2. 技能不足风险 + - 应对: 技术培训、代码评审、结对编程 + + 3. 协作效率风险 + - 应对: 流程规范、工具支持、定期沟通 +``` + +--- + +## 六、总结 + +FischerX架构设计方案基于现代全栈开发底座的最佳实践,充分考虑了国内环境的特殊性,提供了: + +1. **完整的架构蓝图**:从应用层到基础设施层的完整设计 +2. **灵活的技术选型**:提供Node.js、Java、Python三种方案 +3. **国内环境适配**:认证、支付、云服务、合规性全面适配 +4. **清晰的实施路线**:分阶段实施计划、团队配置、成本估算 +5. **风险应对策略**:技术、业务、团队风险的应对方案 + +该架构方案具有以下特点: + +- **模块化设计**:清晰的模块划分,支持独立开发和部署 +- **可扩展性**:支持从单体应用平滑过渡到微服务架构 +- **快速开发**:开箱即用的基础设施,降低开发成本 +- **业务复用**:核心业务模块可复用,提升开发效率 +- **国内适配**:全面适配国内云服务、认证体系、支付系统、合规要求 + +建议根据实际项目需求和团队技能选择合适的技术栈组合,按照分阶段实施计划逐步推进,确保项目成功落地。 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..3c42a08 --- /dev/null +++ b/README.md @@ -0,0 +1,299 @@ +# FischerX + +Fischer公司开发底座 — 适配国内运行环境的全栈Monorepo项目,理念对标John Rush的Mars Stack/Mars Foundation。 + +## 技术栈 + +### 前端 +- **框架**: Next.js 14+ (App Router) +- **语言**: TypeScript (严格模式) +- **样式**: Tailwind CSS +- **UI组件**: Shadcn UI +- **状态管理**: Zustand + React Query +- **表单**: React Hook Form + Zod +- **测试**: Vitest + Playwright + +### 后端 +- **框架**: NestJS +- **ORM**: Prisma +- **数据库**: PostgreSQL +- **缓存**: Redis +- **认证**: JWT + Passport +- **测试**: Jest + +### 基础设施 +- **容器化**: Docker + Docker Compose +- **编排**: Kubernetes (阿里云ACK) +- **IaC**: Terraform +- **CI/CD**: GitHub Actions +- **监控**: Prometheus + Grafana + Loki + Jaeger + +### 工具链 +- **包管理**: pnpm +- **构建系统**: Turborepo +- **代码规范**: ESLint + Prettier +- **CLI工具**: @fischerx/cli + +## 核心模块 + +| 模块 | 说明 | 状态 | +|------|------|------| +| 用户管理 | 用户CRUD、头像上传 | ✅ 完成 | +| 认证授权 | JWT、Session、手机号登录、微信/支付宝OAuth、实名认证、MFA | ✅ 完成 | +| 权限控制 | RBAC模型、角色管理、权限分配、装饰器守卫 | ✅ 完成 | +| 文件存储 | 阿里云OSS、腾讯云COS、MinIO、图片处理、CDN | ✅ 完成 | +| 支付系统 | 支付宝、微信支付、银联适配器、退款、对账 | ✅ 完成 | +| 消息通知 | 邮件、短信、推送、站内信(适配器模式) | ✅ 完成 | +| 内容管理 | 文章、分类、标签、评论、版本控制 | ✅ 后端完成 | +| 监控告警 | Prometheus + Grafana + AlertManager + Loki + Jaeger | ✅ 完成 | +| CLI工具 | 项目初始化、代码生成、部署命令 | ✅ 完成 | + +## 快速开始 + +### 环境要求 +- Node.js >= 18.0.0 +- pnpm >= 8.0.0 +- Docker & Docker Compose +- PostgreSQL 15+ +- Redis 7+ + +### 安装 + +```bash +# 克隆项目 +git clone http://8.153.107.96/fischer/fischerX.git +cd fischerX + +# 安装依赖 +pnpm install +``` + +### 本地开发 + +```bash +# 1. 启动基础设施(PostgreSQL + Redis) +docker-compose up -d postgres redis + +# 2. 配置环境变量 +cp services/api/.env.example services/api/.env +# 编辑 .env 填入数据库连接、Redis连接、JWT密钥等 + +# 3. 运行数据库迁移 +cd services/api +npx prisma migrate dev +cd ../.. + +# 4. 启动后端API服务 +cd services/api +pnpm start:dev + +# 5. 启动前端Web应用 +cd apps/web +pnpm dev +``` + +### 访问地址 + +| 服务 | 地址 | +|------|------| +| 前端Web | http://localhost:3000 | +| 后端API | http://localhost:3001/api/v1/health | +| Grafana | http://localhost:3001 (admin/fischerx123) | +| Prometheus | http://localhost:9090 | +| Jaeger | http://localhost:16686 | + +## 项目结构 + +``` +FischerX/ +├── apps/ # 应用层 +│ ├── web/ # Web应用 (Next.js) +│ └── admin/ # 管理后台 (占位) +├── packages/ # 共享包 +│ ├── core/ # 核心业务逻辑 (@fischerx/core) +│ ├── ui/ # 共享UI组件 (@fischerx/ui) +│ ├── utils/ # 工具函数 (@fischerx/utils) +│ ├── types/ # 类型定义 (@fischerx/types) +│ ├── config/ # 配置管理 (@fischerx/config) +│ └── constants/ # 常量定义 (@fischerx/constants) +├── services/ # 后端服务 +│ └── api/ # API服务 (NestJS) +│ ├── prisma/ # 数据库Schema +│ └── src/modules/ # 业务模块 +│ ├── auth/ # 认证授权 +│ ├── rbac/ # 权限控制 +│ ├── user/ # 用户管理 +│ ├── file/ # 文件存储 +│ ├── payment/ # 支付系统 +│ ├── notification/ # 消息通知 +│ ├── content/ # 内容管理 +│ ├── health/ # 健康检查 +│ ├── cache/ # 缓存服务 +│ └── monitoring/ # 监控集成 +├── infra/ # 基础设施 +│ ├── db/ # 数据库Docker配置 +│ ├── k8s/ # Kubernetes配置 +│ ├── monitoring/ # 监控栈 (Prometheus/Grafana/Loki/Jaeger) +│ ├── terraform/ # 阿里云资源管理 +│ └── envs/ # 多环境配置 (dev/test/prod) +├── tools/ # 开发工具 +│ └── cli/ # CLI工具 (@fischerx/cli) +├── docs/ # 文档 +│ ├── architecture/ # 架构文档 +│ ├── requirements/ # 需求文档 +│ ├── design/ # 设计文档 +│ ├── development/ # 开发文档 +│ ├── api/ # API文档 +│ ├── testing/ # 测试文档 +│ ├── deployment/ # 部署文档 +│ ├── operations/ # 运维文档 +│ ├── user/ # 用户文档 +│ └── templates/ # 文档模板 +├── .github/workflows/ # CI/CD (8个Workflow) +├── docker-compose.yml # Docker Compose +├── turbo.json # Turborepo配置 +├── pnpm-workspace.yaml # pnpm工作空间 +└── package.json # 根package.json +``` + +## API端点 + +### 认证授权 +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | /api/v1/auth/register | 用户注册 | +| POST | /api/v1/auth/login | 密码登录 | +| POST | /api/v1/auth/sms/send | 发送验证码 | +| POST | /api/v1/auth/sms/login | 验证码登录 | +| POST | /api/v1/auth/wechat/login | 微信OAuth登录 | +| POST | /api/v1/auth/alipay/login | 支付宝OAuth登录 | +| POST | /api/v1/auth/realname/verify | 实名认证 | +| POST | /api/v1/auth/mfa/enable | 启用MFA | +| POST | /api/v1/auth/mfa/verify | 验证MFA | + +### 用户管理 +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | /api/v1/users/me | 当前用户信息 | +| PUT | /api/v1/users/me | 更新用户信息 | +| POST | /api/v1/users/me/avatar | 上传头像 | +| GET | /api/v1/users | 用户列表 (管理员) | + +### 权限控制 +| 方法 | 路径 | 说明 | +|------|------|------| +| CRUD | /api/v1/roles | 角色管理 | +| CRUD | /api/v1/permissions | 权限管理 | +| POST | /api/v1/roles/:id/permissions | 分配权限 | +| POST | /api/v1/users/:id/roles | 分配角色 | + +### 支付系统 +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | /api/v1/payment/orders | 创建支付订单 | +| GET | /api/v1/payment/orders/:id | 查询订单 | +| POST | /api/v1/payment/refunds | 申请退款 | +| POST | /api/v1/payment/callback/:channel | 支付回调 | + +### 文件存储 +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | /api/v1/files/upload | 上传文件 | +| GET | /api/v1/files | 文件列表 | +| GET | /api/v1/files/:id | 文件详情 | +| DELETE | /api/v1/files/:id | 删除文件 | + +### 消息通知 +| 方法 | 路径 | 说明 | +|------|------|------| +| POST | /api/v1/notifications | 发送通知 | +| GET | /api/v1/notifications | 通知列表 | +| PUT | /api/v1/notifications/:id/read | 标记已读 | + +## 底座使用方式 + +### 方式一:Monorepo模式(推荐) +在FischerX Monorepo中创建新应用,自动继承共享包: +```bash +fischerx create-app my-crm --type=admin +``` + +### 方式二:独立项目模式 +从FischerX模板创建独立项目: +```bash +fischerx init client-project --template=standalone +``` + +### 方式三:API服务模式 +部署FischerX作为共享服务,通过API调用底座功能。 + +## CLI工具 + +```bash +# 安装 +cd tools/cli && pnpm install && pnpm build + +# 项目管理 +fischerx init # 初始化新项目 +fischerx create-app # 创建新应用 +fischerx create-package # 创建新共享包 + +# 代码生成 +fischerx generate page # 生成页面 +fischerx generate component # 生成组件 +fischerx generate api # 生成API +fischerx generate module # 生成完整模块 + +# 部署 +fischerx deploy --env dev # 部署到开发环境 +fischerx deploy --env prod # 部署到生产环境 + +# 其他 +fischerx doctor # 检查项目健康 +fischerx info # 显示项目信息 +``` + +## 国内环境适配 + +| 维度 | 适配方案 | +|------|---------| +| 云服务 | 阿里云(首选)、腾讯云(备选)、华为云(备选) | +| 认证 | 手机号验证码、微信OAuth、支付宝OAuth、实名认证 | +| 支付 | 微信支付、支付宝、银联 | +| 存储 | 阿里云OSS、腾讯云COS、MinIO私有化 | +| 短信 | 阿里云短信 | +| 邮件 | SMTP / 阿里云邮件 | +| 监控 | Prometheus + Grafana / 阿里云ARMS | +| 日志 | Loki / 阿里云SLS | +| 部署 | 阿里云ACK / 自建K8s | +| CDN | 阿里云CDN | + +## 可用脚本 + +| 脚本 | 说明 | +|------|------| +| `pnpm install` | 安装所有依赖 | +| `pnpm build` | 构建所有包和应用 | +| `pnpm dev` | 启动开发服务器 | +| `pnpm lint` | 运行ESLint检查 | +| `pnpm test` | 运行所有测试 | +| `pnpm format` | 使用Prettier格式化代码 | + +## 待完善功能 + +| 优先级 | 功能 | 说明 | +|--------|------|------| +| P0 | 订单系统模块 | 独立Order模块,订单状态机 | +| P0 | 企业微信通知 | WeComChannelService适配器 | +| P0 | 邮件真实发送 | 集成Nodemailer/阿里云邮件 | +| P0 | 短信真实发送 | 集成阿里云短信SDK | +| P1 | 用户管理前端页面 | 用户列表/编辑/删除 | +| P1 | 通知中心前端页面 | 通知列表/设置 | +| P1 | 订单前端页面 | 订单列表/详情 | +| P2 | 支付真实SDK集成 | 支付宝/微信支付真实SDK | +| P2 | 内容审核 | 阿里云绿网内容安全 | +| P2 | @fischerx/client-sdk | 客户端SDK包 | + +## License + +Private - Fischer Company diff --git a/apps/admin/.gitkeep b/apps/admin/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/apps/web/.gitignore b/apps/web/.gitignore new file mode 100644 index 0000000..5ef6a52 --- /dev/null +++ b/apps/web/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile new file mode 100644 index 0000000..f92cac2 --- /dev/null +++ b/apps/web/Dockerfile @@ -0,0 +1,26 @@ +FROM node:20-alpine AS base + +FROM base AS deps +RUN apk add --no-cache libc6-compat +WORKDIR /app +COPY package.json pnpm-lock.yaml* ./ +RUN npm install -g pnpm@8.15.0 && pnpm install --frozen-lockfile + +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . +RUN npm install -g pnpm@8.15.0 && pnpm build + +FROM base AS runner +WORKDIR /app +ENV NODE_ENV production +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs +COPY --from=builder /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static +USER nextjs +EXPOSE 3000 +ENV PORT 3000 +CMD ["node", "server.js"] diff --git a/apps/web/README.md b/apps/web/README.md new file mode 100644 index 0000000..e215bc4 --- /dev/null +++ b/apps/web/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/apps/web/components.json b/apps/web/components.json new file mode 100644 index 0000000..556d973 --- /dev/null +++ b/apps/web/components.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "src/app/globals.css", + "baseColor": "slate", + "cssVariables": true + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils" + } +} diff --git a/apps/web/e2e/home.spec.ts b/apps/web/e2e/home.spec.ts new file mode 100644 index 0000000..1c7aca8 --- /dev/null +++ b/apps/web/e2e/home.spec.ts @@ -0,0 +1,13 @@ +import { test, expect } from '@playwright/test' + +test.describe('Home Page', () => { + test('should load the home page', async ({ page }) => { + await page.goto('/') + await expect(page).toHaveTitle(/FischerX/) + }) + + test('should display navigation', async ({ page }) => { + await page.goto('/') + await expect(page.getByRole('navigation')).toBeVisible() + }) +}) diff --git a/apps/web/eslint.config.mjs b/apps/web/eslint.config.mjs new file mode 100644 index 0000000..05e726d --- /dev/null +++ b/apps/web/eslint.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig, globalIgnores } from "eslint/config"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; + +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ]), +]); + +export default eslintConfig; diff --git a/apps/web/next.config.ts b/apps/web/next.config.ts new file mode 100644 index 0000000..68a6c64 --- /dev/null +++ b/apps/web/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + output: "standalone", +}; + +export default nextConfig; diff --git a/apps/web/package.json b/apps/web/package.json new file mode 100644 index 0000000..9dca1ab --- /dev/null +++ b/apps/web/package.json @@ -0,0 +1,56 @@ +{ + "name": "web", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "eslint", + "test": "vitest", + "test:ui": "vitest --ui", + "test:e2e": "playwright test", + "test:e2e:ui": "playwright test --ui" + }, + "dependencies": { + "@hookform/resolvers": "^5.4.0", + "@radix-ui/react-slot": "^1.2.4", + "@tanstack/react-query": "^5.100.13", + "@sentry/nextjs": "^8.0.0", + "@opentelemetry/api": "^1.8.0", + "@opentelemetry/sdk-trace-web": "^1.21.0", + "@opentelemetry/context-zone": "^1.21.0", + "@opentelemetry/instrumentation-fetch": "^0.48.0", + "@opentelemetry/instrumentation-xml-http-request": "^0.48.0", + "axios": "^1.16.1", + "web-vitals": "^4.0.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^1.16.0", + "next": "16.2.6", + "react": "18.0.0", + "react-dom": "18.0.0", + "react-hook-form": "^7.76.1", + "tailwind-merge": "^3.6.0", + "tailwindcss-animate": "^1.0.7", + "zod": "^4.4.3", + "zustand": "^5.0.13" + }, + "devDependencies": { + "@playwright/test": "^1.60.0", + "@tailwindcss/postcss": "^4", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@types/node": "^20", + "@types/react": "^18.3.29", + "@types/react-dom": "^18.3.7", + "@vitejs/plugin-react": "^4.0.0", + "eslint": "^9", + "eslint-config-next": "16.2.6", + "jsdom": "^29.1.1", + "tailwindcss": "^4", + "typescript": "^5", + "vite": "^8.0.14", + "vitest": "^4.1.7" + } +} diff --git a/apps/web/playwright.config.ts b/apps/web/playwright.config.ts new file mode 100644 index 0000000..530d57e --- /dev/null +++ b/apps/web/playwright.config.ts @@ -0,0 +1,33 @@ +import { defineConfig, devices } from '@playwright/test' + +export default defineConfig({ + testDir: './e2e', + fullyParallel: true, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 1 : undefined, + reporter: 'html', + use: { + baseURL: 'http://localhost:3000', + trace: 'on-first-retry', + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + ], + webServer: { + command: 'pnpm dev', + url: 'http://localhost:3000', + reuseExistingServer: !process.env.CI, + }, +}) diff --git a/apps/web/pnpm-lock.yaml b/apps/web/pnpm-lock.yaml new file mode 100644 index 0000000..dd43c06 --- /dev/null +++ b/apps/web/pnpm-lock.yaml @@ -0,0 +1,5718 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@hookform/resolvers': + specifier: ^5.4.0 + version: 5.4.0(react-hook-form@7.76.1(react@18.0.0)) + '@radix-ui/react-slot': + specifier: ^1.2.4 + version: 1.2.4(@types/react@18.3.29)(react@18.0.0) + '@tanstack/react-query': + specifier: ^5.100.13 + version: 5.100.13(react@18.0.0) + axios: + specifier: ^1.16.1 + version: 1.16.1 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + lucide-react: + specifier: ^1.16.0 + version: 1.16.0(react@18.0.0) + next: + specifier: 16.2.6 + version: 16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@18.0.0(react@18.0.0))(react@18.0.0) + react: + specifier: 18.0.0 + version: 18.0.0 + react-dom: + specifier: 18.0.0 + version: 18.0.0(react@18.0.0) + react-hook-form: + specifier: ^7.76.1 + version: 7.76.1(react@18.0.0) + tailwind-merge: + specifier: ^3.6.0 + version: 3.6.0 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@4.3.0) + zod: + specifier: ^4.4.3 + version: 4.4.3 + zustand: + specifier: ^5.0.13 + version: 5.0.13(@types/react@18.3.29)(react@18.0.0) + devDependencies: + '@playwright/test': + specifier: ^1.60.0 + version: 1.60.0 + '@tailwindcss/postcss': + specifier: ^4 + version: 4.3.0 + '@testing-library/jest-dom': + specifier: ^6.9.1 + version: 6.9.1 + '@testing-library/react': + specifier: ^16.3.2 + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@18.0.0(react@18.0.0))(react@18.0.0) + '@types/node': + specifier: ^20 + version: 20.19.41 + '@types/react': + specifier: ^18.3.29 + version: 18.3.29 + '@types/react-dom': + specifier: ^18.3.7 + version: 18.3.7(@types/react@18.3.29) + '@vitejs/plugin-react': + specifier: ^4.0.0 + version: 4.0.0(vite@8.0.14(@types/node@20.19.41)(jiti@2.7.0)) + eslint: + specifier: ^9 + version: 9.39.4(jiti@2.7.0) + eslint-config-next: + specifier: 16.2.6 + version: 16.2.6(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2))(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2) + jsdom: + specifier: ^29.1.1 + version: 29.1.1 + tailwindcss: + specifier: ^4 + version: 4.3.0 + typescript: + specifier: ^5 + version: 5.0.2 + vite: + specifier: ^8.0.14 + version: 8.0.14(@types/node@20.19.41)(jiti@2.7.0) + vitest: + specifier: ^4.1.7 + version: 4.1.7(@types/node@20.19.41)(jsdom@29.1.1)(vite@8.0.14(@types/node@20.19.41)(jiti@2.7.0)) + +packages: + + '@adobe/css-tools@4.5.0': + resolution: {integrity: sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==} + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@asamuzakjp/css-color@5.1.11': + resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/dom-selector@7.1.1': + resolution: {integrity: sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/generational-cache@1.0.1': + resolution: {integrity: sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/nwsapi@2.3.9': + resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.3': + resolution: {integrity: sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.2': + resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.3': + resolution: {integrity: sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@bramus/specificity@2.4.2': + resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} + hasBin: true + + '@csstools/color-helpers@6.0.2': + resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} + engines: {node: '>=20.19.0'} + + '@csstools/css-calc@3.2.1': + resolution: {integrity: sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-color-parser@4.1.1': + resolution: {integrity: sha512-eZ5XOtyhK+mggRafYUWzA0tvaYOFgdY8AkgQiCJF9qNAePnUo/zmsqqYubBBb3sQ8uNUaSKTY9s9klfRaAXL0g==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.4': + resolution: {integrity: sha512-wgsqt92b7C7tQhIdPNxj0n9zuUbQlvAuI1exyzeNrOKOi62SD7ren8zqszmpVREjAOqg8cD2FqYhQfAuKjk4sw==} + peerDependencies: + css-tree: ^3.2.1 + peerDependenciesMeta: + css-tree: + optional: true + + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} + + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.4': + resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@exodus/bytes@1.15.1': + resolution: {integrity: sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true + + '@hookform/resolvers@5.4.0': + resolution: {integrity: sha512-EIsqr/t/qbinPIhGjMdtvutIN1Kk4uwbROE9/UQ93CAVGR7GkA7Y92+fX80OzXi/OB67jVFYwKGO1WzkxmkFZw==} + peerDependencies: + react-hook-form: ^7.55.0 + + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@jest/types@27.0.2': + resolution: {integrity: sha512-XpjCtJ/99HB4PmyJ2vgmN7vT+JLP7RW1FBT9RgnMFS4Dt7cvIyBee8O3/j98aUZ34ZpenPZFqmaaObWSeL65dg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + '@jridgewell/gen-mapping@0.3.12': + resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} + + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.4.10': + resolution: {integrity: sha512-Ht8wIW5v165atIX1p+JvKR5ONzUyF4Ac8DZIQ5kZs9zrb6M8SJNXpx1zn04rn65VjBMygRoMXcyYwNK0fT7bEg==} + + '@jridgewell/sourcemap-codec@1.4.14': + resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@napi-rs/wasm-runtime@1.1.4': + resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@next/env@16.2.6': + resolution: {integrity: sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==} + + '@next/eslint-plugin-next@16.2.6': + resolution: {integrity: sha512-Z8l6o4JWKUl755x4R+wogD86KPeU+Ckw4K+SYG4kHeOJtRenDeK+OSbGcqZpDtbwn9DsJVdir2UxmwXuinUbUw==} + + '@next/swc-darwin-arm64@16.2.6': + resolution: {integrity: sha512-ZJGkkcNfYgrrMkqOdZ7zoLa1TOy0qpcMfk/z4Mh/FKUz40gVO+HNQWqmLxf67Z5WB64DRp0dhEbyHfel+6sJUg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@16.2.6': + resolution: {integrity: sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@16.2.6': + resolution: {integrity: sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-arm64-musl@16.2.6': + resolution: {integrity: sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@next/swc-linux-x64-gnu@16.2.6': + resolution: {integrity: sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-x64-musl@16.2.6': + resolution: {integrity: sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@next/swc-win32-arm64-msvc@16.2.6': + resolution: {integrity: sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@16.2.6': + resolution: {integrity: sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} + + '@oxc-project/types@0.132.0': + resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@playwright/test@1.60.0': + resolution: {integrity: sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==} + engines: {node: '>=18'} + hasBin: true + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-slot@1.2.4': + resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@rolldown/binding-android-arm64@1.0.2': + resolution: {integrity: sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.2': + resolution: {integrity: sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.2': + resolution: {integrity: sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.2': + resolution: {integrity: sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': + resolution: {integrity: sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.2': + resolution: {integrity: sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.2': + resolution: {integrity: sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.0.2': + resolution: {integrity: sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.2': + resolution: {integrity: sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.0.2': + resolution: {integrity: sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.0.2': + resolution: {integrity: sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.0.2': + resolution: {integrity: sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.2': + resolution: {integrity: sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.2': + resolution: {integrity: sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.2': + resolution: {integrity: sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@standard-schema/utils@0.3.0': + resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@tailwindcss/node@4.3.0': + resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} + + '@tailwindcss/oxide-android-arm64@4.3.0': + resolution: {integrity: sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.0': + resolution: {integrity: sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.0': + resolution: {integrity: sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.0': + resolution: {integrity: sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + resolution: {integrity: sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + resolution: {integrity: sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': + resolution: {integrity: sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + resolution: {integrity: sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.0': + resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==} + engines: {node: '>= 20'} + + '@tailwindcss/postcss@4.3.0': + resolution: {integrity: sha512-Jm05Tjx+9yCLGv5qw1c+84Psds8MnyrEQYCB+FFk2lgGiUjlRqdxke4mVTuYrj2xnVZqKim2Apr5ySuQRYAw/w==} + + '@tanstack/query-core@5.100.13': + resolution: {integrity: sha512-mlKVKMTzZWGTKAC1CKOgt7axAjJ921emkEvYIp27I/PdP1yEYL/BteLY8iK35gn8hoYeKB4mgJ/ve3lrDI6/Fw==} + + '@tanstack/react-query@5.100.13': + resolution: {integrity: sha512-HSBr8CycQEAoXsJR7KNDawBnINJEJ96Eme8oE0hCXjyodE2I97vg3IDzDJBDu18LsbzpVVJcKo80eqLfVCykxw==} + peerDependencies: + react: ^18 || ^19 + + '@testing-library/dom@10.4.1': + resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} + engines: {node: '>=18'} + + '@testing-library/jest-dom@6.9.1': + resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + + '@testing-library/react@16.3.2': + resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} + engines: {node: '>=18'} + peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 || ^19.0.0 + '@types/react-dom': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/node@20.19.41': + resolution: {integrity: sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==} + + '@types/prop-types@15.7.15': + resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + + '@types/react-dom@18.3.7': + resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} + peerDependencies: + '@types/react': ^18.0.0 + + '@types/react@18.3.29': + resolution: {integrity: sha512-ch0qJdr2JY0r04NXSprbK6TXOgnaJ1Tz23fm5W+z0/CBah6BSBc3n96h7K9GOtwh0HrilNWHIBzE1Ko4Dcw/Wg==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@16.0.11': + resolution: {integrity: sha512-sbtvk8wDN+JvEdabmZExoW/HNr1cB7D/j4LT08rMiuikfA7m/JNJg7ATQcgzs34zHnoScDkY0ZRSl29Fkmk36g==} + + '@typescript-eslint/eslint-plugin@8.59.4': + resolution: {integrity: sha512-PegsU+XfyJJNjd4+u/k6f9yTyp0lEXXiPopUNobZcIAUJFGICFLN+sP0Rb3JehVmiij1Ph0dFGYqODoRo/2+6A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.59.4 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/parser@8.59.4': + resolution: {integrity: sha512-zORHqO/tuhxY1zWuTvMUqddRxpiFJ72xVfcNoWpqdLjs6lfPbuQBJuW4pk+49/uBMy7Ssr4bzgjiKmmDB1UbZQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/project-service@8.59.4': + resolution: {integrity: sha512-Ly00Vu4oAacfDeHp2Zg85ioNG6l8HG+tN1D7J+xTHSxu9y0awYKJ2zH1rFBn8ZSfuGK+7FxK3Cgl3uAz0aZZLg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.59.4': + resolution: {integrity: sha512-mUeR/3H1WrTAddJrwut8OoPjfauaztMQmRwV5fQTUyNVJCLiUXXe4lGEyYIL2oFDpP7UtgbGJXCt72wT0z2S3Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.59.4': + resolution: {integrity: sha512-DLCpnKgD4alVxTBSKulK+gU1KCqOgUXfDRDXh2mZgzokQKa/70ax93I2uVO3m/LLvIAtWZIFoiifudmIqAxpMA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/type-utils@8.59.4': + resolution: {integrity: sha512-uonTuPAAKr9XaBGqJ3LjYTh72zy5DyGesljO9gtmk/eFW0W1fRHjnwVYKB35Lm8d5Q5CluEW3gPHjTvZTmgrfA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@8.59.4': + resolution: {integrity: sha512-F1o7WJcCq+bc8dwcO/YsSEOudAH8RDtaOhM6wcAQhcUsFhnWQl81JKy48q1hoxAU0qrzM89+31GYh1515Zde3Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.59.4': + resolution: {integrity: sha512-F+RuOmcDXo4+TPdfd/TCLS3m2nw8gE9XXyZLrA3JBfaA5tz9TtdkyD3YJFmPxulyc2cKbEok/CvFE3MgSLWnag==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/utils@8.59.4': + resolution: {integrity: sha512-cYXeNAUsG4lJo5dbc1FcKm+JwIWrj1/UpTORsC6tGMjEZ81DYcvIr9/ueikhMa/Y/gDQYGp+YX9/xQrXje5BJw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@8.59.4': + resolution: {integrity: sha512-U3gxVaDVnuZKhSspW/MzMxE1kq7zOdc072FcSNoqA1I9p8HyKbBFfEHoWckBAMgNMph4MamwS5iTVzFmrnt8TQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + resolution: {integrity: sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.12.2': + resolution: {integrity: sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.12.2': + resolution: {integrity: sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.12.2': + resolution: {integrity: sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.12.2': + resolution: {integrity: sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + resolution: {integrity: sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + resolution: {integrity: sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + resolution: {integrity: sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + resolution: {integrity: sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + resolution: {integrity: sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + resolution: {integrity: sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + resolution: {integrity: sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + resolution: {integrity: sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + resolution: {integrity: sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + resolution: {integrity: sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + resolution: {integrity: sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + resolution: {integrity: sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + resolution: {integrity: sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==} + cpu: [arm64] + os: [openharmony] + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': + resolution: {integrity: sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + resolution: {integrity: sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + resolution: {integrity: sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + resolution: {integrity: sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==} + cpu: [x64] + os: [win32] + + '@vitejs/plugin-react@4.0.0': + resolution: {integrity: sha512-HX0XzMjL3hhOYm+0s95pb0Z7F8O81G7joUHgfDd/9J/ZZf5k4xX6QAMFkKsHFxaHlf6X7GD7+XuaZ66ULiJuhQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 + + '@vitest/expect@4.1.7': + resolution: {integrity: sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w==} + + '@vitest/mocker@4.1.7': + resolution: {integrity: sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.7': + resolution: {integrity: sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==} + + '@vitest/runner@4.1.7': + resolution: {integrity: sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw==} + + '@vitest/snapshot@4.1.7': + resolution: {integrity: sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw==} + + '@vitest/spy@4.1.7': + resolution: {integrity: sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==} + + '@vitest/utils@4.1.7': + resolution: {integrity: sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@6.0.0: + resolution: {integrity: sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==} + engines: {node: '>= 6.0.0'} + + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axe-core@4.11.4: + resolution: {integrity: sha512-KunSNx+TVpkAw/6ULfhnx+HWRecjqZGTOyquAoWHYLRSdK1tB5Ihce1ZW+UY3fj33bYAFWPu7W/GRSmmrCGuxA==} + engines: {node: '>=4'} + + axios@1.16.1: + resolution: {integrity: sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + balanced-match@1.0.0: + resolution: {integrity: sha512-9Y0g0Q8rmSt+H33DfKv7FOc3v+iRI+o1lbzt8jGcIosYW37IIW/2XVYq5NPdmaD5NQ59Nk26Kl/vZbwW9Fr8vg==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + baseline-browser-mapping@2.10.32: + resolution: {integrity: sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==} + engines: {node: '>=6.0.0'} + hasBin: true + + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + + brace-expansion@1.1.14: + resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} + + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} + + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + engines: {node: 18 || 20 || >=22} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001793: + resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} + + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css.escape@1.5.1: + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + + data-urls@7.0.0: + resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + + dom-accessibility-api@0.6.3: + resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + electron-to-chromium@1.5.361: + resolution: {integrity: sha512-Q6Hts7N9FnJc5LeGRINFvLhCI9xZmNtTDe5ZbcVezQz7cU4a8Aua3GH1b8J2XY8Al9PF+OCwYqhgsOOheMdvkA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + enhanced-resolve@5.22.0: + resolution: {integrity: sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==} + engines: {node: '>=10.13.0'} + + entities@8.0.0: + resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} + engines: {node: '>=20.19.0'} + + es-abstract@1.24.2: + resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-iterator-helpers@1.3.2: + resolution: {integrity: sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==} + engines: {node: '>= 0.4'} + + es-module-lexer@2.1.0: + resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-next@16.2.6: + resolution: {integrity: sha512-z2ELYSkyrrJ6cuunTU8vhsT/RpouPkjaSah06nVW6Rg2Hpg0Vs8s497/e5s8G8qtdp4ccsiovz5P1rv+5VSW2Q==} + peerDependencies: + eslint: '>=9.0.0' + typescript: '>=3.3.1' + peerDependenciesMeta: + typescript: + optional: true + + eslint-import-resolver-node@0.3.10: + resolution: {integrity: sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==} + + eslint-import-resolver-typescript@3.10.1: + resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.12.1: + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-jsx-a11y@6.10.2: + resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + + eslint-plugin-react-hooks@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 + + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.39.4: + resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.0: + resolution: {integrity: sha512-EryKbCE/wxpxKniQlyas6PY1I9vwtF3uCBweX+N8KYTCn3Y12RTGtQAJ/bd5pl7kxUAc8v/R3Ake/N17OZiFqA==} + engines: {node: '>=16'} + + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + foreground-child@3.1.0: + resolution: {integrity: sha512-lXeSPRCndWPaipZbtI4CkvTZpF6OPsy19dkvf7+5AHeJD+w+iAKPc9Q78xWBmX4SdR+8xrtY9jTXs/YDv8q+Ug==} + engines: {node: '>=14'} + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@16.4.0: + resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.3: + resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} + engines: {node: '>= 0.4'} + + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + + html-encoding-sniffer@6.0.0: + resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + import-fresh@3.2.1: + resolution: {integrity: sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-bun-module@2.0.0: + resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + + jackspeak@3.1.2: + resolution: {integrity: sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==} + engines: {node: '>=14'} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + js-tokens@3.0.0: + resolution: {integrity: sha512-poXEQHPMmTrYZuJgNRll2sbc3kJsSU1m/g1Q93IE6txNj3p6xOOOmdj1G/zCVGawYSPzTkSoWGg1otqbeqKJeg==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsdom@29.1.1: + resolution: {integrity: sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + language-subtag-registry@0.3.20: + resolution: {integrity: sha512-KPMwROklF4tEx283Xw0pNKtfTj1gZ4UByp4EsIFWLgBavJltF4TiYPc39k06zSTsLzxTVXXDSpbwaQXaFB4Qeg==} + + language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@10.2.0: + resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} + engines: {node: 14 || >=16.14} + + lru-cache@11.5.0: + resolution: {integrity: sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==} + engines: {node: 20 || >=22} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-react@1.16.0: + resolution: {integrity: sha512-dYwyPzb4MEKpGUmNYk3WKWPnMrHs3FKM+q94kAnJrcDIqqn1hq2xY8scaS2ovsOCM5D51ey2gaRG3PBb1vgoYQ==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + next@16.2.6: + resolution: {integrity: sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==} + engines: {node: '>=20.9.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + + node-exports-info@1.6.0: + resolution: {integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==} + engines: {node: '>= 0.4'} + + node-releases@2.0.46: + resolution: {integrity: sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==} + engines: {node: '>=18'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-limit@3.0.2: + resolution: {integrity: sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse5@8.0.1: + resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + playwright-core@1.60.0: + resolution: {integrity: sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.60.0: + resolution: {integrity: sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==} + engines: {node: '>=18'} + hasBin: true + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + pretty-format@27.0.2: + resolution: {integrity: sha512-mXKbbBPnYTG7Yra9qFBtqj+IXcsvxsvOBco3QHxtxTl+hHKq6QdzMZ+q0CtL4ORHZgwGImRr2XZUX2EWzORxig==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + react-dom@18.0.0: + resolution: {integrity: sha512-XqX7uzmFo0pUceWFCt7Gff6IyIMzFUn7QMZrbrQfGxtaxXZIcGQzoNpRLE3fQLnS4XzLLPMZX2T9TRcSrasicw==} + peerDependencies: + react: ^18.0.0 + + react-hook-form@7.76.1: + resolution: {integrity: sha512-rYM7tPiWlu3nZchkR/ex7piyzui2vFPyaLnXnI/RnblB/L4qfMmyses8llJVtF1NpE9WBBsJlGtcSZzPCXW1qQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-is@17.0.1: + resolution: {integrity: sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==} + + react-refresh@0.14.0: + resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} + engines: {node: '>=0.10.0'} + + react@18.0.0: + resolution: {integrity: sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==} + engines: {node: '>=0.10.0'} + + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@2.0.0-next.7: + resolution: {integrity: sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==} + engines: {node: '>= 0.4'} + hasBin: true + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@5.0.5: + resolution: {integrity: sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==} + engines: {node: '>=14'} + hasBin: true + + rolldown@1.0.2: + resolution: {integrity: sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.4: + resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} + engines: {node: '>=0.4'} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + + scheduler@0.21.0: + resolution: {integrity: sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.8.1: + resolution: {integrity: sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==} + engines: {node: '>=10'} + hasBin: true + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + stable-hash@0.0.5: + resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@4.1.0: + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + string-width@4.2.0: + resolution: {integrity: sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string.prototype.includes@2.0.1: + resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} + engines: {node: '>= 0.4'} + + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + + tailwind-merge@3.6.0: + resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} + + tailwindcss-animate@1.0.7: + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + + tailwindcss@4.3.0: + resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@1.1.2: + resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} + engines: {node: '>=18'} + + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + + tldts-core@7.0.30: + resolution: {integrity: sha512-uiHN8PIB1VmWyS98eZYja4xzlYqeFZVjb4OuYlJQnZAuJhMw4PbKQOKgHKhBdJR3FE/t5mUQ1Kd80++B+qhD1Q==} + + tldts@7.0.30: + resolution: {integrity: sha512-ELrFxuqsDdHUwoh0XxDbxuLD3Wnz49Z57IFvTtvWy1hJdcMZjXLIuonjilCiWHlT2GbE4Wlv1wKVTzDFnXH1aw==} + hasBin: true + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tough-cookie@6.0.1: + resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} + engines: {node: '>=16'} + + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} + + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typescript-eslint@8.59.4: + resolution: {integrity: sha512-Rw6+44QNFaXtgHSjPy+Kw8hrJniMYzR85E9yLmOLcfZ91/rz+JXQbDTCmc6ccxMPY6K6PgAq26f0JCBfR7LIPQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + typescript@5.0.2: + resolution: {integrity: sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==} + engines: {node: '>=12.20'} + hasBin: true + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + undici@7.25.0: + resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} + engines: {node: '>=20.18.1'} + + unrs-resolver@1.12.2: + resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + vite@8.0.14: + resolution: {integrity: sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.18 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.1.7: + resolution: {integrity: sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.7 + '@vitest/browser-preview': 4.1.7 + '@vitest/browser-webdriverio': 4.1.7 + '@vitest/coverage-istanbul': 4.1.7 + '@vitest/coverage-v8': 4.1.7 + '@vitest/ui': 4.1.7 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} + engines: {node: '>=20'} + + whatwg-mimetype@5.0.0: + resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} + engines: {node: '>=20'} + + whatwg-url@16.0.1: + resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.20: + resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} + engines: {node: '>= 0.4'} + + which@2.0.1: + resolution: {integrity: sha512-N7GBZOTswtB9lkQBZA4+zAXrjEIWAUOB93AvzUiudRzRxhUdLURQ7D/gAIMY1gatT/LTbmbcv8SiYazy3eYB7w==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + + zustand@5.0.13: + resolution: {integrity: sha512-efI2tVaVQPqtOh114loML/Z80Y4NP3yc+Ff0fYiZJPauNeWZeIp/bRFD7I9bfmCOYBh/PHxlglQ9+wvlwnPikQ==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + +snapshots: + + '@adobe/css-tools@4.5.0': {} + + '@alloc/quick-lru@5.2.0': {} + + '@asamuzakjp/css-color@5.1.11': + dependencies: + '@asamuzakjp/generational-cache': 1.0.1 + '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@asamuzakjp/dom-selector@7.1.1': + dependencies: + '@asamuzakjp/generational-cache': 1.0.1 + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.2.1 + is-potential-custom-element-name: 1.0.1 + + '@asamuzakjp/generational-cache@1.0.1': {} + + '@asamuzakjp/nwsapi@2.3.9': {} + + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.3': {} + + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.3 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.3 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.28.6': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.29.2': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + + '@babel/parser@7.29.3': + dependencies: + '@babel/types': 7.29.0 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/runtime@7.29.2': {} + + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.3 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@bramus/specificity@2.4.2': + dependencies: + css-tree: 3.2.1 + + '@csstools/color-helpers@6.0.2': {} + + '@csstools/css-calc@3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-color-parser@4.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/color-helpers': 6.0.2 + '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.4(css-tree@3.2.1)': + optionalDependencies: + css-tree: 3.2.1 + + '@csstools/css-tokenizer@4.0.0': {} + + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))': + dependencies: + eslint: 9.39.4(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.2': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.5': + dependencies: + ajv: 6.15.0 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.2.1 + js-yaml: 4.1.1 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.4': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@exodus/bytes@1.15.1': {} + + '@hookform/resolvers@5.4.0(react-hook-form@7.76.1(react@18.0.0))': + dependencies: + '@standard-schema/utils': 0.3.0 + react-hook-form: 7.76.1(react@18.0.0) + + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@img/colour@1.1.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.10.0 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.0 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jest/types@27.0.2': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 20.19.41 + '@types/yargs': 16.0.11 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.12': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/gen-mapping@0.3.5': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.4.10 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.4.10': {} + + '@jridgewell/sourcemap-codec@1.4.14': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.4.14 + + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 + optional: true + + '@next/env@16.2.6': {} + + '@next/eslint-plugin-next@16.2.6': + dependencies: + fast-glob: 3.3.1 + + '@next/swc-darwin-arm64@16.2.6': + optional: true + + '@next/swc-darwin-x64@16.2.6': + optional: true + + '@next/swc-linux-arm64-gnu@16.2.6': + optional: true + + '@next/swc-linux-arm64-musl@16.2.6': + optional: true + + '@next/swc-linux-x64-gnu@16.2.6': + optional: true + + '@next/swc-linux-x64-musl@16.2.6': + optional: true + + '@next/swc-win32-arm64-msvc@16.2.6': + optional: true + + '@next/swc-win32-x64-msvc@16.2.6': + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@nolyfill/is-core-module@1.0.39': {} + + '@oxc-project/types@0.132.0': {} + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@playwright/test@1.60.0': + dependencies: + playwright: 1.60.0 + + '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.29)(react@18.0.0)': + dependencies: + react: 18.0.0 + optionalDependencies: + '@types/react': 18.3.29 + + '@radix-ui/react-slot@1.2.4(@types/react@18.3.29)(react@18.0.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.29)(react@18.0.0) + react: 18.0.0 + optionalDependencies: + '@types/react': 18.3.29 + + '@rolldown/binding-android-arm64@1.0.2': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.2': + optional: true + + '@rolldown/binding-darwin-x64@1.0.2': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.2': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.2': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.2': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.2': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.2': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.2': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.2': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.2': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.2': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.2': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.2': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@rtsao/scc@1.1.0': {} + + '@standard-schema/spec@1.1.0': {} + + '@standard-schema/utils@0.3.0': {} + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/node@4.3.0': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.22.0 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.0 + + '@tailwindcss/oxide-android-arm64@4.3.0': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.0': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.0': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + optional: true + + '@tailwindcss/oxide@4.3.0': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-arm64': 4.3.0 + '@tailwindcss/oxide-darwin-x64': 4.3.0 + '@tailwindcss/oxide-freebsd-x64': 4.3.0 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.0 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.0 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.0 + '@tailwindcss/oxide-linux-x64-musl': 4.3.0 + '@tailwindcss/oxide-wasm32-wasi': 4.3.0 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.0 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.0 + + '@tailwindcss/postcss@4.3.0': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.3.0 + '@tailwindcss/oxide': 4.3.0 + postcss: 8.5.15 + tailwindcss: 4.3.0 + + '@tanstack/query-core@5.100.13': {} + + '@tanstack/react-query@5.100.13(react@18.0.0)': + dependencies: + '@tanstack/query-core': 5.100.13 + react: 18.0.0 + + '@testing-library/dom@10.4.1': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/runtime': 7.29.2 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.0.2 + + '@testing-library/jest-dom@6.9.1': + dependencies: + '@adobe/css-tools': 4.5.0 + aria-query: 5.3.2 + css.escape: 1.5.1 + dom-accessibility-api: 0.6.3 + picocolors: 1.1.1 + redent: 3.0.0 + + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@18.3.7(@types/react@18.3.29))(@types/react@18.3.29)(react-dom@18.0.0(react@18.0.0))(react@18.0.0)': + dependencies: + '@babel/runtime': 7.29.2 + '@testing-library/dom': 10.4.1 + react: 18.0.0 + react-dom: 18.0.0(react@18.0.0) + optionalDependencies: + '@types/react': 18.3.29 + '@types/react-dom': 18.3.7(@types/react@18.3.29) + + '@tybys/wasm-util@0.10.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/aria-query@5.0.4': {} + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.9': {} + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/node@20.19.41': + dependencies: + undici-types: 6.21.0 + + '@types/prop-types@15.7.15': {} + + '@types/react-dom@18.3.7(@types/react@18.3.29)': + dependencies: + '@types/react': 18.3.29 + + '@types/react@18.3.29': + dependencies: + '@types/prop-types': 15.7.15 + csstype: 3.2.3 + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@16.0.11': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@typescript-eslint/eslint-plugin@8.59.4(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2))(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2) + '@typescript-eslint/scope-manager': 8.59.4 + '@typescript-eslint/type-utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2) + '@typescript-eslint/utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2) + '@typescript-eslint/visitor-keys': 8.59.4 + eslint: 9.39.4(jiti@2.7.0) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.0.2) + typescript: 5.0.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2)': + dependencies: + '@typescript-eslint/scope-manager': 8.59.4 + '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/typescript-estree': 8.59.4(typescript@5.0.2) + '@typescript-eslint/visitor-keys': 8.59.4 + debug: 4.4.3 + eslint: 9.39.4(jiti@2.7.0) + typescript: 5.0.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.59.4(typescript@5.0.2)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.59.4(typescript@5.0.2) + '@typescript-eslint/types': 8.59.4 + debug: 4.4.3 + typescript: 5.0.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.59.4': + dependencies: + '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/visitor-keys': 8.59.4 + + '@typescript-eslint/tsconfig-utils@8.59.4(typescript@5.0.2)': + dependencies: + typescript: 5.0.2 + + '@typescript-eslint/type-utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2)': + dependencies: + '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/typescript-estree': 8.59.4(typescript@5.0.2) + '@typescript-eslint/utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2) + debug: 4.4.3 + eslint: 9.39.4(jiti@2.7.0) + ts-api-utils: 2.5.0(typescript@5.0.2) + typescript: 5.0.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.59.4': {} + + '@typescript-eslint/typescript-estree@8.59.4(typescript@5.0.2)': + dependencies: + '@typescript-eslint/project-service': 8.59.4(typescript@5.0.2) + '@typescript-eslint/tsconfig-utils': 8.59.4(typescript@5.0.2) + '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/visitor-keys': 8.59.4 + debug: 4.4.3 + minimatch: 10.2.5 + semver: 7.8.1 + tinyglobby: 0.2.16 + ts-api-utils: 2.5.0(typescript@5.0.2) + typescript: 5.0.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.59.4 + '@typescript-eslint/types': 8.59.4 + '@typescript-eslint/typescript-estree': 8.59.4(typescript@5.0.2) + eslint: 9.39.4(jiti@2.7.0) + typescript: 5.0.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.59.4': + dependencies: + '@typescript-eslint/types': 8.59.4 + eslint-visitor-keys: 5.0.1 + + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + optional: true + + '@unrs/resolver-binding-android-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.12.2': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + optional: true + + '@vitejs/plugin-react@4.0.0(vite@8.0.14(@types/node@20.19.41)(jiti@2.7.0))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + react-refresh: 0.14.0 + vite: 8.0.14(@types/node@20.19.41)(jiti@2.7.0) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@4.1.7': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.7 + '@vitest/utils': 4.1.7 + chai: 6.2.2 + tinyrainbow: 3.1.0 + + '@vitest/mocker@4.1.7(vite@8.0.14(@types/node@20.19.41)(jiti@2.7.0))': + dependencies: + '@vitest/spy': 4.1.7 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.14(@types/node@20.19.41)(jiti@2.7.0) + + '@vitest/pretty-format@4.1.7': + dependencies: + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.7': + dependencies: + '@vitest/utils': 4.1.7 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.7': + dependencies: + '@vitest/pretty-format': 4.1.7 + '@vitest/utils': 4.1.7 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.7': {} + + '@vitest/utils@4.1.7': + dependencies: + '@vitest/pretty-format': 4.1.7 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + + acorn-jsx@5.3.2(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + + acorn@8.16.0: {} + + agent-base@6.0.0: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + ansi-styles@6.2.3: {} + + argparse@2.0.1: {} + + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + + aria-query@5.3.2: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-shim-unscopables: 1.1.0 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-shim-unscopables: 1.1.0 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + assertion-error@2.0.1: {} + + ast-types-flow@0.0.8: {} + + async-function@1.0.0: {} + + asynckit@0.4.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axe-core@4.11.4: {} + + axios@1.16.1: + dependencies: + follow-redirects: 1.16.0 + form-data: 4.0.5 + https-proxy-agent: 5.0.1 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + - supports-color + + axobject-query@4.1.0: {} + + balanced-match@1.0.0: {} + + balanced-match@4.0.4: {} + + baseline-browser-mapping@2.10.32: {} + + bidi-js@1.0.3: + dependencies: + require-from-string: 2.0.2 + + brace-expansion@1.1.14: + dependencies: + balanced-match: 1.0.0 + concat-map: 0.0.1 + + brace-expansion@2.1.0: + dependencies: + balanced-match: 1.0.0 + + brace-expansion@5.0.6: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.32 + caniuse-lite: 1.0.30001793 + electron-to-chromium: 1.5.361 + node-releases: 2.0.46 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.9: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001793: {} + + chai@6.2.2: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + client-only@0.0.1: {} + + clsx@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.1 + + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + + css.escape@1.5.1: {} + + csstype@3.2.3: {} + + damerau-levenshtein@1.0.8: {} + + data-urls@7.0.0: + dependencies: + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + transitivePeerDependencies: + - '@noble/hashes' + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decimal.js@10.6.0: {} + + deep-is@0.1.4: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + delayed-stream@1.0.0: {} + + dequal@2.0.3: {} + + detect-libc@2.1.2: {} + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + dom-accessibility-api@0.5.16: {} + + dom-accessibility-api@0.6.3: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + electron-to-chromium@1.5.361: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + enhanced-resolve@5.22.0: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + entities@8.0.0: {} + + es-abstract@1.24.2: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.3 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.4 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.20 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-iterator-helpers@1.3.2: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + math-intrinsics: 1.1.0 + + es-module-lexer@2.1.0: {} + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.3 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.3 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-config-next@16.2.6(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2))(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2): + dependencies: + '@next/eslint-plugin-next': 16.2.6 + eslint: 9.39.4(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-react: 7.37.5(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-react-hooks: 7.1.1(eslint@9.39.4(jiti@2.7.0)) + globals: 16.4.0 + typescript-eslint: 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2) + optionalDependencies: + typescript: 5.0.2 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + + eslint-import-resolver-node@0.3.10: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.2 + resolve: 2.0.0-next.7 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.4.3 + eslint: 9.39.4(jiti@2.7.0) + get-tsconfig: 4.14.0 + is-bun-module: 2.0.0 + stable-hash: 0.0.5 + tinyglobby: 0.2.16 + unrs-resolver: 1.12.2 + optionalDependencies: + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2) + eslint: 9.39.4(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.4(jiti@2.7.0)) + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.39.4(jiti@2.7.0) + eslint-import-resolver-node: 0.3.10 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@2.7.0)) + hasown: 2.0.3 + is-core-module: 2.16.2 + is-glob: 4.0.3 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.4(jiti@2.7.0)): + dependencies: + aria-query: 5.3.2 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + ast-types-flow: 0.0.8 + axe-core: 4.11.4 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 9.39.4(jiti@2.7.0) + hasown: 2.0.3 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + safe-regex-test: 1.1.0 + string.prototype.includes: 2.0.1 + + eslint-plugin-react-hooks@7.1.1(eslint@9.39.4(jiti@2.7.0)): + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.3 + eslint: 9.39.4(jiti@2.7.0) + hermes-parser: 0.25.1 + zod: 4.4.3 + zod-validation-error: 4.0.2(zod@4.4.3) + transitivePeerDependencies: + - supports-color + + eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@2.7.0)): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.3.2 + eslint: 9.39.4(jiti@2.7.0) + estraverse: 5.3.0 + hasown: 2.0.3 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.5 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.7 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@9.39.4(jiti@2.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.2 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.5 + '@eslint/js': 9.39.4 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.9 + ajv: 6.15.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + esutils@2.0.3: {} + + expect-type@1.3.0: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.1: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.0 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.0: + dependencies: + flatted: 3.4.2 + keyv: 4.5.4 + rimraf: 5.0.5 + + flatted@3.4.2: {} + + follow-redirects@1.16.0: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + foreground-child@3.1.0: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.3 + mime-types: 2.1.35 + + fsevents@2.3.2: + optional: true + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.3 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + generator-function@2.0.1: {} + + gensync@1.0.0-beta.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.3 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + get-tsconfig@4.14.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.5.0: + dependencies: + foreground-child: 3.1.0 + jackspeak: 3.1.2 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + globals@14.0.0: {} + + globals@16.4.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.3: + dependencies: + function-bind: 1.1.2 + + hermes-estree@0.25.1: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + + html-encoding-sniffer@6.0.0: + dependencies: + '@exodus/bytes': 1.15.1 + transitivePeerDependencies: + - '@noble/hashes' + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.2.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + indent-string@4.0.0: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.3 + side-channel: 1.1.0 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-bun-module@2.0.0: + dependencies: + semver: 7.8.1 + + is-callable@1.2.7: {} + + is-core-module@2.16.2: + dependencies: + hasown: 2.0.3 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-fullwidth-code-point@3.0.0: {} + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-potential-custom-element-name@1.0.1: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.3 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.20 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + iterator.prototype@1.1.5: + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + + jackspeak@3.1.2: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jiti@2.7.0: {} + + js-tokens@3.0.0: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsdom@29.1.1: + dependencies: + '@asamuzakjp/css-color': 5.1.11 + '@asamuzakjp/dom-selector': 7.1.1 + '@bramus/specificity': 2.4.2 + '@csstools/css-syntax-patches-for-csstree': 1.1.4(css-tree@3.2.1) + '@exodus/bytes': 1.15.1 + css-tree: 3.2.1 + data-urls: 7.0.0 + decimal.js: 10.6.0 + html-encoding-sniffer: 6.0.0 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.5.0 + parse5: 8.0.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.1 + undici: 7.25.0 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - '@noble/hashes' + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + json5@2.2.3: {} + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + language-subtag-registry@0.3.20: {} + + language-tags@1.0.9: + dependencies: + language-subtag-registry: 0.3.20 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 3.0.0 + + lru-cache@10.2.0: {} + + lru-cache@11.5.0: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@1.16.0(react@18.0.0): + dependencies: + react: 18.0.0 + + lz-string@1.5.0: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + math-intrinsics@1.1.0: {} + + mdn-data@2.27.1: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + min-indent@1.0.1: {} + + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.6 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.14 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.0 + + minimist@1.2.8: {} + + minipass@7.1.3: {} + + ms@2.1.3: {} + + nanoid@3.3.12: {} + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} + + next@16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@18.0.0(react@18.0.0))(react@18.0.0): + dependencies: + '@next/env': 16.2.6 + '@swc/helpers': 0.5.15 + baseline-browser-mapping: 2.10.32 + caniuse-lite: 1.0.30001793 + postcss: 8.4.31 + react: 18.0.0 + react-dom: 18.0.0(react@18.0.0) + styled-jsx: 5.1.6(@babel/core@7.29.0)(react@18.0.0) + optionalDependencies: + '@next/swc-darwin-arm64': 16.2.6 + '@next/swc-darwin-x64': 16.2.6 + '@next/swc-linux-arm64-gnu': 16.2.6 + '@next/swc-linux-arm64-musl': 16.2.6 + '@next/swc-linux-x64-gnu': 16.2.6 + '@next/swc-linux-x64-musl': 16.2.6 + '@next/swc-win32-arm64-msvc': 16.2.6 + '@next/swc-win32-x64-msvc': 16.2.6 + '@playwright/test': 1.60.0 + sharp: 0.34.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + node-exports-info@1.6.0: + dependencies: + array.prototype.flatmap: 1.3.3 + es-errors: 1.3.0 + object.entries: 1.1.9 + semver: 6.3.1 + + node-releases@2.0.46: {} + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.entries@1.1.9: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + obug@2.1.1: {} + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-limit@3.0.2: + dependencies: + p-try: 2.2.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.0.2 + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse5@8.0.1: + dependencies: + entities: 8.0.0 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.2.0 + minipass: 7.1.3 + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.4: {} + + playwright-core@1.60.0: {} + + playwright@1.60.0: + dependencies: + playwright-core: 1.60.0 + optionalDependencies: + fsevents: 2.3.2 + + possible-typed-array-names@1.1.0: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.15: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + pretty-format@27.0.2: + dependencies: + '@jest/types': 27.0.2 + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.1 + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + proxy-from-env@2.1.0: {} + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + react-dom@18.0.0(react@18.0.0): + dependencies: + loose-envify: 1.4.0 + react: 18.0.0 + scheduler: 0.21.0 + + react-hook-form@7.76.1(react@18.0.0): + dependencies: + react: 18.0.0 + + react-is@16.13.1: {} + + react-is@17.0.1: {} + + react-refresh@0.14.0: {} + + react@18.0.0: + dependencies: + loose-envify: 1.4.0 + + redent@3.0.0: + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + resolve-pkg-maps@1.0.0: {} + + resolve@2.0.0-next.7: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.2 + node-exports-info: 1.6.0 + object-keys: 1.1.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + rimraf@5.0.5: + dependencies: + glob: 10.5.0 + + rolldown@1.0.2: + dependencies: + '@oxc-project/types': 0.132.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.2 + '@rolldown/binding-darwin-arm64': 1.0.2 + '@rolldown/binding-darwin-x64': 1.0.2 + '@rolldown/binding-freebsd-x64': 1.0.2 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.2 + '@rolldown/binding-linux-arm64-gnu': 1.0.2 + '@rolldown/binding-linux-arm64-musl': 1.0.2 + '@rolldown/binding-linux-ppc64-gnu': 1.0.2 + '@rolldown/binding-linux-s390x-gnu': 1.0.2 + '@rolldown/binding-linux-x64-gnu': 1.0.2 + '@rolldown/binding-linux-x64-musl': 1.0.2 + '@rolldown/binding-openharmony-arm64': 1.0.2 + '@rolldown/binding-wasm32-wasi': 1.0.2 + '@rolldown/binding-win32-arm64-msvc': 1.0.2 + '@rolldown/binding-win32-x64-msvc': 1.0.2 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.4: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + + scheduler@0.21.0: + dependencies: + loose-envify: 1.4.0 + + semver@6.3.1: {} + + semver@7.8.1: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.1 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + siginfo@2.0.0: {} + + signal-exit@4.1.0: {} + + source-map-js@1.2.1: {} + + stable-hash@0.0.5: {} + + stackback@0.0.2: {} + + std-env@4.1.0: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + string-width@4.2.0: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 + + string.prototype.includes@2.0.1: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-abstract: 1.24.2 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.2 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.9 + define-properties: 1.2.1 + es-object-atoms: 1.1.2 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + + strip-bom@3.0.0: {} + + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + + strip-json-comments@3.1.1: {} + + styled-jsx@5.1.6(@babel/core@7.29.0)(react@18.0.0): + dependencies: + client-only: 0.0.1 + react: 18.0.0 + optionalDependencies: + '@babel/core': 7.29.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + symbol-tree@3.2.4: {} + + tailwind-merge@3.6.0: {} + + tailwindcss-animate@1.0.7(tailwindcss@4.3.0): + dependencies: + tailwindcss: 4.3.0 + + tailwindcss@4.3.0: {} + + tapable@2.3.3: {} + + tinybench@2.9.0: {} + + tinyexec@1.1.2: {} + + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + tinyrainbow@3.1.0: {} + + tldts-core@7.0.30: {} + + tldts@7.0.30: + dependencies: + tldts-core: 7.0.30 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tough-cookie@6.0.1: + dependencies: + tldts: 7.0.30 + + tr46@6.0.0: + dependencies: + punycode: 2.3.1 + + ts-api-utils@2.5.0(typescript@5.0.2): + dependencies: + typescript: 5.0.2 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.9 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript-eslint@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2): + dependencies: + '@typescript-eslint/eslint-plugin': 8.59.4(@typescript-eslint/parser@8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2))(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2) + '@typescript-eslint/parser': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2) + '@typescript-eslint/typescript-estree': 8.59.4(typescript@5.0.2) + '@typescript-eslint/utils': 8.59.4(eslint@9.39.4(jiti@2.7.0))(typescript@5.0.2) + eslint: 9.39.4(jiti@2.7.0) + typescript: 5.0.2 + transitivePeerDependencies: + - supports-color + + typescript@5.0.2: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@6.21.0: {} + + undici@7.25.0: {} + + unrs-resolver@1.12.2: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.12.2 + '@unrs/resolver-binding-android-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-x64': 1.12.2 + '@unrs/resolver-binding-freebsd-x64': 1.12.2 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-arm64-musl': 1.12.2 + '@unrs/resolver-binding-linux-loong64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-loong64-musl': 1.12.2 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-musl': 1.12.2 + '@unrs/resolver-binding-linux-s390x-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-musl': 1.12.2 + '@unrs/resolver-binding-openharmony-arm64': 1.12.2 + '@unrs/resolver-binding-wasm32-wasi': 1.12.2 + '@unrs/resolver-binding-win32-arm64-msvc': 1.12.2 + '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 + '@unrs/resolver-binding-win32-x64-msvc': 1.12.2 + + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + vite@8.0.14(@types/node@20.19.41)(jiti@2.7.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.15 + rolldown: 1.0.2 + tinyglobby: 0.2.16 + optionalDependencies: + '@types/node': 20.19.41 + fsevents: 2.3.3 + jiti: 2.7.0 + + vitest@4.1.7(@types/node@20.19.41)(jsdom@29.1.1)(vite@8.0.14(@types/node@20.19.41)(jiti@2.7.0)): + dependencies: + '@vitest/expect': 4.1.7 + '@vitest/mocker': 4.1.7(vite@8.0.14(@types/node@20.19.41)(jiti@2.7.0)) + '@vitest/pretty-format': 4.1.7 + '@vitest/runner': 4.1.7 + '@vitest/snapshot': 4.1.7 + '@vitest/spy': 4.1.7 + '@vitest/utils': 4.1.7 + es-module-lexer: 2.1.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.1.0 + tinybench: 2.9.0 + tinyexec: 1.1.2 + tinyglobby: 0.2.16 + tinyrainbow: 3.1.0 + vite: 8.0.14(@types/node@20.19.41)(jiti@2.7.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 20.19.41 + jsdom: 29.1.1 + transitivePeerDependencies: + - msw + + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + + webidl-conversions@8.0.1: {} + + whatwg-mimetype@5.0.0: {} + + whatwg-url@16.0.1: + dependencies: + '@exodus/bytes': 1.15.1 + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.20 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.20: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.9 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.1: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + word-wrap@1.2.5: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.0 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 + + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + + yallist@3.1.1: {} + + zod-validation-error@4.0.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@4.4.3: {} + + zustand@5.0.13(@types/react@18.3.29)(react@18.0.0): + optionalDependencies: + '@types/react': 18.3.29 + react: 18.0.0 diff --git a/apps/web/pnpm-workspace.yaml b/apps/web/pnpm-workspace.yaml new file mode 100644 index 0000000..3d69787 --- /dev/null +++ b/apps/web/pnpm-workspace.yaml @@ -0,0 +1,6 @@ +allowBuilds: + sharp: set this to true or false + unrs-resolver: set this to true or false +ignoredBuiltDependencies: + - sharp + - unrs-resolver diff --git a/apps/web/postcss.config.mjs b/apps/web/postcss.config.mjs new file mode 100644 index 0000000..61e3684 --- /dev/null +++ b/apps/web/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/apps/web/public/file.svg b/apps/web/public/file.svg new file mode 100644 index 0000000..004145c --- /dev/null +++ b/apps/web/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/web/public/globe.svg b/apps/web/public/globe.svg new file mode 100644 index 0000000..567f17b --- /dev/null +++ b/apps/web/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/web/public/next.svg b/apps/web/public/next.svg new file mode 100644 index 0000000..5174b28 --- /dev/null +++ b/apps/web/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/web/public/vercel.svg b/apps/web/public/vercel.svg new file mode 100644 index 0000000..7705396 --- /dev/null +++ b/apps/web/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/web/public/window.svg b/apps/web/public/window.svg new file mode 100644 index 0000000..b2b2a44 --- /dev/null +++ b/apps/web/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/web/src/app/(auth)/layout.tsx b/apps/web/src/app/(auth)/layout.tsx new file mode 100644 index 0000000..c96df6d --- /dev/null +++ b/apps/web/src/app/(auth)/layout.tsx @@ -0,0 +1,11 @@ +export default function AuthLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( +
+ {children} +
+ ) +} diff --git a/apps/web/src/app/(auth)/login/page.tsx b/apps/web/src/app/(auth)/login/page.tsx new file mode 100644 index 0000000..a3c7628 --- /dev/null +++ b/apps/web/src/app/(auth)/login/page.tsx @@ -0,0 +1,353 @@ +'use client'; + +import { useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { z } from 'zod'; +import { useRouter } from 'next/navigation'; +import Link from 'next/link'; +import api from '@/lib/api'; +import { useUserStore } from '@/stores/userStore'; + +type LoginTab = 'password' | 'sms'; + +const passwordLoginSchema = z.object({ + email: z.string().email('Invalid email format').optional().or(z.literal('')), + phone: z.string().regex(/^1[3-9]\d{9}$/, 'Invalid phone format').optional().or(z.literal('')), + password: z.string().min(1, 'Password is required'), +}).refine((data) => { + if (!data.email && !data.phone) { + return { + path: ['email'], + message: 'Email or phone is required', + }; + } + return { path: ['email'], message: '' }; +}); + +const smsLoginSchema = z.object({ + phone: z.string().regex(/^1[3-9]\d{9}$/, 'Invalid phone format'), + code: z.string().regex(/^\d{6}$/, 'Verification code must be 6 digits'), +}); + +type PasswordLoginFormData = z.infer; +type SmsLoginFormData = z.infer; + +export default function LoginPage() { + const router = useRouter(); + const setUser = useUserStore((state) => state.setUser); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + const [activeTab, setActiveTab] = useState('password'); + const [smsSent, setSmsSent] = useState(false); + const [countdown, setCountdown] = useState(0); + + const passwordForm = useForm({ + resolver: zodResolver(passwordLoginSchema), + }); + + const smsForm = useForm({ + resolver: zodResolver(smsLoginSchema), + }); + + const handleSendSms = async () => { + const phone = smsForm.getValues('phone'); + if (!phone || !/^1[3-9]\d{9}$/.test(phone)) { + smsForm.setError('phone', { message: 'Please enter a valid phone number' }); + return; + } + + try { + setError(null); + await api.post('/auth/sms/send', { phone }); + setSmsSent(true); + setCountdown(60); + + const timer = setInterval(() => { + setCountdown((prev) => { + if (prev <= 1) { + clearInterval(timer); + setSmsSent(false); + return 0; + } + return prev - 1; + }); + }, 1000); + } catch (err) { + const error = err as { response?: { data?: { message?: string } } }; + setError(error.response?.data?.message || 'Failed to send verification code'); + } + }; + + const onPasswordSubmit = async (data: PasswordLoginFormData) => { + try { + setError(null); + setLoading(true); + const response = await api.post('/auth/login', { + email: data.email || undefined, + phone: data.phone || undefined, + password: data.password, + }); + + const { accessToken, refreshToken, user } = response.data.data; + localStorage.setItem('token', accessToken); + localStorage.setItem('refreshToken', refreshToken); + setUser(user); + router.push('/dashboard'); + } catch (err) { + const error = err as { response?: { data?: { message?: string } } }; + setError(error.response?.data?.message || 'Login failed'); + } finally { + setLoading(false); + } + }; + + const onSmsSubmit = async (data: SmsLoginFormData) => { + try { + setError(null); + setLoading(true); + const response = await api.post('/auth/sms/login', { + phone: data.phone, + code: data.code, + }); + + const { accessToken, refreshToken, user } = response.data.data; + localStorage.setItem('token', accessToken); + localStorage.setItem('refreshToken', refreshToken); + setUser(user); + router.push('/dashboard'); + } catch (err) { + const error = err as { response?: { data?: { message?: string } } }; + setError(error.response?.data?.message || 'SMS login failed'); + } finally { + setLoading(false); + } + }; + + const handleWechatLogin = async () => { + try { + setError(null); + setLoading(true); + const response = await api.post('/auth/wechat/login', { + code: 'mock-wechat-code', + }); + + const { accessToken, refreshToken, user } = response.data.data; + localStorage.setItem('token', accessToken); + localStorage.setItem('refreshToken', refreshToken); + setUser(user); + router.push('/dashboard'); + } catch (err) { + const error = err as { response?: { data?: { message?: string } } }; + setError(error.response?.data?.message || 'WeChat login failed'); + } finally { + setLoading(false); + } + }; + + const handleAlipayLogin = async () => { + try { + setError(null); + setLoading(true); + const response = await api.post('/auth/alipay/login', { + code: 'mock-alipay-code', + }); + + const { accessToken, refreshToken, user } = response.data.data; + localStorage.setItem('token', accessToken); + localStorage.setItem('refreshToken', refreshToken); + setUser(user); + router.push('/dashboard'); + } catch (err) { + const error = err as { response?: { data?: { message?: string } } }; + setError(error.response?.data?.message || 'Alipay login failed'); + } finally { + setLoading(false); + } + }; + + return ( +
+
+

Sign In

+

Choose your preferred login method

+
+ +
+ + +
+ + {activeTab === 'password' && ( +
+
+ + + {passwordForm.formState.errors.email && ( +

{passwordForm.formState.errors.email.message}

+ )} +
+ +
+ + + {passwordForm.formState.errors.phone && ( +

{passwordForm.formState.errors.phone.message}

+ )} +
+ +
+ + + {passwordForm.formState.errors.password && ( +

{passwordForm.formState.errors.password.message}

+ )} +
+ + {error && ( +
+ {error} +
+ )} + + +
+ )} + + {activeTab === 'sms' && ( +
+
+ + + {smsForm.formState.errors.phone && ( +

{smsForm.formState.errors.phone.message}

+ )} +
+ +
+ +
+ + +
+ {smsForm.formState.errors.code && ( +

{smsForm.formState.errors.code.message}

+ )} +
+ + {error && ( +
+ {error} +
+ )} + + +
+ )} + +
+
+ +
+
+ Or continue with +
+
+ +
+ + +
+ +
+ + Create account + + + Forgot password? + +
+
+ ); +} diff --git a/apps/web/src/app/(auth)/register/page.tsx b/apps/web/src/app/(auth)/register/page.tsx new file mode 100644 index 0000000..abdea9e --- /dev/null +++ b/apps/web/src/app/(auth)/register/page.tsx @@ -0,0 +1,197 @@ +'use client'; + +import { useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { z } from 'zod'; +import { useRouter } from 'next/navigation'; +import Link from 'next/link'; +import api from '@/lib/api'; +import { useUserStore } from '@/stores/userStore'; + +const registerSchema = z.object({ + email: z.string().email('Invalid email format').optional().or(z.literal('')), + phone: z.string().regex(/^1[3-9]\d{9}$/, 'Invalid phone format').optional().or(z.literal('')), + username: z.string().min(3, 'Username must be at least 3 characters'), + password: z.string().min(6, 'Password must be at least 6 characters'), + confirmPassword: z.string(), + agreeTerms: z.boolean().refine((val) => val === true, { + message: 'You must agree to the terms and conditions', + }), +}).refine((data) => { + if (!data.email && !data.phone) { + return { + path: ['email'], + message: 'Email or phone is required', + }; + } + if (data.password !== data.confirmPassword) { + return { + path: ['confirmPassword'], + message: 'Passwords do not match', + }; + } + return { path: ['email'], message: '' }; +}); + +type RegisterFormData = z.infer; + +export default function RegisterPage() { + const router = useRouter(); + const setUser = useUserStore((state) => state.setUser); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(false); + + const { + register, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(registerSchema), + defaultValues: { + agreeTerms: false, + }, + }); + + const onSubmit = async (data: RegisterFormData) => { + try { + setError(null); + setLoading(true); + const response = await api.post('/auth/register', { + email: data.email || undefined, + phone: data.phone || undefined, + username: data.username, + password: data.password, + }); + + const { accessToken, refreshToken, user } = response.data.data; + localStorage.setItem('token', accessToken); + localStorage.setItem('refreshToken', refreshToken); + setUser(user); + router.push('/dashboard'); + } catch (err) { + const error = err as { response?: { data?: { message?: string } } }; + setError(error.response?.data?.message || 'Registration failed'); + } finally { + setLoading(false); + } + }; + + return ( +
+
+

Create Account

+

Enter your details to get started

+
+ +
+
+ + + {errors.email && ( +

{errors.email.message}

+ )} +
+ +
+ + + {errors.phone && ( +

{errors.phone.message}

+ )} +
+ +
+ + + {errors.username && ( +

{errors.username.message}

+ )} +
+ +
+ + + {errors.password && ( +

{errors.password.message}

+ )} +
+ +
+ + + {errors.confirmPassword && ( +

{errors.confirmPassword.message}

+ )} +
+ +
+ + +
+ {errors.agreeTerms && ( +

{errors.agreeTerms.message}

+ )} + + {error && ( +
+ {error} +
+ )} + + +
+ +
+ Already have an account?{' '} + + Sign in + +
+
+ ); +} diff --git a/apps/web/src/app/(dashboard)/admin/permissions/page.tsx b/apps/web/src/app/(dashboard)/admin/permissions/page.tsx new file mode 100644 index 0000000..6871fa4 --- /dev/null +++ b/apps/web/src/app/(dashboard)/admin/permissions/page.tsx @@ -0,0 +1,311 @@ +'use client'; + +import { useState, useEffect } from 'react'; +import api from '@/lib/api'; + +interface Permission { + id: string; + name: string; + description: string | null; + resource: string; + action: string; + createdAt: Date; + updatedAt: Date; +} + +interface Pagination { + page: number; + limit: number; + total: number; + totalPages: number; +} + +export default function PermissionsManagementPage() { + const [permissions, setPermissions] = useState([]); + const [pagination, setPagination] = useState({ + page: 1, + limit: 50, + total: 0, + totalPages: 0, + }); + const [resourceFilter, setResourceFilter] = useState(''); + const [loading, setLoading] = useState(false); + const [showCreateModal, setShowCreateModal] = useState(false); + const [editingPermission, setEditingPermission] = useState(null); + const [formData, setFormData] = useState({ + name: '', + description: '', + resource: '', + action: '', + }); + + useEffect(() => { + fetchPermissions(); + }, [pagination.page, resourceFilter]); + + const fetchPermissions = async () => { + try { + setLoading(true); + const response = await api.get('/permissions', { + params: { + page: pagination.page, + limit: pagination.limit, + resource: resourceFilter || undefined, + }, + }); + setPermissions(response.data.data.permissions); + setPagination(response.data.data.pagination); + } catch (err) { + console.error('Failed to fetch permissions:', err); + } finally { + setLoading(false); + } + }; + + const handleCreate = async () => { + try { + await api.post('/permissions', formData); + setShowCreateModal(false); + setFormData({ name: '', description: '', resource: '', action: '' }); + fetchPermissions(); + } catch (err) { + console.error('Failed to create permission:', err); + alert('Failed to create permission'); + } + }; + + const handleUpdate = async () => { + if (!editingPermission) return; + + try { + await api.put(`/permissions/${editingPermission.id}`, formData); + setEditingPermission(null); + setFormData({ name: '', description: '', resource: '', action: '' }); + fetchPermissions(); + } catch (err) { + console.error('Failed to update permission:', err); + alert('Failed to update permission'); + } + }; + + const handleDelete = async (permissionId: string) => { + if (!confirm('Are you sure you want to delete this permission?')) return; + + try { + await api.delete(`/permissions/${permissionId}`); + fetchPermissions(); + } catch (err) { + console.error('Failed to delete permission:', err); + alert('Failed to delete permission'); + } + }; + + const openEditModal = (permission: Permission) => { + setEditingPermission(permission); + setFormData({ + name: permission.name, + description: permission.description || '', + resource: permission.resource, + action: permission.action, + }); + }; + + const resources = Array.from(new Set(permissions.map((p) => p.resource))); + + return ( +
+
+

Permission Management

+ +
+ +
+ +
+ +
+ + + + + + + + + + + + {loading ? ( + + + + ) : permissions.length === 0 ? ( + + + + ) : ( + permissions.map((permission) => ( + + + + + + + + )) + )} + +
+ Name + + Resource + + Action + + Description + + Actions +
+ Loading... +
+ No permissions found +
{permission.name} + + {permission.resource} + + + + {permission.action} + + {permission.description || '-'} + + +
+
+ + {pagination.totalPages > 1 && ( +
+

+ Showing {(pagination.page - 1) * pagination.limit + 1} to{' '} + {Math.min(pagination.page * pagination.limit, pagination.total)} of {pagination.total}{' '} + permissions +

+
+ + + Page {pagination.page} of {pagination.totalPages} + + +
+
+ )} + + {(showCreateModal || editingPermission) && ( +
+
+

+ {editingPermission ? 'Edit Permission' : 'Create Permission'} +

+
+
+ + setFormData({ ...formData, name: e.target.value })} + className="w-full px-3 py-2 border rounded-md" + placeholder="e.g., user:create" + /> +
+
+ + setFormData({ ...formData, resource: e.target.value })} + className="w-full px-3 py-2 border rounded-md" + placeholder="e.g., user, file, role" + /> +
+
+ + setFormData({ ...formData, action: e.target.value })} + className="w-full px-3 py-2 border rounded-md" + placeholder="e.g., create, read, update, delete" + /> +
+
+ +