Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions backend/src/build-system/__tests__/mock/MockBuilderContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@
return this.virtualDirectory.parseJsonStructure(jsonContent);
}

execute(): Promise<void> {
return Promise.resolve(); // Mock a resolved promise for execution
execute(): Promise<string> {
return Promise.resolve(''); // Mock a resolved promise for execution
Comment on lines +88 to +89
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Return value should match parent class implementation.

The mock implementation should return a valid project UUID to match the parent class behavior, instead of an empty string.

Apply this diff to align with the parent class:

-  execute(): Promise<string> {
-    return Promise.resolve(''); // Mock a resolved promise for execution
+  execute(): Promise<string> {
+    return Promise.resolve(this.getGlobalContext('projectUUID') || ''); // Return the project UUID from global context
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
execute(): Promise<string> {
return Promise.resolve(''); // Mock a resolved promise for execution
execute(): Promise<string> {
return Promise.resolve(this.getGlobalContext('projectUUID') || ''); // Return the project UUID from global context

}

getNodeData(handler: any): any {
Expand All @@ -103,7 +103,7 @@
const absolutePath = resolve(filePath); // Resolve the file path
return readFileSync(absolutePath, 'utf-8'); // Read the file content
} catch (err) {
console.error(`Error reading file at ${filePath}:`, err);

Check warning on line 106 in backend/src/build-system/__tests__/mock/MockBuilderContext.ts

View workflow job for this annotation

GitHub Actions / autofix

Unexpected console statement
return ''; // Return an empty string if file read fails
}
}
Expand Down
16 changes: 9 additions & 7 deletions backend/src/build-system/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,20 +97,21 @@ export class BuilderContext {
this.handlerManager = BuildHandlerManager.getInstance();
this.model = OpenAIModelProvider.getInstance();
this.monitor = BuildMonitor.getInstance();
this.logger = new Logger(`builder-context-${id}`);
this.logger = new Logger(`builder-context-${id ?? sequence.id}`);
this.virtualDirectory = new VirtualDirectory();

// Initialize global context with default project values
this.globalContext.set('projectName', sequence.name);
this.globalContext.set('description', sequence.description || '');
this.globalContext.set('platform', 'web'); // Default platform is 'web'
this.globalContext.set('databaseType', sequence.databaseType || 'SQLite');
this.globalContext.set(
'projectUUID',
new Date().toISOString().slice(0, 18).replaceAll(/:/g, '-') +

const projectUUIDPath =
new Date().toISOString().slice(0, 18).replaceAll(/:/g, '-') +
'-' +
uuidv4(),
);
uuidv4();
this.globalContext.set('projectUUID', projectUUIDPath);


if (process.env.DEBUG) {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
Expand Down Expand Up @@ -313,7 +314,7 @@ export class BuilderContext {
* @returns A promise that resolves when the entire build sequence is complete.
*/

async execute(): Promise<void> {
async execute(): Promise<string> {
try {
const nodes = this.sequence.nodes;
let currentIndex = 0;
Expand Down Expand Up @@ -370,6 +371,7 @@ export class BuilderContext {
await Promise.all(Array.from(runningPromises));
await new Promise((resolve) => setTimeout(resolve, this.POLL_INTERVAL));
}
return this.getGlobalContext('projectUUID');
} catch (error) {
this.writeLog('execution-error.json', {
error: error.message,
Expand Down
5 changes: 5 additions & 0 deletions backend/src/build-system/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ export interface BuildSequence {
description?: string;
databaseType?: string;
nodes: BuildNode[];
packages: BuildProjectPackage[];
}
export interface BuildProjectPackage {
name: string;
version: string;
}

/**
Expand Down
6 changes: 5 additions & 1 deletion backend/src/common/model-provider/openai-model-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export class OpenAIModelProvider implements IModelProvider {
private readonly logger = new Logger('OpenAIModelProvider');
private queues: Map<string, PQueue> = new Map();
private configLoader: ConfigLoader;
private defaultModel: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Initialize defaultModel to avoid potential undefined access.

The defaultModel property should be initialized with a default value to prevent potential undefined access.

-  private defaultModel: string;
+  private defaultModel: string = '';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private defaultModel: string;
private defaultModel: string = '';


private constructor() {
this.openai = new OpenAI({
Expand All @@ -35,6 +36,9 @@ export class OpenAIModelProvider implements IModelProvider {
const chatModels = this.configLoader.getAllChatModelConfigs();

for (const model of chatModels) {
if (model.default) {
this.defaultModel = model.model;
}
Comment on lines +39 to +41
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling for missing default model configuration.

The code assumes at least one model will be marked as default. Add error handling to ensure a default model is always available.

+  private hasDefaultModel = false;
   private initializeQueues(): void {
     const chatModels = this.configLoader.getAllChatModelConfigs();
 
     for (const model of chatModels) {
       if (model.default) {
         this.defaultModel = model.model;
+        this.hasDefaultModel = true;
       }
       if (!model.endpoint || !model.token) continue;
       // ... rest of the code
     }
+    if (!this.hasDefaultModel) {
+      this.logger.error('No default model configured');
+      throw new Error('No default model configured in model provider');
+    }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (model.default) {
this.defaultModel = model.model;
}
class OpenaiModelProvider {
// ... other class members
private hasDefaultModel = false;
private initializeQueues(): void {
const chatModels = this.configLoader.getAllChatModelConfigs();
for (const model of chatModels) {
if (model.default) {
this.defaultModel = model.model;
this.hasDefaultModel = true;
}
if (!model.endpoint || !model.token) continue;
// ... rest of the code
}
if (!this.hasDefaultModel) {
this.logger.error('No default model configured');
throw new Error('No default model configured in model provider');
}
}
// ... other methods
}

if (!model.endpoint || !model.token) continue;

const key = this.getQueueKey(model);
Expand Down Expand Up @@ -87,7 +91,7 @@ export class OpenAIModelProvider implements IModelProvider {

async chatSync(input: ChatInput): Promise<string> {
try {
const queue = this.getQueueForModel(input.model);
const queue = this.getQueueForModel(input.model ?? this.defaultModel);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add null check for defaultModel in chatSync.

The chatSync method should verify that defaultModel is available before using it.

-      const queue = this.getQueueForModel(input.model ?? this.defaultModel);
+      if (!input.model && !this.defaultModel) {
+        throw new Error('No model specified and no default model configured');
+      }
+      const queue = this.getQueueForModel(input.model ?? this.defaultModel);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const queue = this.getQueueForModel(input.model ?? this.defaultModel);
if (!input.model && !this.defaultModel) {
throw new Error('No model specified and no default model configured');
}
const queue = this.getQueueForModel(input.model ?? this.defaultModel);

const completion = await queue.add(async () => {
const result = await this.openai.chat.completions.create({
messages: input.messages,
Expand Down
3 changes: 2 additions & 1 deletion backend/src/common/model-provider/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ export interface MessageInterface {
}

export interface ChatInput {
model: string;
// if model not provided, default model will be used
model?: string;
messages: MessageInterface[];
}

Expand Down
73 changes: 58 additions & 15 deletions backend/src/guard/project.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
CanActivate,
ExecutionContext,
UnauthorizedException,
Logger,
} from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
import { JwtService } from '@nestjs/jwt';
Expand All @@ -11,6 +12,8 @@ import { ProjectService } from '../project/project.service';

@Injectable()
export class ProjectGuard implements CanActivate {
private readonly logger = new Logger('ProjectGuard');

constructor(
private readonly projectsService: ProjectService,
private readonly jwtService: JwtService,
Expand All @@ -19,38 +22,78 @@ export class ProjectGuard implements CanActivate {
async canActivate(context: ExecutionContext): Promise<boolean> {
const gqlContext = GqlExecutionContext.create(context);
const request = gqlContext.getContext().req;
const args = gqlContext.getArgs();

// Verify and decode JWT token
const user = await this.validateToken(request);

// Extract project identifier from arguments
const projectIdentifier = this.extractProjectIdentifier(args);

if (!projectIdentifier) {
this.logger.debug('No project identifier found in request');
return true; // Skip check if no project identifier is found
}
Comment on lines +30 to +36
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential bypass if project identifier is missing.

When no project identifier is found, the guard immediately returns true, which effectively skips ownership checks. Confirm that this is intentional. Otherwise, you might introduce a security gap that allows requests without a project ID to pass.

 if (!projectIdentifier) {
-  return true; // Skip check
+  throw new UnauthorizedException('Missing project identifier');
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Extract project identifier from arguments
const projectIdentifier = this.extractProjectIdentifier(args);
if (!projectIdentifier) {
this.logger.debug('No project identifier found in request');
return true; // Skip check if no project identifier is found
}
// Extract project identifier from arguments
const projectIdentifier = this.extractProjectIdentifier(args);
if (!projectIdentifier) {
this.logger.debug('No project identifier found in request');
throw new UnauthorizedException('Missing project identifier');
}


// Extract the authorization header
// Validate project ownership
await this.validateProjectOwnership(projectIdentifier, user.userId);

// Store user in request context for later use
request.user = user;
return true;
}

private async validateToken(request: any): Promise<any> {
const authHeader = request.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
throw new UnauthorizedException('Authorization token is missing');
}

// Decode the token to get user information
const token = authHeader.split(' ')[1];
let user: any;
try {
user = this.jwtService.verify(token);
return this.jwtService.verify(token);
} catch (error) {
this.logger.error(`Token validation failed: ${error.message}`);
throw new UnauthorizedException('Invalid token');
}
}

// Extract projectId from the request arguments
const args = gqlContext.getArgs();
const { projectId } = args;
private extractProjectIdentifier(args: any): string | undefined {
// Handle different input formats
if (args.projectId) return args.projectId;
if (args.input?.projectId) return args.input.projectId;
if (args.isValidProject?.projectId) return args.isValidProject.projectId;
if (args.projectPath) return args.projectPath;
if (args.input?.projectPath) return args.input.projectPath;
if (args.isValidProject?.projectPath)
return args.isValidProject.projectPath;

// Fetch the project and check if the userId matches the project's userId
const project = await this.projectsService.getProjectById(projectId);
if (!project) {
return undefined;
}

private async validateProjectOwnership(
projectIdentifier: string,
userId: number,
): Promise<void> {
let project;
try {
project = await this.projectsService.getProjectById(projectIdentifier);
} catch (error) {
this.logger.error(`Failed to fetch project: ${error.message}`);
throw new UnauthorizedException('Project not found');
}

//To do: In the feature when we need allow teams add check here

if (project.userId !== user.userId) {
throw new UnauthorizedException('User is not the owner of the project');
if (!project) {
throw new UnauthorizedException('Project not found');
}

return true;
if (project.userId !== userId) {
this.logger.warn(
`Unauthorized access attempt: User ${userId} tried to access project ${projectIdentifier}`,
);
throw new UnauthorizedException(
'User is not authorized to access this project',
);
}
}
}
123 changes: 123 additions & 0 deletions backend/src/project/build-system-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { BackendCodeHandler } from 'src/build-system/handlers/backend/code-generate';
import { BackendFileReviewHandler } from 'src/build-system/handlers/backend/file-review/file-review';
import { BackendRequirementHandler } from 'src/build-system/handlers/backend/requirements-document';
import { DBRequirementHandler } from 'src/build-system/handlers/database/requirements-document';
import { DBSchemaHandler } from 'src/build-system/handlers/database/schemas/schemas';
import { FileFAHandler } from 'src/build-system/handlers/file-manager/file-arch';
import { FileStructureHandler } from 'src/build-system/handlers/file-manager/file-structure';
import { FrontendCodeHandler } from 'src/build-system/handlers/frontend-code-generate';
import { PRDHandler } from 'src/build-system/handlers/product-manager/product-requirements-document/prd';
import { ProjectInitHandler } from 'src/build-system/handlers/project-init';
import { UXDMDHandler } from 'src/build-system/handlers/ux/datamap';
import { UXSMDHandler } from 'src/build-system/handlers/ux/sitemap-document';
import { UXSMSHandler } from 'src/build-system/handlers/ux/sitemap-structure';
import { UXSMSPageByPageHandler } from 'src/build-system/handlers/ux/sitemap-structure/sms-page';
import { BuildSequence } from 'src/build-system/types';
import { v4 as uuidv4 } from 'uuid';
import { CreateProjectInput } from './dto/project.input';

export function buildProjectSequenceByProject(
input: CreateProjectInput,
): BuildSequence {
const sequence: BuildSequence = {
id: uuidv4(),
version: '1.0.0',
name: input.projectName,
description: input.description,
databaseType: input.databaseType,
packages: input.packages,
nodes: [
{
handler: ProjectInitHandler,
name: 'Project Folders Setup',
},
{
handler: PRDHandler,
name: 'Project Requirements Document Node',
},
{
handler: UXSMDHandler,
name: 'UX Sitemap Document Node',
},
{
handler: UXSMSHandler,
name: 'UX Sitemap Structure Node',
},
{
handler: UXDMDHandler,
name: 'UX DataMap Document Node',
},
{
handler: DBRequirementHandler,
name: 'Database Requirements Node',
},
{
handler: FileStructureHandler,
name: 'File Structure Generation',
options: {
projectPart: 'frontend',
},
},
{
handler: UXSMSPageByPageHandler,
name: 'Level 2 UX Sitemap Structure Node details',
},
{
handler: DBSchemaHandler,
name: 'Database Schemas Node',
},
{
handler: FileFAHandler,
name: 'File Arch',
},
{
handler: BackendRequirementHandler,
name: 'Backend Requirements Node',
},
{
handler: BackendCodeHandler,
name: 'Backend Code Generator Node',
},
{
handler: BackendFileReviewHandler,
name: 'Backend File Review Node',
},
{
handler: FrontendCodeHandler,
name: 'Frontend Code Generator Node',
},
],
};
return sequence;
}
Comment on lines +19 to +92
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling and improve documentation.

The function needs error handling and documentation for better maintainability.

  1. Add JSDoc documentation explaining the purpose, parameters, and return value.
  2. Add error handling for invalid input.
  3. Make the version configurable instead of hardcoding.

Apply this diff:

+/**
+ * Builds a sequence of build steps for a project.
+ * @param input - The project creation input containing project details and packages
+ * @returns A build sequence containing ordered handlers for project setup
+ * @throws {Error} If required input fields are missing or invalid
+ */
 export function buildProjectSequenceByProject(
   input: CreateProjectInput,
 ): BuildSequence {
+  if (!input.description || !input.packages) {
+    throw new Error('Missing required input fields');
+  }
+
   const sequence: BuildSequence = {
     id: uuidv4(),
-    version: '1.0.0',
+    version: process.env.BUILD_SEQUENCE_VERSION || '1.0.0',
     name: input.projectName,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function buildProjectSequenceByProject(
input: CreateProjectInput,
): BuildSequence {
const sequence: BuildSequence = {
id: uuidv4(),
version: '1.0.0',
name: input.projectName,
description: input.description,
databaseType: input.databaseType,
packages: input.packages,
nodes: [
{
handler: ProjectInitHandler,
name: 'Project Folders Setup',
},
{
handler: PRDHandler,
name: 'Project Requirements Document Node',
},
{
handler: UXSMDHandler,
name: 'UX Sitemap Document Node',
},
{
handler: UXSMSHandler,
name: 'UX Sitemap Structure Node',
},
{
handler: UXDMDHandler,
name: 'UX DataMap Document Node',
},
{
handler: DBRequirementHandler,
name: 'Database Requirements Node',
},
{
handler: FileStructureHandler,
name: 'File Structure Generation',
options: {
projectPart: 'frontend',
},
},
{
handler: UXSMSPageByPageHandler,
name: 'Level 2 UX Sitemap Structure Node details',
},
{
handler: DBSchemaHandler,
name: 'Database Schemas Node',
},
{
handler: FileFAHandler,
name: 'File Arch',
},
{
handler: BackendRequirementHandler,
name: 'Backend Requirements Node',
},
{
handler: BackendCodeHandler,
name: 'Backend Code Generator Node',
},
{
handler: BackendFileReviewHandler,
name: 'Backend File Review Node',
},
{
handler: FrontendCodeHandler,
name: 'Frontend Code Generator Node',
},
],
};
return sequence;
}
/**
* Builds a sequence of build steps for a project.
* @param input - The project creation input containing project details and packages
* @returns A build sequence containing ordered handlers for project setup
* @throws {Error} If required input fields are missing or invalid
*/
export function buildProjectSequenceByProject(
input: CreateProjectInput,
): BuildSequence {
if (!input.description || !input.packages) {
throw new Error('Missing required input fields');
}
const sequence: BuildSequence = {
id: uuidv4(),
version: process.env.BUILD_SEQUENCE_VERSION || '1.0.0',
name: input.projectName,
description: input.description,
databaseType: input.databaseType,
packages: input.packages,
nodes: [
{
handler: ProjectInitHandler,
name: 'Project Folders Setup',
},
{
handler: PRDHandler,
name: 'Project Requirements Document Node',
},
{
handler: UXSMDHandler,
name: 'UX Sitemap Document Node',
},
{
handler: UXSMSHandler,
name: 'UX Sitemap Structure Node',
},
{
handler: UXDMDHandler,
name: 'UX DataMap Document Node',
},
{
handler: DBRequirementHandler,
name: 'Database Requirements Node',
},
{
handler: FileStructureHandler,
name: 'File Structure Generation',
options: {
projectPart: 'frontend',
},
},
{
handler: UXSMSPageByPageHandler,
name: 'Level 2 UX Sitemap Structure Node details',
},
{
handler: DBSchemaHandler,
name: 'Database Schemas Node',
},
{
handler: FileFAHandler,
name: 'File Arch',
},
{
handler: BackendRequirementHandler,
name: 'Backend Requirements Node',
},
{
handler: BackendCodeHandler,
name: 'Backend Code Generator Node',
},
{
handler: BackendFileReviewHandler,
name: 'Backend File Review Node',
},
{
handler: FrontendCodeHandler,
name: 'Frontend Code Generator Node',
},
],
};
return sequence;
}


/**
* Generates a project name prompt based on the provided description.
*/
export function generateProjectNamePrompt(description: string): string {
return `You are a project name generator. Based on the following project description, generate a concise, memorable, and meaningful project name.
Input Description: ${description}
Requirements for the project name:
1. Must be 1-3 words maximum
2. Should be clear and professional
3. Avoid generic terms like "project" or "system"
4. Use camelCase or kebab-case format
5. Should reflect the core functionality or purpose
6. Must be unique and memorable
7. Should be easy to pronounce
8. Avoid acronyms unless they're very intuitive
Please respond ONLY with the project name, without any explanation or additional text.
Example inputs and outputs:
Description: "A task management system with real-time collaboration features"
Output: taskFlow
Description: "An AI-powered document analysis and extraction system"
Output: docMind
Description: "A microservice-based e-commerce platform with advanced inventory management"
Output: tradeCore`;
}
Comment on lines +97 to +123
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add input validation.

The function should validate the input description to ensure it's not empty or too long.

Apply this diff:

 export function generateProjectNamePrompt(description: string): string {
+  if (!description?.trim()) {
+    throw new Error('Description is required');
+  }
+  if (description.length > 500) {
+    throw new Error('Description is too long. Maximum length is 500 characters');
+  }
+
   return `You are a project name generator. Based on the following project description, generate a concise, memorable, and meaningful project name.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function generateProjectNamePrompt(description: string): string {
return `You are a project name generator. Based on the following project description, generate a concise, memorable, and meaningful project name.
Input Description: ${description}
Requirements for the project name:
1. Must be 1-3 words maximum
2. Should be clear and professional
3. Avoid generic terms like "project" or "system"
4. Use camelCase or kebab-case format
5. Should reflect the core functionality or purpose
6. Must be unique and memorable
7. Should be easy to pronounce
8. Avoid acronyms unless they're very intuitive
Please respond ONLY with the project name, without any explanation or additional text.
Example inputs and outputs:
Description: "A task management system with real-time collaboration features"
Output: taskFlow
Description: "An AI-powered document analysis and extraction system"
Output: docMind
Description: "A microservice-based e-commerce platform with advanced inventory management"
Output: tradeCore`;
}
export function generateProjectNamePrompt(description: string): string {
if (!description?.trim()) {
throw new Error('Description is required');
}
if (description.length > 500) {
throw new Error('Description is too long. Maximum length is 500 characters');
}
return `You are a project name generator. Based on the following project description, generate a concise, memorable, and meaningful project name.
Input Description: ${description}
Requirements for the project name:
1. Must be 1-3 words maximum
2. Should be clear and professional
3. Avoid generic terms like "project" or "system"
4. Use camelCase or kebab-case format
5. Should reflect the core functionality or purpose
6. Must be unique and memorable
7. Should be easy to pronounce
8. Avoid acronyms unless they're very intuitive
Please respond ONLY with the project name, without any explanation or additional text.
Example inputs and outputs:
Description: "A task management system with real-time collaboration features"
Output: taskFlow
Description: "An AI-powered document analysis and extraction system"
Output: docMind
Description: "A microservice-based e-commerce platform with advanced inventory management"
Output: tradeCore`;
}

36 changes: 36 additions & 0 deletions backend/src/project/dto/project.input.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// DTOs for Project APIs
import { InputType, Field, ID } from '@nestjs/graphql';

/**
* @deprecated We don't need project upsert
*/
@InputType()
export class UpsertProjectInput {
@Field()
Expand All @@ -14,3 +17,36 @@ export class UpsertProjectInput {
@Field(() => [String], { nullable: true })
projectPackages: string[];
}

@InputType()
export class CreateProjectInput {
@Field(() => String, { nullable: true })
projectName?: string;

@Field()
description: string;

@Field(() => [ProjectPackage])
packages: ProjectPackage[];

@Field(() => String, { nullable: true })
databaseType?: string;
}

@InputType()
export class ProjectPackage {
@Field()
name: string;

@Field()
version: string;
}

@InputType()
export class IsValidProjectInput {
@Field(() => ID)
projectId: string;

@Field(() => String, { nullable: true })
projectPath: string;
}
Loading
Loading