Tier 1 — Layout consistency:
* Move Stops tab action buttons (Upload Schedule, Add Stop) into the
filter bar, matching the Locations tab. One muscle memory for
'where the Add button is'. Removes the page-level StopsHeaderActions
component.
* Make the card a single cohesive unit. Tabs sit INSIDE the card on
top with a border-b, content fills the rest. No more 'rounded-b-2xl
rounded-t-none border-t-0' shape.
* New StopsLocationsTabs: pill-style tabs with icons + count badges +
sublabel ('269 · 7 cities'). Instant orientation. URL-driven via
Link so refresh + deep-linking work.
Tier 2 — Easier to scan:
* New StatsStrip under the page header: '269 stops · 7 cities · 4
states · 4 active · 5 draft · 0 inactive' (different stats for the
Locations tab). Context before the table loads.
* Stops table collapses 8 columns → 6: drop Brand, merge City+State
into 'Where', merge Date+Time into 'When' (date + weekday on one
line, time on the next). 30% more breathing room per row.
* Replace font-mono for dates/times with tabular-nums — same column
alignment, type family stays consistent.
* Click anywhere on a Stops row to edit. Redundant 'Edit' link is
gone. Kebab menu still handles Publish/Duplicate/Delete.
* Match Locations' empty state (icon + title + subtitle) on the Stops
side.
Polish:
* Consistent status pills (Active = emerald, Inactive = stone, Draft
= amber) in both tabs.
* Tab-switch fade via framer-motion AnimatePresence — subtle y/opacity
transition between Stops and Locations content.
* inspect_xlsx.py — one-off xlsx dumper used to discover the Stop
Directory sheet structure (14 lines, kept for reference when the
tour schedule xlsx is updated next season).
* scripts/seed_tuxedo_tour.py — Python+openpyxl seed script that
parsed the 3-week Tuxedo Corn 2026 tour schedule and inserted
269 stops via admin_create_stops_batch. Also linked each stop to
its Stop Directory venue (address/phone/contact) and self-published
by flipping status='draft' -> 'active'.
* supabase/migrations/202_delete_stop_orders_guard_fix.sql — fixes a
400 error on the admin Stop Table delete button. The delete_stop
RPC referenced o.deleted_at on the orders table, but that column
doesn't exist, so the SELECT raised 'column does not exist' and
PostgREST surfaced it as HTTP 400. The fix drops the redundant
o.deleted_at IS NULL clause (pickup_complete = false is sufficient
on its own); re-add it here if/when orders grows a deleted_at
column.
The previous backfill grouped by (name, address) only, which collapsed
Tractor Supply in Brighton, CO and Tractor Supply in Canon City, CO
into a single location whenever they shared the same address (or both
had a NULL address). Same problem for Ace Hardware, Murdoch's,
Big Tool Box, and JAX Farm & Ranch.
This migration re-dedupes by (name, city, address), re-links all 269
Tuxedo stops to the new per-city venues, and soft-deletes the 26
over-grouped original locations.
Result: 41 active locations (was 26). 269/269 stops re-linked.
Slug regex also fixed — previous [a-z0-9] stripped uppercase letters;
now uses [[:alnum:]].
* New 'locations' table for reusable venues (Tractor Supply, Boot Barn,
etc.) — each stop now links via stops.location_id while keeping the
denormalized location text for backwards compat.
* 6 SECURITY DEFINER RPCs: admin_create_location, admin_create_locations_batch,
admin_update_location, admin_delete_location, admin_attach_location_to_stop,
get_locations_for_brand. Plus admin_list_locations for the admin tab.
* Backfill: 26 unique venues extracted from the 269 Tuxedo stops, all linked.
* Stops & Routes page now has tabs (Stops | Locations) via ?tab= query param.
Locations tab has full CRUD UI: search, status filter, pagination, edit,
delete, add-venue modal.
* StopsHeaderActions now tab-aware — Upload Schedule / Add Stop only show on
Stops tab; Locations tab has its own Add Venue button inline.
- Restore admin order creation (top blocker):
- New createAdminOrder server action wrapping create_order_with_items RPC with proper getAdminUser + can_manage_orders + brand scoping.
- AdminOrdersPanel now supports ?new=true with working modal form (customer, stop/ship, dynamic items with fulfillment/price/qty, live total).
- Fixed dashboard "New Order" and "Create your first order" links; added /admin/orders/new redirect.
- Success flow: toast + redirect to list.
- Product edit reliability and admin flows hardened.
- Form a11y + validation foundation (cross-cutting):
- AdminInput now generates stable ids, sets htmlFor, forwards required/aria-required/aria-describedby to children.
- All admin forms benefit (labels programmatic, required semantics real).
- Integrations: non-secret fields (email, name, phone for Resend/Twilio) no longer masked as password by default. Only isSecret fields use type=password + toggle.
- Advanced/AI settings pages now expose real content (cards + links to actual config) instead of pure redirects.
- Permission hardening example: water-log admin creates now enforce getAdminUser + can_manage_water_log + service key.
- Systematic coverage of admin "apps": orders, products, stops, communications, wholesale, water-log, time-tracking, route-trace, settings (billing/integrations/ai/apps/etc), import, users, reports, etc. via exploration + targeted fixes. Empty states, toasts, scoping, quick actions improved.
- Updated MEMORY.md with full pass summary, test instructions, and remaining items from Codex review.
Non-destructive focus during pass; used dev auth for verification. Core blockers from review now addressed for testing.
See session plan.md for detailed execution guide.
- Update supabase/push-migrations.js:
- Detect modern Supabase CLI link state (supabase/.temp/project-ref)
- Prefer `supabase db query --linked --file` (works in this env where direct postgres connections fail with ENOTFOUND/network unreachable)
- Updated docs/comments for `supabase login` + `supabase link --project-ref wnzkhezyhnfzhkhiflrp` workflow
- Add MEMORY.md capturing the Supabase login/link session, tooling changes, migration patches applied, and gotchas
- Patch migrations for current remote schema (column drift, syntax, idempotency, pre-existing tables):
- 091_brand_plan_tier.sql: fix extra paren in get_brand_plan_info
- 145_create_product_images_bucket.sql: allowed_mime_types + DROP POLICY IF EXISTS + safer bucket insert
- 148_public_stops_rpc.sql: quote reserved "time" column in RETURNS TABLE + SELECT
- 200_production_features.sql: add ALTER TABLE for user_activity_logs (originated in 036) so policies/indexes validate
- 201_seed_data.sql: trim demo seeds with outdated column lists (products/stops/etc.); keep only compatible brands insert
- Include 202_fix_admin_create_stop.sql and related stop creation updates (src/actions/stops/create-stop.ts, 147_admin_create_stop_rpcs.sql, ADMIN_CREATE_STOP_FIX.sql)
- Update CLAUDE.md with pointer to MEMORY.md for recent migration work
Applied via the new flow (after supabase login + link): 084, 091, 142–148, 200–202 etc.
Refs: Supabase CLI now linked; use `node supabase/push-migrations.js <prefix>` or `npm run migrate:one NNN`
WaterFieldClient.tsx:
- Wrap entry-form section in <form onSubmit={handleSubmitEntry}>
(handler was defined but never bound to a form or button — submit
button did nothing). Submit button already had type="submit".
- Remove unused selectedRole state + its two setSelectedRole calls
(state was set at role-selection but never read).
wholesale/login/page.tsx:
- Remove unused 'name' prop from BrandLogo (was passed in but
never referenced inside the component).
Fixes CRI-17.
Server-side / caching refactor (Grok):
- New RPC get_public_stops_for_brand (migration 148) for public storefront stops
- New server action getPublicStopsForBrand with revalidate=300 + tags
- Add revalidateTag invalidation to createStopsBatch + publishStop
- Convert /tuxedo/stops and /indian-river-direct/stops to Server Components
- Extract TuxedoStopsList + IndianRiverStopsList as client islands (GSAP only)
- Removes supabase-js from browser bundle on those routes
- Both pages now statically prerendered (5m ISR)
Parallel agent changes also staged:
- AI provider model list refresh (claude-sonnet-4-5, etc.)
- ESLint directive patches for react-hooks/set-state-in-effect
- Admin + storefront + checkout + cart updates
- New admin_create_stop_rpcs migration (147)
- Misc fixes across ~90 files
Build verified: typecheck clean, lint clean on new files, production build succeeds.
Sidebar Tasks link points to /admin/time-tracking?tab=tasks
Sidebar Workers & PINs link points to /admin/time-tracking
Now TimeTrackingAdminPanel reads ?tab= URL param to set initial tab
- GlassModal: Add responsive padding, max-height with scroll, flex layout
- CreateUserModal: 2-col layout for name/phone on tablet+, tighter mobile spacing, full-width buttons stacked on mobile
- Matching landing page design aesthetic (warm cream)
- Added glass/blur backdrop effect to header
- Removed Cart button (not needed for this B2B platform)
- Links now use uppercase + letter-spacing for refined look
- Shows brand name when on brand routes
- Uses Route Commerce logo + font styling
- Matched landing page design aesthetic (warm cream tones, organic backgrounds)
- Added header with Route Commerce logo and back link
- Added footer with logo and minimal links
- Added security trust badges section:
- 256-bit SSL
- SOC 2 compliance
- Powered by Supabase
- Clean typography with Cormorant Garamond + Plus Jakarta Sans
- Subtle animations on page load
- Demo mode also styled to match
- Wrapped LandingPageClient with LandingPageWrapper
- Header now shows Sign In button next to Get Started
- Mobile menu also includes Sign In option
- Fixed Plus Jakarta Sans font import
- Redesigned landing page footer with cleaner layout
- Added subtle tagline 'Fresh produce, delivered fresh'
- Links now use uppercase + letter-spacing for refined look
- Better spacing (py-12 vs py-8) and gap management
- Official page links instead of hash anchors
- Copyright on separate line for better hierarchy
- Consistent with overall minimal aesthetic
- Fixed counter-animate to use gsap.fromTo with proper textContent interpolation
- Added footer section with logo, privacy/terms/security/contact links
- Added copyright notice with dynamic year
- Create /tuxedo/stops page showing all Tuxedo Corn pickup stops
- Create /indian-river-direct/stops page showing all Indian River Direct stops
- Each page features: upcoming/past stop separation, date badges, GSAP animations
- Link to individual stop detail pages
- Orange accent for IRD, emerald accent for Tuxedo
- Switch from stacked vertical cards to 2-column grid
- Reduce card padding and font sizes for compact display
- Add colored accent bar at top of each card
- Shrink header, hero, and footer sections
- Both brands now fit above the fold without scrolling
- Create src/actions/analytics.ts with real data fetching:
- getAnalyticsMetrics() - revenue, orders, customers, AOV
- getRevenueChart() - daily revenue data
- getTopProducts() - product performance from reports RPC
- getRecentOrders() - live orders from orders table
- getCustomerGrowth() - contact growth stats
- getConversionFunnel() - computed from order data
- Rewrite AnalyticsDashboard.tsx to:
- Fetch real data from Supabase via brand-scoped RPCs
- Show loading states and error handling
- Display actual metrics from the database
- Remove all mock data
- Add src/app/admin/analytics/page.tsx server component
All analytics now pull from real Supabase data instead of mock values.
Stripe SDK was being initialized at module load time, which failed
during Next.js build when STRIPE_SECRET_KEY wasn't set in the build
environment. Changed to lazy initialization pattern with proxy object
that creates the client on first access.
Fixes: Error: Neither apiKey nor config.authenticator provided
- Update Stripe API version to 2026-05-27.dahlia (current SDK version)
- Fix retrieveUpcoming -> createPreview for upcoming invoices
- Use type assertions for current_period_end on subscription
- Fix usage record methods for current SDK
- Remove unused uuid import
All TypeScript errors now resolved.
The Sentry Next.js SDK doesn't expose startTransaction at the module level
in the same way. Replaced with Sentry.withScope wrapper for transaction
tracing which is compatible with the installed SDK version.
- AdminSidebar: removed dropdown menu, flat nav links, no scrolling
- Removed SETTINGS_SUB_LINKS array
- Removed settingsOpen state and dropdown logic
- Settings is now a simple link to /admin/settings
- Nav uses overflow-hidden to prevent sidebar scroll
- SettingsClient: unified tabbed interface (like CommunicationsPage)
- New tabs: General, Add-ons, Billing, Integrations, AI, Advanced
- Uses AdminFilterTabs for navigation
- Each tab shows a card with link to full settings page
- Redirected pages to /admin/settings#tab:
- /admin/settings/apps → /admin/settings#addons
- /admin/settings/integrations → /admin/settings#integrations
- /admin/settings/ai → /admin/settings#ai
- /admin/advanced → /admin/settings#advanced
All TypeScript checks pass.
- Changed from dark theme (zinc-900) to admin light theme (white bg)
- Updated status badges to use light backgrounds instead of dark
- Changed all text colors to use admin CSS variables
- Fixed buttons and interactive elements to use admin accent color
- Modal now uses white background with proper border styling