secondme-nextjs

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SecondMe Next.js 项目生成

SecondMe Next.js Project Generation

基于
/secondme-init
的配置和
/secondme-prd
的需求定义,生成完整的 Next.js 项目。

Generate a complete Next.js project based on the configuration from
/secondme-init
and requirement definitions from
/secondme-prd
.

前置条件检查

Precondition Checks

1. 检查 state.json

1. Check state.json

首先检查
.secondme/state.json
是否存在:
  • 不存在 → 提示:
    请先运行 /secondme-init 初始化项目配置
  • 存在 → 继续
First check if
.secondme/state.json
exists:
  • Does not exist → Prompt:
    Please run /secondme-init to initialize project configuration first
  • Exists → Continue

2. 检查执行模式

2. Check Execution Mode

检查参数是否包含
--quick
快速模式 (--quick)
  • 跳过 stage 检查
  • 使用默认 PRD 配置
  • 直接开始生成项目
标准模式
  • 检查
    stage >= "prd"
  • 如果
    stage == "init"
    → 提示:
    请先运行 /secondme-prd 定义需求,或使用 /secondme-nextjs --quick 快速生成
  • 如果
    stage >= "prd"
    → 继续

Check if the parameters include
--quick
:
Fast Mode (--quick):
  • Skip stage checks
  • Use default PRD configuration
  • Start project generation directly
Standard Mode:
  • Check if
    stage >= "prd"
  • If
    stage == "init"
    → Prompt:
    Please run /secondme-prd to define requirements first, or use /secondme-nextjs --quick for fast generation
  • If
    stage >= "prd"
    → Continue

读取配置

Read Configuration

.secondme/state.json
读取:
javascript
const state = {
  app_name: "secondme-tinder",  // 应用名称
  modules: ["auth", "chat", "profile"],  // 已选模块
  config: {
    client_id: "71658da7-659c-414a-abdf-cb6472037fc2",
    client_secret: "xxx",
    redirect_uri: "http://localhost:3000/api/auth/callback",
    redirect_uris: [...],
    database_url: "postgresql://...",
    allowed_scopes: [...]
  },
  api: {
    base_url: "https://app.mindos.com/gate/lab",
    oauth_url: "https://go.second.me/oauth/",
    token_endpoint: "...",
    access_token_ttl: 7200,
    refresh_token_ttl: 2592000
  },
  docs: {
    quickstart: "https://develop-docs.second.me/zh/docs",
    oauth2: "...",
    api_reference: "...",
    errors: "..."
  },
  prd: {
    summary: "应用概要",
    features: ["功能1", "功能2"],
    design_preference: "简约现代"
  }
}
重要: 所有 API 端点、文档链接均从
state.api
state.docs
读取,不要硬编码。

Read from
.secondme/state.json
:
javascript
const state = {
  app_name: "secondme-tinder",  // Application name
  modules: ["auth", "chat", "profile"],  // Selected modules
  config: {
    client_id: "71658da7-659c-414a-abdf-cb6472037fc2",
    client_secret: "xxx",
    redirect_uri: "http://localhost:3000/api/auth/callback",
    redirect_uris: [...],
    database_url: "postgresql://...",
    allowed_scopes: [...]
  },
  api: {
    base_url: "https://app.mindos.com/gate/lab",
    oauth_url: "https://go.second.me/oauth/",
    token_endpoint: "...",
    access_token_ttl: 7200,
    refresh_token_ttl: 2592000
  },
  docs: {
    quickstart: "https://develop-docs.second.me/zh/docs",
    oauth2: "...",
    api_reference: "...",
    errors: "..."
  },
  prd: {
    summary: "Application overview",
    features: ["Feature 1", "Feature 2"],
    design_preference: "Minimalist modern"
  }
}
Important: All API endpoints and document links are read from
state.api
and
state.docs
, do not hardcode.

前端设计要求

Frontend Design Requirements

重要: 在构建前端界面时,必须使用
frontend-design:frontend-design
skill 来生成高质量的 UI 组件。
设计原则:
  • 亮色主题:仅使用亮色/浅色主题,不使用暗色/深色主题
  • 简约优雅:遵循极简设计理念,减少视觉噪音
  • 产品特性驱动:UI 设计应紧密结合要实现的功能特性
  • 现代感:采用当下流行的设计趋势,避免过时的 UI 模式
  • 一致性:保持整体视觉风格统一
  • 响应式:适配各种屏幕尺寸
  • 中文界面:所有用户可见的文字(按钮、提示、标签、说明等)必须使用中文
  • 稳定优先:避免复杂动画效果,仅使用简单的过渡动画(如 hover、fade),确保界面稳定流畅

Important: When building frontend interfaces, you must use the
frontend-design:frontend-design
skill to generate high-quality UI components.
Design Principles:
  • Light Theme: Only use light/bright themes, do not use dark themes
  • Minimalist & Elegant: Follow minimalist design concepts, reduce visual noise
  • Product Feature-Driven: UI design should closely align with the functional features to be implemented
  • Modern: Adopt current popular design trends, avoid outdated UI patterns
  • Consistency: Maintain a unified overall visual style
  • Responsive: Adapt to various screen sizes
  • Chinese Interface: All user-visible text (buttons, prompts, labels, instructions, etc.) must be in Chinese
  • Stability First: Avoid complex animation effects, only use simple transition animations (such as hover, fade) to ensure stable and smooth interface

项目生成流程

Project Generation Process

1. 初始化 Next.js 项目

1. Initialize Next.js Project

在当前目录直接初始化 Next.js 项目:
bash
npx create-next-app@latest . --typescript --tailwind --app --src-dir --import-alias "@/*" --yes
Initialize the Next.js project directly in the current directory:
bash
npx create-next-app@latest . --typescript --tailwind --app --src-dir --import-alias "@/*" --yes

2. 安装依赖

2. Install Dependencies

bash
npm install prisma @prisma/client
npx prisma init
bash
npm install prisma @prisma/client
npx prisma init

3. 生成 .env.local

3. Generate .env.local

state.config
state.api
生成环境变量:
env
undefined
Generate environment variables from
state.config
and
state.api
:
env
undefined

SecondMe OAuth2 配置

SecondMe OAuth2 Configuration

SECONDME_CLIENT_ID=[config.client_id] SECONDME_CLIENT_SECRET=[config.client_secret] SECONDME_REDIRECT_URI=[config.redirect_uri]
SECONDME_CLIENT_ID=[config.client_id] SECONDME_CLIENT_SECRET=[config.client_secret] SECONDME_REDIRECT_URI=[config.redirect_uri]

数据库

Database

DATABASE_URL=[config.database_url]
DATABASE_URL=[config.database_url]

SecondMe API(从 state.api 读取)

SecondMe API (read from state.api)

SECONDME_API_BASE_URL=[api.base_url] SECONDME_OAUTH_URL=[api.oauth_url] SECONDME_TOKEN_ENDPOINT=[api.token_endpoint]
undefined
SECONDME_API_BASE_URL=[api.base_url] SECONDME_OAUTH_URL=[api.oauth_url] SECONDME_TOKEN_ENDPOINT=[api.token_endpoint]
undefined

4. 生成 Prisma Schema

4. Generate Prisma Schema

根据已选模块动态生成
prisma/schema.prisma
Dynamically generate
prisma/schema.prisma
based on selected modules.

auth 模块(必有)- User 表必须包含的字段

auth Module (Mandatory) - Required Fields for User Table

User 表必须包含 Token 相关字段用于存储和刷新用户凭证:
prisma
model User {
  id                String   @id @default(cuid())
  secondmeUserId    String   @unique @map("secondme_user_id")
  accessToken       String   @map("access_token")
  refreshToken      String   @map("refresh_token")
  tokenExpiresAt    DateTime @map("token_expires_at")
  createdAt         DateTime @default(now()) @map("created_at")
  updatedAt         DateTime @updatedAt @map("updated_at")
  // 其他字段根据模块需求自行添加

  @@map("users")
}
The User table must include Token-related fields for storing and refreshing user credentials:
prisma
model User {
  id                String   @id @default(cuid())
  secondmeUserId    String   @unique @map("secondme_user_id")
  accessToken       String   @map("access_token")
  refreshToken      String   @map("refresh_token")
  tokenExpiresAt    DateTime @map("token_expires_at")
  createdAt         DateTime @default(now()) @map("created_at")
  updatedAt         DateTime @updatedAt @map("updated_at")
  // Add other fields according to module requirements
}

其他模块

Other Modules

根据已选模块(profile、chat、note)的实际需求,自行设计相应的数据库表结构和关联关系。
Design corresponding database table structures and relationships according to the actual requirements of selected modules (profile, chat, note).

5. 生成代码

5. Generate Code

根据已选模块生成对应代码:
Generate corresponding code based on selected modules:

auth 模块

auth Module

文件说明
src/app/api/auth/login/route.ts
OAuth 登录跳转
src/app/api/auth/callback/route.ts
OAuth 回调处理
src/app/api/auth/logout/route.ts
登出处理
src/lib/auth.ts
认证工具函数
src/components/LoginButton.tsx
登录按钮组件
FileDescription
src/app/api/auth/login/route.ts
OAuth login redirect
src/app/api/auth/callback/route.ts
OAuth callback handling
src/app/api/auth/logout/route.ts
Logout handling
src/lib/auth.ts
Authentication utility functions
src/components/LoginButton.tsx
Login button component

profile 模块

profile Module

文件说明
src/app/api/user/info/route.ts
获取用户信息
src/app/api/user/shades/route.ts
获取兴趣标签
src/components/UserProfile.tsx
用户资料组件
FileDescription
src/app/api/user/info/route.ts
Get user information
src/app/api/user/shades/route.ts
Get interest tags
src/components/UserProfile.tsx
User profile component

chat 模块

chat Module

文件说明
src/app/api/chat/route.ts
流式聊天 API
src/app/api/sessions/route.ts
会话列表 API
src/components/ChatWindow.tsx
聊天界面组件
FileDescription
src/app/api/chat/route.ts
Streaming chat API
src/app/api/sessions/route.ts
Session list API
src/components/ChatWindow.tsx
Chat interface component

act 模块

act Module

文件说明
src/app/api/act/route.ts
流式动作判断 API(结构化 JSON 输出)
src/lib/act.ts
Act API 工具函数(发送 actionControl、解析 SSE JSON 结果)
FileDescription
src/app/api/act/route.ts
Streaming action judgment API (structured JSON output)
src/lib/act.ts
Act API utility functions (send actionControl, parse SSE JSON results)

note 模块

note Module

文件说明
src/app/api/note/route.ts
添加笔记 API
FileDescription
src/app/api/note/route.ts
Add note API

6. 更新 state.json

6. Update state.json

json
{
  "stage": "ready",
  ...
}

json
{
  "stage": "ready",
  ...
}

技术栈

Technology Stack

  • 框架: Next.js 14+ (App Router)
  • 语言: TypeScript
  • 样式: Tailwind CSS
  • 数据库 ORM: Prisma
  • 前端设计: 使用
    frontend-design:frontend-design
    skill 生成
  • API 调用: fetch
  • 状态管理: React hooks
  • 运行端口: 必须使用 3000 端口

  • Framework: Next.js 14+ (App Router)
  • Language: TypeScript
  • Styling: Tailwind CSS
  • Database ORM: Prisma
  • Frontend Design: Generated using
    frontend-design:frontend-design
    skill
  • API Calls: fetch
  • State Management: React hooks
  • Running Port: Must use port 3000

常见问题与注意事项

Common Issues & Notes

CSS @import 顺序问题

CSS @import Order Issue

问题:
globals.css
中使用
@import url(...)
引入 Google Fonts 会导致构建失败。
错误信息:
@import rules must precede all rules aside from @charset and @layer statements
原因: Tailwind CSS 的
@import "tailwindcss"
展开后生成大量规则,导致后续的
@import url(...)
不再是第一个。
正确做法:
  1. 使用
    <link>
    标签(推荐):
    layout.tsx
    中引入
    tsx
    <head>
      <link rel="preconnect" href="https://fonts.googleapis.com" />
      <link href="https://fonts.googleapis.com/css2?family=..." rel="stylesheet" />
    </head>
  2. 使用
    next/font
    (最佳实践):
    tsx
    import { Noto_Sans_SC } from 'next/font/google'
    const notoSans = Noto_Sans_SC({ subsets: ['latin'], weight: ['400', '500'] })
Problem: Using
@import url(...)
to import Google Fonts in
globals.css
causes build failure.
Error Message:
@import rules must precede all rules aside from @charset and @layer statements
Cause: Tailwind CSS's
@import "tailwindcss"
expands to generate a large number of rules, causing subsequent
@import url(...)
to no longer be the first.
Correct Approach:
  1. Use
    <link>
    tag (Recommended)
    : Import in
    layout.tsx
    tsx
    <head>
      <link rel="preconnect" href="https://fonts.googleapis.com" />
      <link href="https://fonts.googleapis.com/css2?family=..." rel="stylesheet" />
    </head>
  2. Use
    next/font
    (Best Practice)
    :
    tsx
    import { Noto_Sans_SC } from 'next/font/google'
    const notoSans = Noto_Sans_SC({ subsets: ['latin'], weight: ['400', '500'] })

构建验证

Build Validation

重要: 每次完成代码修改后,必须运行以下命令验证构建:
bash
npm run build
特别关注:
  • CSS 解析错误
  • TypeScript 类型错误
  • 导入路径错误
Important: After each code modification, you must run the following command to verify the build:
bash
npm run build
Pay special attention to:
  • CSS parsing errors
  • TypeScript type errors
  • Import path errors

WebView OAuth 认证问题

WebView OAuth Authentication Issue

问题: 在 WebView 环境中(如移动端 App 内嵌页面、微信小程序等),OAuth state 验证可能失败,因为 WebView 与系统浏览器之间的存储不共享。
解决方案: 使用宽松的 state 验证,验证失败时记录警告但继续处理登录流程。
tsx
// 之前:验证失败直接拒绝
if (!isValidState) {
  return NextResponse.redirect('/?error=invalid_state');
}

// 之后:验证失败记录警告,继续处理
if (!isValidState) {
  console.warn('OAuth state 验证失败,可能是跨 WebView 场景');
  // 继续处理,不阻止登录
}
注意: 这种方式降低了 CSRF 防护,仅建议在可信的 WebView 环境中使用

Problem: In WebView environments (such as mobile app embedded pages, WeChat Mini Programs, etc.), OAuth state verification may fail because storage is not shared between WebView and system browsers.
Solution: Use relaxed state verification, record a warning but continue with the login process when verification fails.
tsx
// Before: Reject directly if verification fails
if (!isValidState) {
  return NextResponse.redirect('/?error=invalid_state');
}

// After: Record warning if verification fails, continue processing
if (!isValidState) {
  console.warn('OAuth state verification failed, possibly a cross-WebView scenario');
  // Continue processing, do not block login
}
Note: This method reduces CSRF protection, and is only recommended for use in trusted WebView environments

输出结果

Output Result

✅ Next.js 项目已生成!

已生成模块: auth, chat, profile
数据库: PostgreSQL

启动步骤:
1. npm install
2. npx prisma db push
3. npm run dev

项目将在 http://localhost:3000 启动

✅ Next.js project generated successfully!

Generated modules: auth, chat, profile
Database: PostgreSQL

Startup steps:
1. npm install
2. npx prisma db push
3. npm run dev

The project will start at http://localhost:3000

API 响应格式

API Response Format

重要:所有 SecondMe API 响应都遵循统一格式:
json
{
  "code": 0,
  "data": { ... }
}
本地路由与上游 API 的关系: Next.js 本地路由(如
/api/secondme/user/shades
)作为代理层, 将请求转发到上游 SecondMe API(
{state.api.base_url}/api/secondme/...
),并透传上游的响应格式。 前端代码调用本地路由即可,无需直接访问上游 API。
前端代码必须正确提取数据:
typescript
// ✅ 正确写法(调用 Next.js 本地路由,响应格式与上游一致)
const response = await fetch('/api/secondme/user/shades');
const result = await response.json();
if (result.code === 0) {
  const shades = result.data.shades;
  shades.map(item => ...)
}

Important: All SecondMe API responses follow a unified format:
json
{
  "code": 0,
  "data": { ... }
}
Relationship between local routes and upstream APIs: Next.js local routes (such as
/api/secondme/user/shades
) act as a proxy layer, forwarding requests to the upstream SecondMe API (
{state.api.base_url}/api/secondme/...
), and pass through the upstream response format. Frontend code only needs to call local routes, no need to access upstream APIs directly.
Frontend code must extract data correctly:
typescript
// ✅ Correct approach (call Next.js local route, response format is the same as upstream)
const response = await fetch('/api/secondme/user/shades');
const result = await response.json();
if (result.code === 0) {
  const shades = result.data.shades;
  shades.map(item => ...)
}

官方文档

Official Documentation

state.docs
读取文档链接:
文档配置键
快速入门
docs.quickstart
OAuth2 指南
docs.oauth2
API 参考
docs.api_reference
错误码
docs.errors
Read document links from
state.docs
:
DocumentConfiguration Key
Quickstart
docs.quickstart
OAuth2 Guide
docs.oauth2
API Reference
docs.api_reference
Error Codes
docs.errors