- Deleting{" "}
+ Archiving{" "}
{project.name}
{" "}
- permanently removes its Search Console connection, rank tracking,
- audits, and saved keywords. This can't be undone.
+ removes it from your workspace and stops its scheduled rank
+ tracking. You can restore it later from the Projects page.
@@ -206,17 +206,17 @@ function DangerSection({
) : (
- {canDelete
- ? "Permanently delete this project and all of its data."
- : "You can't delete your only project."}
+ {canArchive
+ ? "Archive this project to remove it from your workspace."
+ : "You can't archive your only project."}
)}
diff --git a/src/db/app.schema.ts b/src/db/app.schema.ts
index 5a8b299..2f6b7b7 100644
--- a/src/db/app.schema.ts
+++ b/src/db/app.schema.ts
@@ -53,6 +53,9 @@ export const projects = sqliteTable(
createdAt: text("created_at")
.notNull()
.default(sql`(current_timestamp)`),
+ // Soft delete: archived projects are hidden everywhere but their data
+ // (keywords, rank tracking, audits) is preserved.
+ archivedAt: text("archived_at"),
},
(table) => [
// Only the auto-created Default/null-domain project is a singleton. This
@@ -61,7 +64,9 @@ export const projects = sqliteTable(
// creating multiple projects with the same name or domain later.
uniqueIndex("projects_one_default_per_organization_idx")
.on(table.organizationId)
- .where(sql`${table.name} = 'Default' AND ${table.domain} IS NULL`),
+ .where(
+ sql`${table.name} = 'Default' AND ${table.domain} IS NULL AND ${table.archivedAt} IS NULL`,
+ ),
],
);
diff --git a/src/routes/_app/projects.tsx b/src/routes/_app/projects.tsx
index fa1fa53..14af58f 100644
--- a/src/routes/_app/projects.tsx
+++ b/src/routes/_app/projects.tsx
@@ -1,8 +1,14 @@
import * as React from "react";
import { Link, createFileRoute } from "@tanstack/react-router";
-import { useQuery } from "@tanstack/react-query";
+import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { ChevronRight, Plus } from "lucide-react";
-import { getProjects } from "@/serverFunctions/projects";
+import { toast } from "sonner";
+import {
+ getArchivedProjects,
+ getProjects,
+ restoreProject,
+} from "@/serverFunctions/projects";
+import { getStandardErrorMessage } from "@/client/lib/error-messages";
import { getLastProjectId } from "@/client/lib/active-project";
import { CreateProjectModal } from "@/client/features/projects/CreateProjectModal";
@@ -80,6 +86,8 @@ function ProjectsPage() {
))}
)}
+
+
{creating ? (
@@ -88,3 +96,57 @@ function ProjectsPage() {