2f20b1e5c2
Build & Push Docker Image / build (push) Successful in 2m15s
- tools: add deletedAt/deletedBy, soft delete via DELETE /tools/:id when actor has trash entitlement, else immediate hard delete - trash endpoints: GET /tools/trash, POST /tools/trash (admin bulk), POST /tools/trash/restore, DELETE /tools/trash, POST /tools/trash/empty - trash feature for premium/enterprise; exclude trashed from all public surfaces (browse, categories, features, tags, similar, ratings, costs, analytics, redundancy) - TRASH_RETENTION_DAYS env (0 = keep forever) with hourly purge job - frontend: /trash page (premium+, restore for all, permanent delete + empty for admin), admin Tools tab with multi-select bulk trash, sidebar Trash link, tool-detail delete hint
24 lines
1.1 KiB
TypeScript
24 lines
1.1 KiB
TypeScript
import { pgTable, text, serial, timestamp } from "drizzle-orm/pg-core";
|
|
import { createInsertSchema } from "drizzle-zod";
|
|
import { z } from "zod/v4";
|
|
|
|
export const toolsTable = pgTable("tools", {
|
|
id: serial("id").primaryKey(),
|
|
name: text("name").notNull(),
|
|
description: text("description").notNull(),
|
|
category: text("category").notNull(),
|
|
websiteUrl: text("website_url"),
|
|
iconUrl: text("icon_url"),
|
|
createdBy: text("created_by"),
|
|
features: text("features").array().notNull().default([]),
|
|
tags: text("tags").array().notNull().default([]),
|
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow().$onUpdate(() => new Date()),
|
|
deletedAt: timestamp("deleted_at", { withTimezone: true }),
|
|
deletedBy: text("deleted_by"),
|
|
});
|
|
|
|
export const insertToolSchema = createInsertSchema(toolsTable).omit({ id: true, createdAt: true, updatedAt: true });
|
|
export type InsertTool = z.infer<typeof insertToolSchema>;
|
|
export type Tool = typeof toolsTable.$inferSelect;
|