This commit is contained in:
shafi54 2026-09-05 11:45:08 +05:30
parent bfb67e626b
commit d58530075d
13 changed files with 43 additions and 44 deletions

View file

@ -100,7 +100,7 @@ er-ui/app/(drawer)/(tabs)/home/index.tsx, I want similar here") and expects the
- When the two DB-helper implementations diverge at the data-model level (sqlite is SKU-based with skuIds; the dormant postgres collapsed the SKU tier into productIds), the live/canonical model wins: the sqlite/SKU model — which packages/shared already standardizes on — is the source of truth and the dormant postgres helper is to be aligned/migrated to it (up to and including schema-level changes so even row types match), not the reverse. Confidence: 0.75 - When the two DB-helper implementations diverge at the data-model level (sqlite is SKU-based with skuIds; the dormant postgres collapsed the SKU tier into productIds), the live/canonical model wins: the sqlite/SKU model — which packages/shared already standardizes on — is the source of truth and the dormant postgres helper is to be aligned/migrated to it (up to and including schema-level changes so even row types match), not the reverse. Confidence: 0.75
- The dedup directive is general, not limited to DB helpers: for types that are "exactly same but repeated" anywhere in the monorepo, move them into a shared package (@packages/shared), organize them there with proper comments, and export/reuse them from that one source — "Do this for all the types which are same and repeated" (stated when asking to address the duplicate-type spread repo-wide). Confidence: 0.8 - The dedup directive is general, not limited to DB helpers: for types that are "exactly same but repeated" anywhere in the monorepo, move them into a shared package (@packages/shared), organize them there with proper comments, and export/reuse them from that one source — "Do this for all the types which are same and repeated" (stated when asking to address the duplicate-type spread repo-wide). Confidence: 0.9
- When organizing a shared type package, prefers to keep similar types together — all types that have identical properties should stay grouped/collocated so exact duplicates live side by side (e.g., clustering same-shaped types together in the shared files rather than scattering them). Confidence: 0.75 - When organizing a shared type package, prefers to keep similar types together — all types that have identical properties should stay grouped/collocated so exact duplicates live side by side (e.g., clustering same-shaped types together in the shared files rather than scattering them). Confidence: 0.75
e changes. Confidence: 0.95 e changes. Confidence: 0.95

View file

@ -1,20 +1,12 @@
import { create } from 'zustand'; import { create } from 'zustand';
import { devtools } from 'zustand/middleware'; import { devtools } from 'zustand/middleware';
import type { IdName } from '@packages/shared';
interface User { type User = IdName;
id: number;
name: string;
}
interface Role { type Role = IdName;
id: number;
name: string;
}
interface Permission { type Permission = IdName;
id: number;
name: string;
}
interface UserWithRole extends User { interface UserWithRole extends User {
role: Role | null; role: Role | null;

View file

@ -1001,3 +1001,41 @@ Verification: user-ui 106, admin-ui 122, backend 11 (all = baselines); fallback-
[2026-09-05 11:25:00] COMPLETED Cluster-2 TabIconProps unification (6 files + shared def). [2026-09-05 11:25:00] COMPLETED Cluster-2 TabIconProps unification (6 files + shared def).
Added shared TabIconProps {focused, size, color} in primitives.types.ts (auto-exported via existing primitives star). Replaced all 6 local interfaces (5 user-ui icons + ui CartIcon), each verified single local use, zero cross-file consumers. Added shared TabIconProps {focused, size, color} in primitives.types.ts (auto-exported via existing primitives star). Replaced all 6 local interfaces (5 user-ui icons + ui CartIcon), each verified single local use, zero cross-file consumers.
Verification: user-ui 106, admin-ui 122, backend 11 (all = baselines); zero leftover local interfaces. Docs: cluster-02 file + types_inventory status section marked resolved. Verification: user-ui 106, admin-ui 122, backend 11 (all = baselines); zero leftover local interfaces. Docs: cluster-02 file + types_inventory status section marked resolved.
[2026-09-05 11:25:09] Cluster-04 (ProductRow): NOT unified — sqlite vs pg productInfo schemas differ (sqlite: storeId/incrementStep/productType; pg: unitId/price/images/flags), so one shared alias cannot represent both. Correct action instead: delete the 2 DEAD copies.
- packages/db_helper_postgres/src/admin-apis/vendor-snippets.ts: delete line 15 type ProductRow = InferSelectModel<typeof productInfo> (zero references anywhere)
- packages/db_helper_sqlite/src/admin-apis/vendor-snippets.ts: delete line 16 type ProductRow = InferSelectModel<typeof productInfo> (zero references anywhere)
Kept local (live, genuinely different types): pg product.ts:31 (1 use), sqlite product.ts:64 (2 uses).
[2026-09-05 11:28:00] COMPLETED Cluster-04 ProductRow handling (unification declined, dead copies removed).
Verification: tsc sqlite 4, pg 45 (both = baselines). Zero ProductRow references remain in either vendor-snippets.ts. Docs: cluster-04 file updated.
[2026-09-05 11:31:26] Cluster-05 (StoreRow): NOT unified — both live aliases evaluate the same today (identical storeInfo columns; both mapStores assign cleanly to shared Store), but no shared InferSelectModel source exists and hand-written copies would go silently stale. Correct action instead: delete the 2 DEAD copies.
- packages/db_helper_postgres/src/user-apis/stores.ts: delete line 7 type StoreRow = InferSelectModel<typeof storeInfo> (zero references anywhere)
- packages/db_helper_sqlite/src/user-apis/stores.ts: delete line 8 type StoreRow = InferSelectModel<typeof storeInfo> (zero references anywhere)
Kept local (live, self-maintaining mirrors): pg product.ts:33 (1 use), sqlite product.ts:103 (2 uses).
[2026-09-05 11:32:00] FOLLOW-UP cluster-05: remove orphaned imports left by StoreRow deletions.
- packages/db_helper_postgres/src/user-apis/stores.ts: delete line 4 import type { InferSelectModel } from 'drizzle-orm' (no remaining uses in file)
- packages/db_helper_sqlite/src/user-apis/stores.ts: delete line 4 import type { InferSelectModel } from 'drizzle-orm' (no remaining uses in file)
[2026-09-05 11:34:00] COMPLETED Cluster-05 StoreRow handling (unification declined, dead copies removed).
Verification: tsc sqlite 4, pg 45 (both = baselines). Zero StoreRow references remain in either user-apis/stores.ts. Docs: cluster-05 file updated.
[2026-09-05 11:36:35] Clusters 06-56 survey: no cluster carries a unify verdict — all are keep-local (schema-bound mirrors, RN/web independence, drifted shapes, circular deps) except dead-copy deletions. Executing dead-only cleanup:
- c15: migrator postgresToSqlite/index.ts lines 7-10 + sqliteToPostgres/index.ts lines 5-8 — delete dead `interface TableInfo` (ColumnInfo stays, live). No unification (ColumnInfo differs per direction).
- c28: pg + sqlite user-apis/complaint.ts line 7 — delete dead `type ComplaintRow`; line 4 `InferSelectModel` import orphaned in both, delete too.
[2026-09-05 11:39:00] Clusters 35/36/37/39/43 dead-copy deletions (unification declined per file verdicts — schema-bound mirrors stay local).
- pg admin-apis/product.ts: delete line 36 type ProductTagRow (c39, dead) + lines 37-39 ProductGroupRow / ProductGroupMembershipRow / ProductReviewRow (c35-37, dead). Keep 35 ProductTagInfoRow (live), 161/162 Insert/Update (live).
- sqlite admin-apis/product.ts: delete lines 107-109 ProductGroupRow / ProductGroupMembershipRow / ProductReviewRow (c35-37, dead) + line 302 type ProductInfoUpdate = Partial<ProductInfoInsert> (c43, dead). Keep 106 ProductTagRow (5 uses), 301 ProductInfoInsert (live).
InferSelectModel/InferInsertModel imports stay (other live aliases in both files).
[2026-09-05 11:42:00] COMPLETED type-cluster dead-copy sweep (clusters 15, 28, 35, 36, 37, 39, 43 — 12 deletions total).
Verification: tsc sqlite 4, pg 45 (= baselines), migrator 0 errors. All deleted names grep-blank; live counterparts intact (sqlite ProductTagRow 6 refs, pg ProductInfoUpdate 2 refs). Docs: 7 cluster files updated.
FINAL POSITION on "unify the rest" (06-56): no cluster carries a unify verdict. Keep-local reasons per file: schema-bound InferSelectModel mirrors (16,26,27,29-34,38,40-42 + remaining 39/43), drifted/differing shapes (07,15,18,19,22,25,45,46,49,50,55,56), intentionally distinct shared types (10,18), RN/web independence (11-14,47,51-54,56), single-use co-located props (08), backend-circular (23-25), out-of-scope fallback-ui (06,09 partial w/ shared canonical already, 48), per-app collisions (44,49,50).
[2026-09-05 11:45:00] Cluster-06: use shared IdName in fallback-ui userStore.ts.
- apps/fallback-ui/src/stores/userStore.ts: delete local `interface User/Role/Permission` (each exactly {id:number;name:string}); add import type { IdName } from '@packages/shared' + type User = IdName / type Role = IdName / type Permission = IdName. Names kept (UserWithRole extends User + store shape unchanged); only the hook is exported so no external imports affected.
[2026-09-05 11:47:00] COMPLETED Cluster-06 IdName adoption. Verification: fallback-ui tsc 107 = baseline, zero errors in userStore.ts. Docs: cluster-06 file updated.

View file

@ -33,10 +33,6 @@ type UnitRow = InferSelectModel<typeof units>
type StoreRow = InferSelectModel<typeof storeInfo> type StoreRow = InferSelectModel<typeof storeInfo>
type SpecialDealRow = InferSelectModel<typeof specialDeals> type SpecialDealRow = InferSelectModel<typeof specialDeals>
type ProductTagInfoRow = InferSelectModel<typeof productTagInfo> type ProductTagInfoRow = InferSelectModel<typeof productTagInfo>
type ProductTagRow = InferSelectModel<typeof productTags>
type ProductGroupRow = InferSelectModel<typeof productGroupInfo>
type ProductGroupMembershipRow = InferSelectModel<typeof productGroupMembership>
type ProductReviewRow = InferSelectModel<typeof productReviews>
const getStringArray = (value: unknown): string[] | null => { const getStringArray = (value: unknown): string[] | null => {
if (!Array.isArray(value)) return null if (!Array.isArray(value)) return null

View file

@ -12,7 +12,6 @@ import type {
type VendorSnippetRow = InferSelectModel<typeof vendorSnippets> type VendorSnippetRow = InferSelectModel<typeof vendorSnippets>
type DeliverySlotRow = InferSelectModel<typeof deliverySlotInfo> type DeliverySlotRow = InferSelectModel<typeof deliverySlotInfo>
type ProductRow = InferSelectModel<typeof productInfo>
const mapVendorSnippet = (snippet: VendorSnippetRow): AdminVendorSnippet => ({ const mapVendorSnippet = (snippet: VendorSnippetRow): AdminVendorSnippet => ({
id: snippet.id, id: snippet.id,

View file

@ -1,11 +1,8 @@
import { db } from '../db/db_index' import { db } from '../db/db_index'
import { complaints } from '../db/schema' import { complaints } from '../db/schema'
import { asc, eq } from 'drizzle-orm' import { asc, eq } from 'drizzle-orm'
import type { InferSelectModel } from 'drizzle-orm'
import type { UserComplaint } from '@packages/shared' import type { UserComplaint } from '@packages/shared'
type ComplaintRow = InferSelectModel<typeof complaints>
export async function getUserComplaints(userId: number): Promise<UserComplaint[]> { export async function getUserComplaints(userId: number): Promise<UserComplaint[]> {
const userComplaints = await db const userComplaints = await db
.select({ .select({

View file

@ -1,10 +1,8 @@
import { db } from '../db/db_index' import { db } from '../db/db_index'
import { productInfo, storeInfo, units } from '../db/schema' import { productInfo, storeInfo, units } from '../db/schema'
import { and, eq, sql } from 'drizzle-orm' import { and, eq, sql } from 'drizzle-orm'
import type { InferSelectModel } from 'drizzle-orm'
import type { UserStoreDetailData, UserStoreProductData, UserStoreSummaryData, StoreSummary } from '@packages/shared' import type { UserStoreDetailData, UserStoreProductData, UserStoreSummaryData, StoreSummary } from '@packages/shared'
type StoreRow = InferSelectModel<typeof storeInfo>
type StoreProductRow = { type StoreProductRow = {
id: number id: number
name: string name: string

View file

@ -104,9 +104,6 @@ type StoreRow = InferSelectModel<typeof storeInfo>
type SpecialDealRow = InferSelectModel<typeof specialDeals> type SpecialDealRow = InferSelectModel<typeof specialDeals>
type ProductTagInfoRow = InferSelectModel<typeof productTagInfo> type ProductTagInfoRow = InferSelectModel<typeof productTagInfo>
type ProductTagRow = InferSelectModel<typeof productTags> type ProductTagRow = InferSelectModel<typeof productTags>
type ProductGroupRow = InferSelectModel<typeof productGroupInfo>
type ProductGroupMembershipRow = InferSelectModel<typeof productGroupMembership>
type ProductReviewRow = InferSelectModel<typeof productReviews>
const getStringArray = (value: unknown): string[] | null => { const getStringArray = (value: unknown): string[] | null => {
if (!Array.isArray(value)) return null if (!Array.isArray(value)) return null
@ -299,7 +296,6 @@ export async function deleteProduct(id: number): Promise<AdminProduct | null> {
} }
type ProductInfoInsert = InferInsertModel<typeof productInfo> type ProductInfoInsert = InferInsertModel<typeof productInfo>
type ProductInfoUpdate = Partial<ProductInfoInsert>
export async function createProduct(input: CreateProductInput): Promise<AdminProductWithRelations> { export async function createProduct(input: CreateProductInput): Promise<AdminProductWithRelations> {
if (!input.skus || input.skus.length === 0) { if (!input.skus || input.skus.length === 0) {

View file

@ -13,7 +13,6 @@ import { coerceDate } from '../lib/date'
type VendorSnippetRow = InferSelectModel<typeof vendorSnippets> type VendorSnippetRow = InferSelectModel<typeof vendorSnippets>
type DeliverySlotRow = InferSelectModel<typeof deliverySlotInfo> type DeliverySlotRow = InferSelectModel<typeof deliverySlotInfo>
type ProductRow = InferSelectModel<typeof productInfo>
const mapVendorSnippet = (snippet: VendorSnippetRow): AdminVendorSnippet => ({ const mapVendorSnippet = (snippet: VendorSnippetRow): AdminVendorSnippet => ({
id: snippet.id, id: snippet.id,

View file

@ -1,11 +1,8 @@
import { db } from '../db/db_index' import { db } from '../db/db_index'
import { complaints } from '../db/schema' import { complaints } from '../db/schema'
import { asc, eq } from 'drizzle-orm' import { asc, eq } from 'drizzle-orm'
import type { InferSelectModel } from 'drizzle-orm'
import type { UserComplaint } from '@packages/shared' import type { UserComplaint } from '@packages/shared'
type ComplaintRow = InferSelectModel<typeof complaints>
export async function getUserComplaints(userId: number): Promise<UserComplaint[]> { export async function getUserComplaints(userId: number): Promise<UserComplaint[]> {
const userComplaints = await db const userComplaints = await db
.select({ .select({

View file

@ -1,12 +1,9 @@
import { db } from '../db/db_index' import { db } from '../db/db_index'
import { productInfo, productSkus, storeInfo } from '../db/schema' import { productInfo, productSkus, storeInfo } from '../db/schema'
import { and, asc, eq, inArray } from 'drizzle-orm' import { and, asc, eq, inArray } from 'drizzle-orm'
import type { InferSelectModel } from 'drizzle-orm'
import type { UserStoreDetailData, UserStoreProductData, UserStoreSummaryData, StoreSummary } from '@packages/shared' import type { UserStoreDetailData, UserStoreProductData, UserStoreSummaryData, StoreSummary } from '@packages/shared'
import { composeSkuName, composeUnitNotation } from '../lib/sku-features' import { composeSkuName, composeUnitNotation } from '../lib/sku-features'
type StoreRow = InferSelectModel<typeof storeInfo>
const getStringArray = (value: unknown): string[] | null => { const getStringArray = (value: unknown): string[] | null => {
if (!Array.isArray(value)) return null if (!Array.isArray(value)) return null
return value.map((item) => String(item)) return value.map((item) => String(item))

View file

@ -4,11 +4,6 @@ import { postgresConfig, sqliteConfig, migrationConfig, logConfig } from '../con
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
interface TableInfo {
tableName: string;
columns: ColumnInfo[];
}
interface ColumnInfo { interface ColumnInfo {
name: string; name: string;
type: string; type: string;

View file

@ -2,11 +2,6 @@ import { Client } from 'pg';
import Database from 'better-sqlite3'; import Database from 'better-sqlite3';
import { postgresConfig, sqliteConfig, migrationConfig, logConfig } from '../config'; import { postgresConfig, sqliteConfig, migrationConfig, logConfig } from '../config';
interface TableInfo {
tableName: string;
columns: ColumnInfo[];
}
interface ColumnInfo { interface ColumnInfo {
name: string; name: string;
type: string; type: string;