feat: migrate setup visibility from boolean to three-tier system
Replace isPublic boolean with visibility enum (private/link/public) across the full stack. Add shares table to schema for future share link support. Update all services, routes, schemas, hooks, components, and tests. Plan: 32-01 (Setup Sharing System - Schema Migration) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -114,7 +114,7 @@ app.post("/delete", zValidator("json", deleteAccountSchema), async (c) => {
|
||||
await tx
|
||||
.update(setups)
|
||||
.set({ userId: sentinel.id })
|
||||
.where(and(eq(setups.userId, userId), eq(setups.isPublic, true)));
|
||||
.where(and(eq(setups.userId, userId), eq(setups.visibility, "public")));
|
||||
|
||||
// 3. Get private setup IDs for cleanup
|
||||
const privateSetups = await tx
|
||||
|
||||
@@ -21,7 +21,7 @@ interface CursorPage<T> {
|
||||
/**
|
||||
* Get popular public setups ordered by item count descending.
|
||||
* Cursor format: "{itemCount}_{id}" for stable composite pagination.
|
||||
* Only public setups (isPublic=true) are returned.
|
||||
* Only public setups (visibility='public') are returned.
|
||||
*/
|
||||
export async function getPopularSetups(
|
||||
db: Db = prodDb,
|
||||
@@ -50,7 +50,7 @@ export async function getPopularSetups(
|
||||
.from(setups)
|
||||
.leftJoin(setupItems, eq(setupItems.setupId, setups.id))
|
||||
.leftJoin(users, eq(users.id, setups.userId))
|
||||
.where(eq(setups.isPublic, true))
|
||||
.where(eq(setups.visibility, "public"))
|
||||
.groupBy(setups.id, setups.name, setups.createdAt, users.displayName)
|
||||
.orderBy(desc(sql<number>`COUNT(${setupItems.id})`), desc(setups.id))
|
||||
.limit(fetchLimit);
|
||||
|
||||
@@ -79,7 +79,7 @@ export async function getPublicProfile(db: Db, userId: number) {
|
||||
), 0)`.as("total_cost"),
|
||||
})
|
||||
.from(setups)
|
||||
.where(and(eq(setups.userId, userId), eq(setups.isPublic, true)));
|
||||
.where(and(eq(setups.userId, userId), eq(setups.visibility, "public")));
|
||||
|
||||
return { ...user, setups: publicSetups };
|
||||
}
|
||||
@@ -88,7 +88,7 @@ export async function getPublicSetupWithItems(db: Db, setupId: number) {
|
||||
const [setup] = await db
|
||||
.select()
|
||||
.from(setups)
|
||||
.where(and(eq(setups.id, setupId), eq(setups.isPublic, true)));
|
||||
.where(and(eq(setups.id, setupId), eq(setups.visibility, "public")));
|
||||
|
||||
if (!setup) return null;
|
||||
|
||||
|
||||
@@ -14,7 +14,11 @@ type Db = typeof prodDb;
|
||||
export async function createSetup(db: Db, userId: number, data: CreateSetup) {
|
||||
const [row] = await db
|
||||
.insert(setups)
|
||||
.values({ name: data.name, userId, isPublic: data.isPublic ?? false })
|
||||
.values({
|
||||
name: data.name,
|
||||
userId,
|
||||
visibility: data.visibility ?? "private",
|
||||
})
|
||||
.returning();
|
||||
|
||||
return row;
|
||||
@@ -25,7 +29,7 @@ export async function getAllSetups(db: Db, userId: number) {
|
||||
.select({
|
||||
id: setups.id,
|
||||
name: setups.name,
|
||||
isPublic: setups.isPublic,
|
||||
visibility: setups.visibility,
|
||||
createdAt: setups.createdAt,
|
||||
updatedAt: setups.updatedAt,
|
||||
itemCount: sql<number>`COALESCE((
|
||||
@@ -129,8 +133,8 @@ export async function updateSetup(
|
||||
name: data.name,
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
if (data.isPublic !== undefined) {
|
||||
updateData.isPublic = data.isPublic;
|
||||
if (data.visibility !== undefined) {
|
||||
updateData.visibility = data.visibility;
|
||||
}
|
||||
|
||||
const [row] = await db
|
||||
|
||||
Reference in New Issue
Block a user