first code

This commit is contained in:
程广 2025-06-09 17:58:54 +08:00
commit 16a04dbb27
25 changed files with 2441 additions and 0 deletions

4
backend/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
dist
.env
node_modules
*.log

1990
backend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

40
backend/package.json Normal file
View File

@ -0,0 +1,40 @@
{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "rimraf dist && tsc",
"start": "npm run build && node dist/main.js",
"dev": "ts-node -r tsconfig-paths/register src/main.ts",
"typeorm": "typeorm-ts-node-commonjs -d dist/data-source.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@nestjs/common": "^9.4.3",
"@nestjs/core": "^9.4.3",
"@nestjs/passport": "^11.0.5",
"@nestjs/platform-express": "^9.4.3",
"@nestjs/typeorm": "^11.0.0",
"bcrypt": "^6.0.0",
"class-validator": "^0.14.2",
"jsonwebtoken": "^9.0.2",
"passport": "^0.4.1",
"passport-jwt": "^4.0.1",
"reflect-metadata": "^0.1.14",
"rxjs": "^7.8.2",
"typeorm": "^0.3.24",
"uid": "^2.0.2"
},
"devDependencies": {
"@types/bcrypt": "^5.0.0",
"@types/passport-jwt": "^4.0.1",
"rimraf": "^6.0.1",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"typescript": "^5.8.3"
}
}

View File

@ -0,0 +1,18 @@
import { Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm';
import { Workspace } from '../workspace/workspace.entity';
@Entity()
export class AiConfig {
@PrimaryGeneratedColumn()
id!: number;
@Column()
apiUrl!: string;
@Column()
apiKey!: string;
@OneToOne(() => Workspace)
@JoinColumn()
workspace!: Workspace;
}

25
backend/src/app.module.ts Normal file
View File

@ -0,0 +1,25 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthModule } from './auth/auth.module';
import { User } from './user/user.entity';
import { Workspace } from './workspace/workspace.entity';
import { Project } from './project/project.entity';
import { AiConfig } from './ai/ai-config.entity';
import { PluginConfig } from './plugins/plugin-config.entity';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'postgres',
password: 'postgres',
database: 'aiframe',
entities: [User, Workspace, Project, AiConfig, PluginConfig],
synchronize: true,
}),
AuthModule,
],
})
export class AppModule {}

View File

@ -0,0 +1,19 @@
import { Body, Controller, Post } from '@nestjs/common';
import { AuthService } from './auth.service';
import { CreateUserDto } from './dto/create-user.dto';
import { LoginDto } from './dto/login.dto';
@Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
@Post('register')
register(@Body() createUserDto: CreateUserDto) {
return this.authService.register(createUserDto);
}
@Post('login')
login(@Body() loginDto: LoginDto) {
return this.authService.login(loginDto);
}
}

View File

@ -0,0 +1,20 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from '../user/user.entity';
import { UserService } from '../user/user.service';
import { UserRepository } from '../user/user.repository';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { JwtStrategy } from './jwt.strategy';
@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [AuthController],
providers: [
AuthService,
UserService,
UserRepository,
JwtStrategy,
],
})
export class AuthModule {}

View File

@ -0,0 +1,40 @@
import { Injectable } from '@nestjs/common';
import { UserService } from '../user/user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { LoginDto } from './dto/login.dto';
import * as bcrypt from 'bcrypt';
@Injectable()
export class AuthService {
constructor(private readonly userService: UserService) {}
async register(createUserDto: CreateUserDto) {
const hashedPassword = await bcrypt.hash(createUserDto.password, 10);
return this.userService.create({
...createUserDto,
password: hashedPassword,
});
}
async login(loginDto: LoginDto) {
const user = await this.userService.findByEmail(loginDto.email);
if (!user) {
throw new Error('User not found');
}
const isPasswordValid = await bcrypt.compare(loginDto.password, user.password);
if (!isPasswordValid) {
throw new Error('Invalid credentials');
}
return {
accessToken: this.generateJwtToken(user),
};
}
private generateJwtToken(user: any): string {
// 实际实现应使用jsonwebtoken库生成JWT
// 这里仅作为示例返回模拟令牌
return `mock-jwt-token-for-${user.email}`;
}
}

View File

@ -0,0 +1,10 @@
import { IsEmail, IsString, MinLength } from 'class-validator';
export class CreateUserDto {
@IsEmail()
email!: string;
@IsString()
@MinLength(6)
password!: string;
}

View File

@ -0,0 +1,10 @@
import { IsEmail, IsString, MinLength } from 'class-validator';
export class LoginDto {
@IsEmail()
email!: string;
@IsString()
@MinLength(6)
password!: string;
}

View File

@ -0,0 +1,3 @@
export * from './dto/create-user.dto';
export * from './dto/login.dto';
export * from './jwt.strategy';

View File

@ -0,0 +1,18 @@
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: process.env.JWT_SECRET || 'secret_key',
});
}
async validate(payload: any) {
return { userId: payload.sub, email: payload.email };
}
}

View File

@ -0,0 +1,17 @@
import { DataSource } from 'typeorm';
import { User } from './user/user.entity';
import { Workspace } from './workspace/workspace.entity';
import { Project } from './project/project.entity';
import { AiConfig } from './ai/ai-config.entity';
import { PluginConfig } from './plugins/plugin-config.entity';
export const AppDataSource = new DataSource({
type: 'postgres',
host: process.env.POSTGRES_HOST || 'localhost',
port: parseInt(process.env.POSTGRES_PORT) || 5432,
username: process.env.POSTGRES_USER || 'postgres',
password: process.env.POSTGRES_PASSWORD || 'postgres',
database: process.env.POSTGRES_DB || 'aiframe',
entities: [User, Workspace, Project, AiConfig, PluginConfig],
synchronize: true,
});

8
backend/src/main.ts Normal file
View File

@ -0,0 +1,8 @@
import { NestFactory } from '@nestjs/core'
import { AppModule } from './app.module'
import 'reflect-metadata'
async function bootstrap () {
const app = await NestFactory.create(AppModule)
await app.listen(3000)
}
bootstrap()

View File

@ -0,0 +1,18 @@
import { Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm';
import { Workspace } from '../workspace/workspace.entity';
@Entity()
export class PluginConfig {
@PrimaryGeneratedColumn()
id!: number;
@Column()
pluginId!: string;
@Column({ type: 'json', nullable: true })
settings!: Record<string, any>;
@OneToOne(() => Workspace)
@JoinColumn()
workspace!: Workspace;
}

View File

@ -0,0 +1,20 @@
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm';
import { Workspace } from '../workspace/workspace.entity';
@Entity()
export class Project {
@PrimaryGeneratedColumn()
id!: number;
@Column()
name!: string;
@Column({ type: 'text', nullable: true })
description!: string;
@ManyToOne(() => Workspace, (workspace: Workspace) => workspace.projects)
workspace!: Workspace;
@Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
createdAt!: Date;
}

View File

@ -0,0 +1,18 @@
import { Entity, Column, OneToOne, JoinColumn } from 'typeorm';
import { Workspace } from '../workspace/workspace.entity';
@Entity()
export class User {
@Column()
id!: number;
@Column({ unique: true })
email!: string;
@Column()
password!: string;
@OneToOne(() => Workspace)
@JoinColumn()
workspace!: Workspace;
}

View File

@ -0,0 +1,7 @@
import { EntityRepository, Repository } from 'typeorm';
import { User } from './user.entity';
@EntityRepository(User)
export class UserRepository extends Repository<User> {
// 可以添加自定义查询方法
}

View File

@ -0,0 +1,15 @@
import { Injectable } from '@nestjs/common';
import { UserRepository } from './user.repository';
@Injectable()
export class UserService {
constructor(private readonly userRepository: UserRepository) {}
create(createUserDto: any) {
return this.userRepository.create(createUserDto);
}
findByEmail(email: string) {
return this.userRepository.findOne({ where: { email } });
}
}

View File

@ -0,0 +1,19 @@
import { Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn, OneToMany } from 'typeorm';
import { User } from '../user/user.entity';
import { Project } from '../project/project.entity';
@Entity()
export class Workspace {
@PrimaryGeneratedColumn()
id!: number;
@Column()
name!: string;
@OneToOne(() => User)
@JoinColumn()
user!: User;
@OneToMany(() => Project, (project: Project) => project.workspace)
projects!: Project[];
}

20
backend/tsconfig.json Normal file
View File

@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
"strict": true,
"outDir": "./dist",
"rootDir": "./src",
"esModuleInterop": true,
"skipLibCheck": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"resolveJsonModule": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"paths": {
"@src/*": ["./src/*"]
}
},
"include": ["src/**/*"]
}

27
docs/API_SPEC.md Normal file
View File

@ -0,0 +1,27 @@
# API接口规范
## 用户认证
- `POST /auth/register` - 用户注册
- 请求体:{email: string, password: string}
- 响应:{accessToken: string}
- `POST /auth/login` - 用户登录
- 请求体:{email: string, password: string}
- 响应:{accessToken: string}
## 工作区管理
- `GET /workspace` - 获取用户工作区
- `POST /workspace` - 创建工作区
## AI服务配置
- `GET /ai/config` - 获取AI配置
- `POST /ai/config` - 保存AI配置
## 插件管理
- `GET /plugins` - 获取可用插件
- `POST /plugins/install` - 安装插件
## 项目管理
- `GET /projects` - 获取项目列表
- `POST /projects` - 创建新项目
- `GET /projects/:id` - 获取项目详情

23
docs/ARCHITECTURE.md Normal file
View File

@ -0,0 +1,23 @@
# 系统架构设计
## 技术栈
- 前端Angular 16 + Material Design
- 后端NestJS + TypeORM + JWT
- 数据库PostgreSQL
- 文件存储MinIO
- 实时通信WebSocket
## 模块划分
1. 用户认证模块
2. 工作区管理模块
3. AI服务集成模块
4. 插件管理模块
5. 项目管理模块
## 数据模型关系
```mermaid
graph TD
User --> Workspace
Workspace --> Project
Workspace --> AiConfig
Workspace --> PluginConfig

36
docs/DATABASE.md Normal file
View File

@ -0,0 +1,36 @@
# 数据库设计
## 用户表 (User)
| 字段名 | 类型 | 描述 |
|-------|------|------|
| id | integer | 主键 |
| email | string | 邮箱(唯一) |
| password | string | 密码 |
## 工作区表 (Workspace)
| 字段名 | 类型 | 描述 |
|-------|------|------|
| id | integer | 主键 |
| name | string | 工作区名称 |
## 项目表 (Project)
| 字段名 | 类型 | 描述 |
|-------|------|------|
| id | integer | 主键 |
| name | string | 项目名称 |
| description | text | 项目描述 |
| createdAt | timestamp | 创建时间 |
## AI配置表 (AiConfig)
| 字段名 | 类型 | 描述 |
|-------|------|------|
| id | integer | 主键 |
| apiUrl | string | API地址 |
| apiKey | string | API密钥 |
## 插件配置表 (PluginConfig)
| 字段名 | 类型 | 描述 |
|-------|------|------|
| id | integer | 主键 |
| pluginId | string | 插件ID |
| settings | json | 插件配置 |

16
require.md Normal file
View File

@ -0,0 +1,16 @@
## role
你是一个软件开发专家,专长领域是:
- Angular前端开发
- Node.js后端开发
- AI与人工智能开发
- 机器学习开发
我现在需要你完成一个项目,项目需求如下:
1. 每个用户有独立的工作区
2. 可以通过用户提供的API地址和APIkey连接到指定的AI服务
3. 可以安装调用指定用户指定的MCP插件
4. 用户可以在工作区中创建新的项目,并保存项目
5. 用户可以通过对话或工作区中的需求文件为AI提供项目需求。
6. AI可以通过MCP插件完成用户需求的功能。
7. 提供界面供用户浏览,下载生成的代码