<purpose>
You are an experienced senior software engineer working on a code repository.
You will be given details about the Project (which represents the repository), including any existing
high-level documentation about the Project.You are being given a detailed plan for some work that needs to be done, including tasks, files, and instructions.
The plan has been prepared for you ahead of time by an LLM Architect, and then checked and improved
by a second Architect. It is likely that the plan is good and you should follow it as closely as possible to completion.Implement the changes described in the plan, following sequentially task by task until the work is complete.
</purpose>
<instructions>
<instruction>Implement all of the tasks in the plan, one by one, in the order specified</instruction>
<instruction>For each task, ensure that the work has been completed according to the instructions in the plan</instruction>
<instruction>Use the tools available to you to examine files in the repository if it helps you make your determination</instruction>
<instruction>Read existing code and comments first, and reuse code where possible</instruction>
<instruction>This is a Next JS application using React and TypeScript. Use those technologies.</instruction>
</instructions>
<data>
Here is an overview of the project you are working on:
<project>
<id>83ad8f85-e269-4fbb-ace5-1d99eb4ca87a</id>
<name>Task Demon</name>
<description>Task Demon is a chatbot-centric SaaS application that acts on behalf of the user to create and maintain tickets (or issues) for work that needs to be done. It also has a number of Agents that can be run on customer devices to automatically use AI to triage, plan and implement work on git repositories.</description>
<status>active</status>
</project>
Here is some background information about this task in the context of the project:
<project-document>
# Task Demon: Add Reset Button to Project Details Page
## Project Overview
**Project Name:** Task Demon
**Project ID:** 2d1b9dd6-a737-4b43-9c2a-6f6323908cb5
**Description:** Task Demon is a chatbot-centric SaaS application designed to automate software development workflows. It acts as an AI-powered task management system that creates and maintains tickets for work that needs to be done. The platform includes specialized AI agents that run on customer devices to automatically triage, plan, and implement work on git repositories. Task Demon integrates deeply with GitHub, providing a seamless experience for managing development tasks.
## Task Details
**Task ID:** eecc9da4-ae5e-4084-84b3-72a6ccbd817f
**Task Name:** Add Reset Button to Project Details Page
**Task Description:** Implement a button on the Project Details page that allows users to reset the project. This button should trigger a new API endpoint that calls a library function to delete all documents, tasks, characterizations, events, workflows, agents, chats, messages, and instructions for the project. Additionally, it should set `tasksImported` to false on the project. The reset option should be accessible via a button in the Project Settings page, which opens a confirmation modal to verify the action due to its destructive nature. After the reset is complete, the modal should inform the user of the success and provide a button to 'Go to Project'.
## Relevant Information from Project Documents
### Project Details Page Characterization
- **Core Components:**
- **Server Components:** Located in `app/app/projects/[projectId]`, including:
- `page.tsx`: Main server component that fetches and renders project data.
- `layout.tsx`: Provides ProjectProvider context to child components.
- **Client Components:** Primarily in `components/projects/`, structured as:
- Project header (title, description).
- Settings panel (preferences, GitHub integration).
- Characterization summary section.
- Task list with filtering capabilities.
- Project chat interface.
- Activity feed with real-time updates.
- Documents section organized by type.
- Project agents section.
- **State Management:**
- `ProjectProvider`: Provides project data and UI preferences.
- `use-project-context.tsx`: Context hook managing project state.
- Custom hooks for real-time data synchronization:
- `use-project-events.ts`: Manages project activity with pagination.
- `use-project-events-swr.ts`: Handles real-time updates via Pusher.
- **Data Flow:**
- **Initial Load:** Server fetches project data, tasks, and characterization status.
- **Real-time Updates:** Pusher channels provide WebSocket-based notifications.
- **User Interactions:** Edit project metadata, start/view characterization, filter and view tasks, chat with project AI, monitor activity feed.
### API Documentation
- **Projects API:**
- `/api/projects/:projectId`: Get project details.
- `/api/projects/:projectId/tasks`: List project tasks.
- `/api/projects/:projectId/characterization`: Get project characterization.
- **New Endpoint Required:** A new API endpoint will be needed to handle the reset functionality, which will delete all related data and reset `tasksImported`.
### Security and Compliance
- **Authentication and Access Control:**
- All routes under `/app/*` are protected by middleware.
- Unauthenticated users are redirected to the login page.
- Secure URL handling with proper validation.
- **Data Handling and Storage:**
- User data stored on Vercel's infrastructure.
- All API communication uses HTTPS.
- WebSocket connections secured with WSS.
### UI Technical Documentation
- **Component Architecture:**
- **Base UI Components:** Foundational elements like Button, Input, Badge, Dialog.
- **Composite Components:** Built from UI primitives.
- **Feature Components:** Project components located in `/components/projects/`.
- **Design System:**
- Theme-aware colors adapting to light/dark modes.
- Semantic color naming and CSS variables implemented through Tailwind.
- **UI Patterns and Conventions:**
- TypeScript interfaces for component props.
- Forwarded refs for better composition.
- Consistent variant and size props.
### Pusher Integration
- **Real-time Communication:**
- Pusher channels for project, task, and characterization-specific events.
- WebSockets for streaming AI agent responses.
### Testing and Quality Assurance
- **Testing Frameworks:**
- **Jest:** Primary testing framework for both backend and frontend.
- **@testing-library/react:** Library for testing React components.
- **Testing Methodologies:**
- Unit Testing, Integration Testing, UI Testing, API Testing.
## Implementation Considerations
1. **UI Design:**
- Add a "Reset Project" button to the Project Settings page.
- Implement a confirmation modal to verify the reset action due to its destructive nature.
- After reset, display a success message with a button to 'Go to Project'.
2. **API Development:**
- Develop a new API endpoint to handle the reset functionality.
- Ensure the endpoint deletes all related data (documents, tasks, characterizations, events, workflows, agents, chats, messages, and instructions) and sets `tasksImported` to false.
3. **Security:**
- Ensure the reset action is protected by proper authentication and authorization checks.
- Implement secure data handling practices as per the security documentation.
4. **Testing:**
- Write unit and integration tests for the new API endpoint.
- Test the UI components for the reset button and confirmation modal.
- Ensure real-time updates are handled correctly post-reset.
5. **Real-time Updates:**
- Use Pusher to notify the UI of changes post-reset, ensuring the user interface reflects the reset state immediately.
By following these guidelines and utilizing the provided documentation, the task of adding a reset button to the Project Details page can be implemented effectively, ensuring a seamless user experience and maintaining the integrity of the Task Demon platform.
</project-document>
This is the task itself:
<task>
<id>eecc9da4-ae5e-4084-84b3-72a6ccbd817f</id>
<name>Add Reset Button to Project Details Page</name>
<description>Implement a button on the Project Details page that allows users to reset the project. This button should trigger a new API endpoint that calls a library function to delete all documents, tasks, characterizations, events, workflows, agents, chats, messages, and instructions for the project. Additionally, it should set `tasksImported` to false on the project. The reset option should be accessible via a button in the Project Settings page, which opens a confirmation modal to verify the action due to its destructive nature. After the reset is complete, the modal should inform the user of the success and provide a button to 'Go to Project'.</description>
<status>closed</status>
</task>
Here is the plan for the work:
<plan>
I'll analyze the task of adding a reset button to the Project Details page and create a comprehensive requirements document. Let me start by understanding the task and existing codebase.
# Requirements Document: Add Reset Button to Project Details Page
## Overview of Approach
This task involves adding a reset functionality to the Project Details page, which requires both frontend components and backend services. I'll need to:
1. Create a new API endpoint for resetting a project
2. Implement library functions to handle data deletion operations
3. Add a reset button to the Project Settings component
4. Create a confirmation dialog for the reset action
5. Create a success notification after reset completion
The reset operation is destructive, removing all associated project data (documents, tasks, characterizations, events, workflows, agents, chats, messages, and instructions) while maintaining the project itself. Given the severity of this action, proper user confirmation and security checks are essential.
This implementation will follow the existing patterns in the Task Demon application, leveraging the ShadCN UI component library, Next.js App Router, and Drizzle ORM.
## Architectural Overview
### System Components
The reset project functionality will span several architectural layers:
1. **UI Layer**:
- A reset button in the Project Settings panel
- A confirmation dialog using the existing ConfirmationDialog component
- Success notification via the toast system
2. **API Layer**:
- A new REST endpoint at `/api/projects/[projectId]/reset` that handles the project reset request
- Authentication and authorization middleware to ensure only authorized users can reset projects
3. **Data Layer**:
- Library functions to delete associated data across multiple tables
- Database queries using Drizzle ORM to perform the deletions
- Project update to reset the `tasksImported` flag
4. **Notification Layer**:
- Pusher integration to notify UI components of the reset completion
- Real-time updates to reflect the project's new state
### Data Flow
```
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐
│ │ │ │ │ │
│ Project Settings │────►│ Reset API Endpoint│────►│ Reset Functions │
│ + Reset Button │ │ │ │ │
│ │ │ │ │ │
└───────────────────┘ └───────────────────┘ └───────────────────┘
▲ │
│ │
│ ▼
┌───────────────────┐ ┌───────────────────┐
│ │ │ │
│ Success Dialog + │◄─────────────────────────────│ Database │
│ Toast Notification│ │ │
│ │ │ │
└───────────────────┘ └───────────────────┘
```
### Security Considerations
The reset functionality requires special attention to security:
1. **Authentication**: Only authenticated users can access the reset endpoint
2. **Authorization**: Users must have permission to modify the specific project
3. **Confirmation**: A double confirmation pattern prevents accidental resets
4. **Validation**: Server-side validation ensures the projectId is valid
5. **Audit Logging**: The action should be logged for audit purposes
### Error Handling
The implementation includes comprehensive error handling:
1. **UI Error States**: Display appropriate error messages if the reset fails
2. **API Error Responses**: Return structured error responses from the API
3. **Recovery Mechanisms**: Provide guidance for users if errors occur
4. **Validation Errors**: Handle invalid inputs gracefully
## Tasks Breakdown
### Backend Implementation
#### API Endpoint Creation
- [ ] 1. Create a new API route handler file at `app/api/projects/[projectId]/reset/route.ts`
- [ ] 2. Implement the DELETE method handler that validates the request and calls the reset library function
- [ ] 3. Add proper error handling and response formatting
- [ ] 4. Add authentication check using Next Auth
#### Library Functions
- [ ] 5. Create a new library file `lib/db/projects/reset.ts` for project reset functionality
- [ ] 6. Implement function to delete all documents associated with a project
- [ ] 7. Implement function to delete all tasks associated with a project
- [ ] 8. Implement function to delete all characterizations associated with a project
- [ ] 9. Implement function to delete all events associated with a project
- [ ] 10. Implement function to delete all workflows associated with a project
- [ ] 11. Implement function to delete all agents associated with a project
- [ ] 12. Implement function to delete all chats and messages associated with a project
- [ ] 13. Implement function to delete all instructions associated with a project
- [ ] 14. Implement function to set `tasksImported` to false on the project
- [ ] 15. Create a main reset function that orchestrates all the deletion operations in a transaction
### Frontend Implementation
#### UI Components
- [ ] 16. Add a "Reset Project" button to the Project Settings component in `components/projects/project-settings-panel.tsx`
- [ ] 17. Create a confirmation dialog component for the reset action
- [ ] 18. Add success notification using the toast system
- [ ] 19. Implement loading state for the reset button during the operation
#### API Integration
- [ ] 20. Create a reset project API client function in `lib/db/projects/queries.ts`
- [ ] 21. Connect the reset button to the API client function
- [ ] 22. Handle API responses and errors in the UI
### Testing
- [ ] 23. Create API route test file `test/api/projects/reset.test.ts`
- [ ] 24. Write test cases for successful project reset
- [ ] 25. Write test cases for unauthorized access attempts
- [ ] 26. Write test cases for invalid project IDs
- [ ] 27. Create UI test file `test/components/projects/reset-project.test.tsx`
- [ ] 28. Write test for the Reset Project button rendering
- [ ] 29. Write test for confirmation dialog appearance and interaction
- [ ] 30. Write test for success notification
- [ ] 31. Write test for API client function in isolation
### Documentation
- [ ] 32. Update API documentation to include the new reset endpoint
- [ ] 33. Document the reset functionality in the project README or internal documentation
## Detailed Implementation Specifications
### Backend Implementation Details
#### API Endpoint
```typescript
// app/api/projects/[projectId]/reset/route.ts
import { auth } from '@/app/(auth)/auth';
import { resetProject } from '@/lib/db/projects/reset';
import { NextRequest, NextResponse } from 'next/server';
/**
* Handler for resetting a project.
* Deletes all associated data and resets the project state.
*
* @param request The incoming request
* @param params Object containing route parameters
* @returns NextResponse with status and message
*/
export async function DELETE(
request: NextRequest,
{ params }: { params: { projectId: string } }
) {
// Authentication check
const session = await auth();
if (!session || !session.user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const { projectId } = params;
if (!projectId) {
return NextResponse.json(
{ error: 'Project ID is required' },
{ status: 400 }
);
}
try {
// Call the reset library function
await resetProject(projectId);
return NextResponse.json(
{ message: 'Project reset successfully' },
{ status: 200 }
);
} catch (error) {
console.error('Error resetting project:', error);
return NextResponse.json(
{ error: 'Failed to reset project' },
{ status: 500 }
);
}
}
```
#### Library Functions
```typescript
// lib/db/projects/reset.ts
import { db } from '@/lib/db';
import { and, eq } from 'drizzle-orm';
import { documents, projects, tasks, characterizations, events, workflows, agents, chats, messages, instructions } from '@/lib/db/schema';
/**
* Resets a project by deleting all associated data and setting tasksImported to false.
* This is a destructive operation that cannot be undone.
*
* @param projectId The ID of the project to reset
* @returns Promise that resolves when reset is complete
*/
export async function resetProject(projectId: string): Promise<void> {
// Execute all operations in a transaction to ensure consistency
return db.transaction(async (tx) => {
// Delete all documents
await tx.delete(documents).where(eq(documents.projectId, projectId));
// Delete all tasks
await tx.delete(tasks).where(eq(tasks.projectId, projectId));
// Delete all characterizations
await tx.delete(characterizations).where(eq(characterizations.projectId, projectId));
// Delete all events
await tx.delete(events).where(eq(events.projectId, projectId));
// Delete all workflows
await tx.delete(workflows).where(eq(workflows.projectId, projectId));
// Delete all agents
await tx.delete(agents).where(eq(agents.projectId, projectId));
// Delete all chats and messages
// First, get all chat IDs for this project
const projectChats = await tx
.select({ id: chats.id })
.from(chats)
.where(eq(chats.projectId, projectId));
// Delete messages for these chats
for (const chat of projectChats) {
await tx.delete(messages).where(eq(messages.chatId, chat.id));
}
// Delete the chats themselves
await tx.delete(chats).where(eq(chats.projectId, projectId));
// Delete all instructions
await tx.delete(instructions).where(eq(instructions.projectId, projectId));
// Reset the tasksImported flag on the project
await tx
.update(projects)
.set({ tasksImported: false })
.where(eq(projects.id, projectId));
});
}
```
```typescript
// lib/db/projects/queries.ts (addition to existing file)
/**
* Reset a project by deleting all associated data and setting tasksImported to false.
*
* @param projectId - The ID of the project to reset
* @returns Promise that resolves when the project has been reset
*/
export async function resetProjectData(projectId: string): Promise<void> {
const response = await fetch(`/api/projects/${projectId}/reset`, {
method: 'DELETE',
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || 'Failed to reset project');
}
}
```
### Frontend Implementation Details
#### Reset Button in Project Settings
```typescript
// components/projects/project-settings-panel.tsx (addition to existing component)
import { useState } from 'react';
import { useRouter } from 'next/navigation';
import { Button } from '@/components/ui/button';
import { ConfirmationDialog } from '@/components/ui/confirmation-dialog';
import { useToast } from '@/hooks/use-toast';
import { resetProjectData } from '@/lib/db/projects/queries';
// Add to existing component
const [isResetDialogOpen, setIsResetDialogOpen] = useState(false);
const [isResetting, setIsResetting] = useState(false);
const [resetSuccess, setResetSuccess] = useState(false);
const router = useRouter();
const { toast } = useToast();
const handleResetProject = async () => {
setIsResetting(true);
try {
await resetProjectData(project.id);
setIsResetting(false);
setResetSuccess(true);
toast({
title: 'Project reset successfully',
description: 'All project data has been deleted.',
variant: 'default',
});
} catch (error) {
setIsResetting(false);
toast({
title: 'Failed to reset project',
description: error instanceof Error ? error.message : 'An error occurred',
variant: 'destructive',
});
}
};
// Add this to the JSX in the component's return statement
<div className="border-t border-border pt-4 mt-4">
<h3 className="text-sm font-medium mb-4">Danger Zone</h3>
<div className="rounded border border-destructive p-4">
<div className="flex flex-col gap-2">
<h4 className="font-medium text-destructive">Reset Project</h4>
<p className="text-sm text-muted-foreground">
This will delete all documents, tasks, and other data associated with this project.
This action cannot be undone.
</p>
<Button
variant="destructive"
className="mt-2 w-fit"
onClick={() => setIsResetDialogOpen(true)}
>
Reset Project
</Button>
</div>
</div>
</div>
<ConfirmationDialog
open={isResetDialogOpen}
onOpenChange={setIsResetDialogOpen}
title="Reset Project"
description="Are you sure you want to reset this project? This will delete all tasks, documents, characterizations, and other data. This action cannot be undone."
confirmText="Reset Project"
cancelText="Cancel"
destructive
onConfirm={handleResetProject}
loading={isResetting}
/>
<ConfirmationDialog
open={resetSuccess}
onOpenChange={setResetSuccess}
title="Project Reset Successfully"
description="Your project has been reset. All tasks, documents, and other data have been deleted."
confirmText="Go to Project"
showCancel={false}
onConfirm={() => {
setResetSuccess(false);
router.push(`/app/projects/${project.id}`);
router.refresh();
}}
/>
```
### Test Implementation Details
```typescript
// test/api/projects/reset.test.ts
import { DELETE } from '@/app/api/projects/[projectId]/reset/route';
import { db } from '@/lib/db';
import { projects, documents, tasks, characterizations, events, workflows, agents, chats, messages, instructions } from '@/lib/db/schema';
import { createMocks } from 'node-mocks-http';
import { v4 as uuidv4 } from 'uuid';
import { eq } from 'drizzle-orm';
jest.mock('@/app/(auth)/auth', () => ({
auth: jest.fn(() => Promise.resolve({
user: { id: 'test-user-id', email: 'test@example.com' }
}))
}));
describe('Project Reset API', () => {
let projectId: string;
// Create test data before each test
beforeEach(async () => {
// Create a test project
projectId = uuidv4();
await db.insert(projects).values({
id: projectId,
name: 'Test Project',
description: 'Test Description',
userId: 'test-user-id',
tasksImported: true,
createdAt: new Date(),
updatedAt: new Date(),
});
// Create test documents, tasks, etc. for this project
await db.insert(documents).values({
id: uuidv4(),
projectId: projectId,
title: 'Test Document',
content: 'Test Content',
type: 'note',
createdAt: new Date(),
updatedAt: new Date(),
});
await db.insert(tasks).values({
id: uuidv4(),
projectId: projectId,
title: 'Test Task',
description: 'Test Description',
status: 'open',
createdAt: new Date(),
updatedAt: new Date(),
});
// Add more test data as needed
});
// Clean up after each test
afterEach(async () => {
// Clean up all test data
await db.delete(documents).where(eq(documents.projectId, projectId));
await db.delete(tasks).where(eq(tasks.projectId, projectId));
await db.delete(projects).where(eq(projects.id, projectId));
// Clean up other tables as needed
});
it('should reset a project successfully', async () => {
// Mock the request
const { req, res } = createMocks({
method: 'DELETE',
});
// Call the API route handler
await DELETE(req, { params: { projectId } });
// Check if all associated data was deleted
const projectDocs = await db.select().from(documents).where(eq(documents.projectId, projectId));
expect(projectDocs.length).toBe(0);
const projectTasks = await db.select().from(tasks).where(eq(tasks.projectId, projectId));
expect(projectTasks.length).toBe(0);
// Check if project still exists but tasksImported is set to false
const updatedProject = await db.select().from(projects).where(eq(projects.id, projectId)).limit(1);
expect(updatedProject.length).toBe(1);
expect(updatedProject[0].tasksImported).toBe(false);
});
it('should return 400 for missing project ID', async () => {
// Mock the request
const { req, res } = createMocks({
method: 'DELETE',
});
// Call the API route handler with empty params
const result = await DELETE(req, { params: { projectId: '' } });
const data = await result.json();
expect(result.status).toBe(400);
expect(data.error).toBe('Project ID is required');
});
// More tests for other cases...
});
```
```typescript
// test/components/projects/reset-project.test.tsx
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { ProjectSettingsPanel } from '@/components/projects/project-settings-panel';
import { resetProjectData } from '@/lib/db/projects/queries';
import { useRouter } from 'next/navigation';
// Mock the dependencies
jest.mock('next/navigation', () => ({
useRouter: jest.fn(),
}));
jest.mock('@/hooks/use-toast', () => ({
useToast: () => ({
toast: jest.fn(),
}),
}));
jest.mock('@/lib/db/projects/queries', () => ({
resetProjectData: jest.fn(),
}));
describe('Project Reset Button', () => {
const mockProject = {
id: 'test-project-id',
name: 'Test Project',
description: 'Test Description',
tasksImported: true,
};
const mockRouter = {
push: jest.fn(),
refresh: jest.fn(),
};
beforeEach(() => {
jest.clearAllMocks();
(useRouter as jest.Mock).mockReturnValue(mockRouter);
});
it('should render the reset button in the danger zone', () => {
render(<ProjectSettingsPanel project={mockProject} />);
expect(screen.getByText('Reset Project')).toBeInTheDocument();
expect(screen.getByText(/This will delete all documents, tasks, and other data/)).toBeInTheDocument();
});
it('should open confirmation dialog when reset button is clicked', async () => {
render(<ProjectSettingsPanel project={mockProject} />);
const resetButton = screen.getByRole('button', { name: 'Reset Project' });
await userEvent.click(resetButton);
expect(screen.getByText('Are you sure you want to reset this project?')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Reset Project' })).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Cancel' })).toBeInTheDocument();
});
it('should call reset API when confirmed', async () => {
(resetProjectData as jest.Mock).mockResolvedValue(undefined);
render(<ProjectSettingsPanel project={mockProject} />);
// Click the reset button
const resetButton = screen.getByRole('button', { name: 'Reset Project' });
await userEvent.click(resetButton);
// Click the confirm button in the dialog
const confirmButton = screen.getByRole('button', { name: 'Reset Project' });
await userEvent.click(confirmButton);
// Check if API was called
expect(resetProjectData).toHaveBeenCalledWith(mockProject.id);
});
it('should show success dialog after reset', async () => {
(resetProjectData as jest.Mock).mockResolvedValue(undefined);
render(<ProjectSettingsPanel project={mockProject} />);
// Click the reset button
const resetButton = screen.getByRole('button', { name: 'Reset Project' });
await userEvent.click(resetButton);
// Click the confirm button in the dialog
const confirmButton = screen.getByRole('button', { name: 'Reset Project' });
await userEvent.click(confirmButton);
// Wait for the success dialog to appear
await waitFor(() => {
expect(screen.getByText('Project Reset Successfully')).toBeInTheDocument();
});
// Click the "Go to Project" button
const goToProjectButton = screen.getByRole('button', { name: 'Go to Project' });
await userEvent.click(goToProjectButton);
// Verify navigation
expect(mockRouter.push).toHaveBeenCalledWith(`/app/projects/${mockProject.id}`);
expect(mockRouter.refresh).toHaveBeenCalled();
});
it('should handle API errors', async () => {
(resetProjectData as jest.Mock).mockRejectedValue(new Error('API error'));
render(<ProjectSettingsPanel project={mockProject} />);
// Click the reset button
const resetButton = screen.getByRole('button', { name: 'Reset Project' });
await userEvent.click(resetButton);
// Click the confirm button in the dialog
const confirmButton = screen.getByRole('button', { name: 'Reset Project' });
await userEvent.click(confirmButton);
// Verify the toast was called (implementation depends on your toast setup)
// You could check for error elements or mock the toast function and verify it's called
});
});
```
## Required Files for Implementation
To implement this feature, the following files will be needed:
1. **New Files:**
- `app/api/projects/[projectId]/reset/route.ts`
- `lib/db/projects/reset.ts`
- `test/api/projects/reset.test.ts`
- `test/components/projects/reset-project.test.tsx`
2. **Files to Modify:**
- `components/projects/project-settings-panel.tsx`
- `lib/db/projects/queries.ts`
3. **Reference Files:**
- `lib/db/schema.ts`
- `components/ui/confirmation-dialog.tsx`
- `components/ui/button.tsx`
- `hooks/use-toast.ts`
- `app/(auth)/auth.ts`
This implementation plan provides a comprehensive guide for adding the reset functionality to the Project Details page, ensuring all required components, API endpoints, and tests are properly specified.
</plan>
Here are some requested instructions from the user. Follow these if possible, but do not do anything contrary to
your main instructions above:
<user-requested-instructions>
The repo consists of a Next JS 15 app in /app and a NPM JS CLI tool in /cli. The Next JS app is the SaaS has an API (see /app/api). The CLI tool integrates closely with the Next JS app (principally via its API), but is a separate codebase, with no code-sharing between the two.
When writing tests, do not import from jest/globals, they are already present for you.
When writing route.test.ts files (to test the API endpoints), do not mock out the database, instead create the data needed for the test via the schema.ts models in a beforeEach or beforeAll function, then surgically delete the data again in an afterAll/afterEach.
We use jest for coding - do not use vitest.
We use the toast hook for UI notifications: `import { useToast } from '@/hooks/use-toast';`
Always specify the use of the App Router pattern, not Page Router in Next JS.
Look at lib/db/schema.ts for the full data model.
We use drizzle for the ORM, make sure you do too and call it correctly.
The Next JS application has the marketing pages for the website (inside the app/(marketing) directory), and the SaaS app pages, which are inside the app/app directory. Most of the time we are working inside app/app
When working on the UI, use the ConfirmationDialog component from confirmation-dialog.tsx in place of document.confirm() when asking for user confirmation.
Use ShadCN components whenever possible.
Run pnpm lint:fix when you are done to make sure you have not introduced any lint errors.
You can run the UI tests using `pnpm test:ui` if you modified any UI or APIs.
When writing tests, do not import from jest/globals, they are already present for you.
When writing route.test.ts files (to test the API endpoints), do not mock out the database, instead create the data needed for the test via the schema.ts models in a beforeEach or beforeAll function, then surgically delete the data again in an afterAll/afterEach.
We use jest for coding - do not use vitest.
We use Next Auth for authentication, imported like this: `import { auth } from '@/app/(auth)/auth';`
We use the toast hook for UI notifications: `import { useToast } from '@/hooks/use-toast';`
</user-requested-instructions>
</data>
Please get started!