Technical Debt Assessment
Critical issues
Section titled “Critical issues”In-memory storage
Section titled “In-memory storage”server/storage.ts implements MemStorage using Map<number, T> for users, orders, integrations, and notifications. A hardcoded admin user is seeded on startup:
// Simplified — actual code in server/storage.tsclass MemStorage { private users = new Map<number, User>(); private orders = new Map<number, Order>(); // ... all volatile, lost on restart}The Drizzle schema in shared/schema.ts defines proper tables (users, orders, integrations, notifications) but they are never connected to a real database. The schema exists as a type definition only.
Hardcoded credential bypass
Section titled “Hardcoded credential bypass”server/auth.ts line 28 contains a direct password comparison that bypasses the scrypt hash:
if (supplied === 'admin123' && stored === '$2b$10$x5SafT...') { return true; // bypasses scrypt verification}This means the admin password is effectively admin123 regardless of what the hash says.
Unauthenticated endpoints
Section titled “Unauthenticated endpoints”The majority of route files — performance metrics, combo logs, tag classifications, tag analytics, tag groups, designers, asset ingest — have zero req.isAuthenticated() checks. Only a handful of legacy routes in server/routes.ts (integrations, orders, notifications) are protected. Combined with the split auth model, 40+ endpoints are effectively public.
No sync scheduling
Section titled “No sync scheduling”Shopify data sync is manual-only. The syncShopifyData function in server/services/shopify-sync.ts is exported but never called on a schedule. The only way to refresh data is through a manual trigger — and the /api/performance-metrics/sync endpoint returns 501 Not Implemented.
Architectural issues
Section titled “Architectural issues”Dual authentication systems
Section titled “Dual authentication systems”The backend uses Passport.js local strategy with Express sessions (stored in MemoryStore), while the frontend uses Supabase Auth with JWT tokens. These two systems don’t share state:
- Backend:
req.isAuthenticated()checks Passport session - Frontend:
useAuth()hook checks Supabase session viaonAuthStateChange - API calls from the frontend don’t carry Supabase JWT to Express
- Express sessions are volatile (MemoryStore, lost on restart)
Cloudflare Access eliminates this by providing a single identity plane.
Duplicated Shopify clients
Section titled “Duplicated Shopify clients”Shopify API access is implemented independently in 6 locations:
server/services/shopify-sync.ts— REST pagination for products/ordersserver/services/asset-ingest.ts— REST + Client Credentials Grant for metafieldssupabase/functions/sync-performance-data/— REST + GraphQL Bulk Operationssupabase/functions/sync-product-tags/— REST paginationsupabase/functions/generate-casestry-orders-csv/— REST order fetchsupabase/functions/shopify-order-lookup/— REST with rate-limit retry
Each independently handles authentication, pagination, rate limiting, and error handling. The target architecture consolidates this into a single shared module.
Materialized views without refresh scheduling
Section titled “Materialized views without refresh scheduling”mart.performance_metrics and mart.tag_performance_aggregate are PostgreSQL materialized views that require REFRESH MATERIALIZED VIEW calls. These are triggered only by:
- Manual API call to
/api/tag-analytics/refresh - Edge function execution (manual trigger)
There is no cron or scheduled refresh. The target system replaces materialized views with explicit table writes on a Cron Trigger schedule.
What’s good
Section titled “What’s good”Despite the debt, several design decisions are sound and carry forward:
- Warehouse layering (
raw → core → mart) is the right pattern for Shopify data - Run tracking via
raw.ingest_runsrecords every sync with duration, row counts, and error details - Idempotent upserts in several code paths (
ON CONFLICTfor dim_products, performance metrics; SHA-256 checksums for assets) - Checksum-based deduplication for assets prevents duplicate uploads
- Tag-based analytics with GIN-indexed arrays enables flexible filtering
- Combo ID convention (
SP-IPH-2-WOMEN-001) provides human-readable, sortable identifiers - React Query for server state management is idiomatic and efficient
- shadcn/ui components are well-structured and easily portable