- 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
- visible brand text changed to toolr (sidebar, mobile header, topbar
fallback, login, 404, home heading, index.html title/og/twitter meta)
- brand logo now links to / in sidebar, mobile header, login, 404
- internal identifiers unchanged: package name, localStorage key
- ThemeToggle moved from sidebar footer to new desktop topbar (top-right),
page title shown left; mobile header + login unchanged
- dark theme primary switched from neon orange to amber/gold (38 92% 50%),
primary-foreground to dark navy for contrast; ring + chart-1 harmonized
- light theme stays orange
Backend security:
- Admin-gate /admin/redundancy (GET+POST) with zod validation and tool existence checks
- Restrict CORS to same-origin (plus CORS_ORIGIN allowlist) and SameSite=Lax cookie
- Validate returnTo to prevent open redirect in the OIDC flow
- Validate/coerce relations body, reject self-relations and non-admin 'recommended'
- Add central JSON error middleware (no more Express HTML 500s)
- Fail fast at startup when SESSION_SECRET/VOTER_SECRET missing in production
Backend correctness:
- Stop leaking voterToken in the create-rating response
- Allow clearing websiteUrl/iconUrl (nullable in UpdateToolBody, frontend sends null)
- Regenerate session after login/callback (session fixation) and add OIDC state check
- Block self-demotion and last-admin demotion in user PATCH
- Set created_by to NULL on user delete (FK-safe)
- Validate cost create/update bodies with zod
- Unique index (tool_id, voter_token) + 409 on race duplicate ratings
- Clamp audit limit, escape ilike wildcards in search, O(N) analytics queries
Frontend:
- tools-browse reads and syncs URL query params (fixes home 'View all' links)
- Invalidate analytics/top-tools/categories/features caches after mutations
- Sync category combobox input when the value changes externally
- Hide Write a Review for anonymous users, drop unreachable rating guard
- Invalidate categories/features queries after creating/editing tools so new
categories appear immediately in search, browse dropdown and tool form
- Always refetch categories/features when the combobox/suggestion inputs mount
- Return JSON 404 for unmatched /api routes instead of the SPA index.html
- Read the manually confirmed 'better tool' from the recommendation notes
instead of using the min tool id in the redundancy dashboard
- Require admin for cost/relation update+delete endpoints
- Stop exposing the voter token in the ratings list response
- Fix parseInt type error on user id params (Express 5 params typing)