KATURA
Your browser is not supported. Please update your iPad to the latest iOS version, or visit us on a newer device.
How to update your iPad Skip to main content JOIN THE WORLD OF KATURA Be the first to discover new collections, exclusive events, and the stories behind our legendary creations.
KaturaβCrafting timeless treasures since 1999.
The technology behind Katura is built in-house. K99 is our jewelry business platform β available to other jewelers.
Β© 2026 KATURA. All rights reserved.
πΊπΈ English EN πΊπΈ United States $
Software Updates Β· KATURA | KATURA
Live from GitHub Β· Refreshed continuously
Software Updates Every change we ship to katura1999.com β features, fixes, security patches, the lot. Pulled straight from our private GitHub repository so you can see exactly what was built and when.
By the numbers Lines of code
850,259
Web platform β TypeScript, React, Prisma, CSS
iOS
79,607
Swift + SwiftUI lines
Android
3,117
Kotlin + Jetpack Compose lines
All platforms
932,983
Web + iOS + Android combined (45.8Γ the King James Bible)
Characters written
36.05M
36,053,358 total characters
Updates pushed
2,087
exact commit count on main
Current version
v1.20.87
build 2087 Β· 40f34e0
Database models
411
across 47 schema files β most SaaS platforms have 20β50
API endpoints
988
individually routed β Stripe's public API has ~400
Translated strings
82,512
every string, in 24 languages
System permutations
10^297
2^988 endpoint combinations β more than atoms in the observable universe (10^80)
Project age
8mo 1d
since Dec 14, 2025
Pre-AI dev hours
31.1K hrs
932,983 lines Γ· 30 LOC/hr β equivalent to 15.0 years (senior engineer, no AI)
With-AI dev hours
7.8K hrs
4Γ AI productivity multiplier (2024β2026 studies) β equivalent to 972 days
Equivalent firm cost
$8,119,493
live ticker Β· Katura rate: $60 USD/hr
Hours estimated from source line count at 30 LOC/hr (industry benchmark for production-quality TypeScript/React without AI assistance), with a 4Γ multiplier for AI-assisted development per published 2024β2026 enterprise studies. Equivalent Firm Cost uses a $250/hr loaded billable rate reflecting a premium engineering firm building enterprise-grade SaaS β and ticks up live, because the project is still being actively built.
Commit history
2,087 updates pushed Showing page 7 of 40 Β· 301β350 of 2,000 fetched
Monday, May 18, 2026 38 updates pushed
Feature yen-digest 9:32 AM Β· ZRosserMcIntosh
full team rollout, server-side emoji strip, reply note Add full Katura team recipients: Rosser (gmail + katura), Stella, Antar, Pedro, Lee β removes the YEN_DIGEST_APPROVED gate entirely Add stripEmoji() post-processor that cleans all Unicode emoji ranges from AI output regardless of prompt compliance (belt + suspenders) Update footer to explicitly name yen@katura1999.com as the reply address Remove ROSSER_EMAIL / APPROVED_TEAM constants β TEAM is the single source Comment header updated to reflect production state (no more Phase 1) Update build 9:23 AM Β· ZRosserMcIntosh
revert workerThreads true β DOMException crash in worker context Feature yen-digest 9:17 AM Β· ZRosserMcIntosh
9AM EST schedule, no emojis, full commit body, gpt-4.5-preview cron schedule 0 9 β 0 14 UTC = 9AM EST / 10AM EDT Switch model gpt-4o β gpt-4.5-preview for highest detail output Remove all emojis from section headers and prompt Send full commit message body to AI (not just subject line) for technical depth: file names, function names, numbers, rationale 2 sentences per item: technical what + plain-English why it matters Skip trivial commits (version bumps, whitespace) max_tokens 1800 β 2400, temperature 0.72 β 0.65 Feature software-updates 8:46 AM Β· ZRosserMcIntosh
show per-platform LOC (iOS/Android/Website) + cumulative totals compute-repo-stats: shallow-clone katura-ios + katura-android into /tmp, walk with same rules, add to cumulative totalLines/totalChars live-stats: Row 1 now shows iOS / Android / Website / Total Lines of Code Characters Written and Pre-AI/With-AI hours use combined LOC from all 3 repos page.tsx: pass websiteLines, iosLines, androidLines props Feature seo 8:26 AM Β· ZRosserMcIntosh
add IndexNow key file for Bing ownership verification Update stl-viewer 8:04 AM Β· ZRosserMcIntosh
rose gold hue shift to peach-salmon; build: cpus 2β4 + workerThreads All three karats were too dark/orange-brown under calmed env settings Shift hue toward pink-salmon (the 'rose' in rose gold), lighter base values: 18K #C87060 β #D4907E (peach-salmon) 14K #B85E4A β #C8826E 10K #A44C38 β #BC7468 (still copper-warm but rosy, not spray paint) Roughness 10K 0.20 β 0.18, metalness 0.93 β 0.92 across all rose golds cpus: 2 β 4 (use all 4 Vercel build container vCPUs) workerThreads: false β true (safe with 7168MB NODE_OPTIONS heap) Feature seo+wholesale 7:54 AM Β· ZRosserMcIntosh
product indexing cron, sitemap resubmission, wholesale email retry queue gsc-monitor: parameterise auth scope; add resubmitSitemap() using webmasters write scope cron/gsc-monitor: call resubmitSitemap() on every Monday run; surface result in response cron/index-products: new daily 06:00 UTC cron β bulk submits all ACTIVE products to IndexNow (batch, no quota) + Google Indexing API (10/batch, 200/day limit); pings sitemap to both Google and Bing. Fixes 'Discovered - currently not indexed' GSC issue. Supports ?mode=recent (default, last 8 days) and ?mode=all (backfill, 200 products/run) cron/wholesale-email-retry: new daily 09:00 UTC cron β retries failed confirmation + internal notification emails up to 3Γ with structured tracking columns; dead-letters after 3 failures and fires sendInternalAlert(severity='error') wholesale/apply: stamp confirmationEmailSentAt / internalEmailSentAt on success; use new emailRetryCount/emailLastError columns instead of freetext notes hack; restore missing try{} block; pass db to logFailedEmail prisma/schema/wholesale: add 4 tracking columns to WholesaleLead scripts/db-migrations: add-wholesale-email-tracking.sql migration vercel.json: add /api/cron/index-products and /api/cron/wholesale-email-retry Update stl-viewer 7:48 AM Β· ZRosserMcIntosh
Cineon tone mapping + recalibrate all metal colors Switch ACESFilmicToneMapping β CineonToneMapping (ACES was shifting saturated yellows to chartreuse green in highlights) toneMappingExposure 1.8 β 1.3, environmentIntensity 2.5 β 1.5, envMapIntensity 2.8 β 1.5 (combined ~7Γ env was bleaching rose gold) Recalibrate all gold base colors to amber spectrum: 24K #C8880A, 18K #BD8008, 14K #B07408, 10K #A06808 Recalibrate rose golds to deep coppery-pink: 18K #C87060, 14K #B85E4A, 10K #A44C38 Calm hemisphere (0.65β0.45), bottom fill (1.2β0.5), ambient (0.4β0.25) Update stale comment (environmentIntensity 2.5 β 1.5) Docs learnings 7:41 AM Β· ZRosserMcIntosh
lessons 101-200 β features, commerce ops, and immediate improvement recommendations Feature yen 7:33 AM Β· ZRosserMcIntosh
weekly dev digest cron β Yen emails the team every Monday with a GPT-4o breakdown of all GitHub commits Uses GITHUB_TOKEN env var if set (raises rate limit 60β5000/hr) 3. Sends commit list to GPT-4o with Yen's persona prompt Groups commits by type: New Features / Improvements / Bug Fixes / Infrastructure / Security / Design / AI / Dependencies Punchy tone, 1-sentence bullets, focused on what matters 4. Builds branded HTML email and sends via Brevo from yen@katura1999.com YEN_DIGEST_APPROVED env var not set β sends ONLY to rosserembrasil@gmail.com Set YEN_DIGEST_APPROVED=true in Vercel env + add team list to APPROVED_TEAM array to enable full distribution after Rosser approves the format CRON_SECRET protected (same pattern as all other cron routes) Recipient list is hardcoded in source β no external/user-controlled emails Full team distribution requires a code change to add addresses No inbound parsing, no untrusted email addresses reach the AI Dark header bar (#1a1a1a) with 'Katura Intelligence / Weekly Dev Digest' Commit count + date badge AI-written digest body (Georgia serif, clean inline styles) Yen signature: circular logo + name/title/email + personal note 'You're welcome to reply... I'm available 24/7/365' Reply-To: yen@katura1999.com (Yen email responder handles replies) Footer: small legal note + commit count Docs learnings 7:21 AM Β· ZRosserMcIntosh
Top 100 lessons from Katura for future projects 100 lessons across: DB/Prisma/PgBouncer, Next.js, Security, API design, SaaS multi-tenancy, Auth, Supabase Storage, Email, Cron jobs, Monitoring, SEO, TypeScript, Cost optimization, Stripe, Three.js, React UX, DX, Architecture. Update stl-viewer 7:19 AM Β· ZRosserMcIntosh
eliminate black renders, add surface finishes, add white gold karat grades Added FINISH_PRESETS constant (polished/satin/brushed/matte) Each finish is a roughness multiplier applied on top of the metal's base roughness β zero latency, no texture maps needed polished: Γ1.0 (mirror polish, existing behavior) satin: Γ3.5 (soft sheen, broader highlights) brushed: Γ5.5 (directional matte approximation) matte: Γ8.0 (fully diffuse, velvety) Added finish state + Select dropdown to STLViewerCanvas toolbar Added finish state + Select dropdown to STLAssemblyViewer toolbar Threaded finish prop through STLModel, AssemblyModel, AssemblyPart 18K White Gold: #F8F6F2, roughness 0.10 (thick rhodium plating β pure white) 14K White Gold: #F0EBE0, roughness 0.12 (thinner plating, slight cream cast) 10K White Gold: #E6DDCA, roughness 0.14 (more yellow base visible at edges) Legacy 'white-gold' key β hidden, maps to 18K for backward compat Yellow gold: richer, more saturated base colors per karat Rose gold: slightly more vivid pink tones All golds + silver: metalness 0.92/0.95 (was 1.0) to allow diffuse warmth Feature cron 7:13 AM Β· ZRosserMcIntosh
Google Search Console weekly monitor Fetches GSC Search Analytics for the current 7-day window (skips last 2 days due to GSC data lag β uses 'final' state only) Compares vs. the prior 7-day window: flags pages with >40% click drop that have >50 impressions (filters out noise from low-traffic pages) Fetches all sitemaps and flags any with crawl errors Posts a Slack digest ONLY when issues are found (no noise on healthy weeks) Returns full JSON report in Vercel function logs for manual review Update db-resilience 7:07 AM Β· ZRosserMcIntosh
serialize all Promise.all() Prisma queries to prevent P2024 pool timeout crashes Added withFallback import from db-resilience getTenantProductSummary: 5 concurrent counts β 5 sequential withFallback calls getTenantProducts: Promise.all([findMany, count]) β sequential withFallback calls getTenantOrderSummary: 6 concurrent queries β 6 sequential withFallback calls getTenantOrders: Promise.all([findMany, count]) β sequential withFallback calls getTenantCustomerSummary: 3 concurrent queries β 3 sequential withFallback calls getTenantCustomers: Promise.all([findMany, count]) β sequential withFallback calls getTenantCustomer: Promise.all([findUnique, findMany, aggregate]) β sequential withFallback calls getTenantDashboardData: Promise.all across 5 sub-functions β sequential withFallback (top-level dashboard now degrades gracefully per section) Added withFallback import First Promise.all (meetings, participants, transcripts, minutes): β 4 sequential withFallback calls Second Promise.all (chatCount, transcriptBounds, translationCache): β 3 sequential .catch() queries Promise.all([meetingRows, minutesRows]) β 2 sequential calls Single-item Promise.all([minutesRows]) β direct (Γ2 occurrences) Promise.all(links.map(...)) β sequential for-loop with per-entity try/catch (prevents N concurrent lookups spiking the pool when a project has many links) Update stl-viewer, share-project-dialog 6:56 AM Β· ZRosserMcIntosh
expand metal presets with karat grades, remove brass, tune colors for hyper-realistic jewelry rendering stl-viewer.tsx: Rewrote METAL_PRESETS with expanded options: Yellow Gold: 24K, 18K, 14K, 10K (each with proper color saturation per karat) Rose Gold: 18K, 14K, 10K (copper tones deepen with lower karat) Added: 950 Platinum, Palladium (separate from generic Platinum) Updated: 925 Sterling Silver (warmer tone vs platinum) Removed: Polished Brass (not a Katura material) Legacy keys (yellow-gold, rose-gold, platinum, silver) kept hidden for backward compat Default metal: yellow-gold β 18k-yellow-gold (both viewers) Enhanced color science comments with karat-grade explanations share-project-dialog.tsx: Updated default metal option list to match Removed brass option Added karat-graded metals to dropdown Changed form defaults: yellow-gold β 18k-yellow-gold (2 places) Feature platform-admin 6:54 AM Β· ZRosserMcIntosh
enable tenant-scoped queries on 10 blocked pages services ServiceRequest.tenantId β findMany custom-orders BespokeInquiry.tenantId β findMany crm CrmDeal + CrmPipelineStage β findMany (both) engagement EngagementLead.tenantId β findMany + _count.designs wholesale WholesaleLead + WholesaleAccount + WholesaleSetting β sequential findMany tasks Task.tenantId β replaces ownerUserId OR-scope; fixes Promise.all β sequential audit AuditLog.tenantId β replaces ownerUserId filter; fixes Promise.all β sequential team User.tenantId β replaces owner-only lookup payroll PayrollRun.tenantId β findMany with stats aggregation payroll/runs PayrollRun.tenantId β findMany payroll/runs back-link was pointing to /admin/payroll β /platform/admin/payroll payroll quick-links were pointing to /admin/payroll/* β /platform/admin/payroll/* All stale SECURITY docblock comments removed scripts/db-migrations/fix-777-ring-slug.sql (Step 1 SELECT to find slug, Step 2 UPDATE to fix it) Update 6:42 AM Β· ZRosserMcIntosh
3 production issues β customers crash, orders slow, entity search UX 250ms debounce β hits /api/admin/entity-search Results grouped with colour-coded type pill (order/project/meeting/customer) Click to select β confirmation row shows entity details 'Link' button disabled until selection is confirmed Notes field preserved ILIKE search across orders, projects, meetings, customers, invoices 5 results per type, newest-first Auth-gated (OWNER/MANAGER/EMPLOYEE) Feature customers 6:21 AM Β· ZRosserMcIntosh
Customer 360 Timeline Orders: placed, paid (with paidVia), shipped, delivered, cancelled, refunded β with real shipment dates Meetings: attended (by email match in MeetingParticipant), plus a separate event when Yen minutes are generated Projects: linked via EntityLink table Engagement leads: ring inquiry submissions with budget range Reviews: star rating + excerpt Colour-coded dot + icon per event type (11 distinct types) Relative timestamps ('3d ago') with full date on hover Clickable titles link directly to the relevant detail page 'Show N more events' collapse after first 15 entries Graceful skeleton loading + error/retry states Perf api 6:07 AM Β· ZRosserMcIntosh
convert parallel Promise.all DB queries to sequential awaits analytics/kpis: 14 parallel count/aggregate queries β 14 sequential awaits Impact: KPI dashboard header no longer risks P2024; 5-min in-memory cache absorbs the sequential overhead so cache-hit latency is unchanged. shipstation (health action): 3 parallel counts β 3 sequential awaits shipstation (overview): 3 parallel queries β 3 sequential awaits email/diagnostics (stats block): 4 parallel counts β 4 sequential awaits Perf cad 5:56 AM Β· ZRosserMcIntosh
collapse 14-query Promise.all into single findUnique β fix P2024 src/app/api/admin/jewelry-projects/[id]/route.ts Update cad 5:49 AM Β· ZRosserMcIntosh
resolve project redirect + glitched STL renders + UptimeRobot MCP docs Only redirect on HTTP 404 (project genuinely not found) On 500/other errors: show a toast error instead of redirecting This surfaces the real P2022 DB error to the developer instead of hiding it src/app/admin/projects/[id]/page.tsx (fetchProject catch block) Admin-auth protected (requireKaturaAdmin) Accepts any Supabase storage public URL Returns a 1-hour signed URL using service role key (bypasses RLS) Cached private 50min (URL valid 60min) Token-auth (share link validation, no login required) Same signed URL generation β works for public share + client view pages Detects any URL containing /storage/v1/object/ Resolves it through the appropriate signed URL endpoint Shows loading overlay while resolving (prevents loading HTML garbage) Falls back to original URL on error (non-fatal) When set, uses /api/share/.../cad-url instead of /api/admin/... Both STLViewerCanvas instances on share page updated with shareToken src/app/api/admin/storage/signed-url/route.ts (NEW) src/app/api/share/projects/[token]/cad-url/route.ts (NEW) src/components/admin/stl-viewer.tsx (useSignedStorageUrl hook + shareToken prop) src/app/share/projects/[token]/page.tsx (shareToken prop on both viewers) docs/mcp/UPTIMEROBOT_MCP.md (full guide + available tools + Katura monitors) docs/mcp/uptimerobot-mcp.example.json (copy-paste MCP config) 5:03 AM Β· ZRosserMcIntosh
docs/copilot: add comprehensive commit message standards + global instructions File: .copilot-instructions.md (10K) Scope: Katura project only 9 major sections with detailed examples Anti-patterns guide, special cases (security, hotfixes, sessions) Verification checklist included COPILOT_GLOBAL_INSTRUCTIONS.yaml (12K) β ready to copy-paste into VSCode global prompts COPILOT_SETUP_INSTRUCTIONS.md β step-by-step setup guide COPILOT_SETUP_QUICK_REF.md β quick reference card GLOBAL_COPILOT_INSTRUCTIONS_TEMPLATE.md β alternative template COPILOT_FILES_SUMMARY.txt β overview README_COPILOT_SETUP.md β complete index docs/performance/PERFORMANCE_INFRA_SETUP.md β 4-layer perf setup prisma/migrations/add_marketing_click_index.sql β index for smart-links aggregates prisma/migrations/add_order_stats_materialized_view.sql β pre-computed order stats src/app/api/cron/refresh-stats/route.ts β materialized view refresh cron 8 new Copilot instruction/reference files 1 performance docs guide 2 SQL migration files 1 cron route for stats refresh package.json (edge-config:seed script) src/lib/env.ts (UPTIMEROBOT_API_KEY schema) vercel.json (refresh-stats cron added) 4:34 AM Β· ZRosserMcIntosh
security/infra: harden cron auth, prisma migrate, ISR tuning, UptimeRobot β May 18 Session consultation-reminders (vercel.json: added ?secret=${CRON_SECRET}) support-escalation (vercel.json: added ?secret=${CRON_SECRET}) meeting-cleanup (vercel.json: added ?secret=${CRON_SECRET}) calendar-reminders (NEW secret in vercel.json) blog-publish (NEW secret in vercel.json) openclaw-reclaim (NEW secret in vercel.json) email/snooze GET endpoint (NEW secret check) src/lib/cron-auth.ts already existed (Bearer token, query param, x-cron-secret) Routes now import + call `requireCronAuth(request)` at top of GET Removed hand-rolled authorization logic from each route vercel.json cron definitions updated to pass ?secret=${CRON_SECRET} in path Medium severity fixed: Cron routes now require CRON_SECRET (set in Vercel) Reduces attack surface for internal job triggers Consistent auth pattern across all cron endpoints ShipEngine handles authentication at the API platform level (API key) Webhook URL embeddings (Basic Auth credentials) are no longer necessary Simplifies config and reduces env var sprawl src/app/api/webhooks/shipstation/route.ts: `verifyWebhookAuth()` now returns `{ valid: true }` Removed ~30 lines of Basic Auth header + query param checks Removed mentions of SHIPSTATION_WEBHOOK_SECRET from env checks Removes Medium severity: Webhook no longer checks a non-enforced secret Webhooks still logged and validated at ShipEngine layer One fewer env var to configure Ran `prisma migrate resolve --applied` on all 10 numbered migrations (20260121_add_source_column through 20260516_add_saas_operator_models) Removed empty 20260511024649_fix_entry_exit_page_types/ folder (no migration.sql) All pending migrations now show as applied in `_prisma_migrations` table pnpm db:status β prisma migrate status pnpm db:migrate β prisma migrate dev (create new migration interactively) pnpm db:deploy β prisma migrate deploy (production deployment; auto-runs on Vercel build) Updated docs/database/MIGRATIONS.md with quick-start guide Added prisma/schema/_base.prisma references to directUrl (DATABASE_URL_UNPOOLED) Noted: Every schema change must have a migration file in same commit P2022 errors (column does not exist) now preventable via migrations Docs 3:57 AM Β· ZRosserMcIntosh
session summary + production incident postmortem 2026-05-18 Update 3:40 AM Β· ZRosserMcIntosh
upload doubled path 400 + Consultation.meetingId P2022 api/upload: filePath was '${bucket}/${fileName}' β Supabase Storage's .from(bucket).upload(path) prepends the bucket automatically, so this produced 'order-attachments/order-attachments/filename' β 400 HTML response (not JSON) β StorageUnknownError. Fix: filePath = fileName only. prisma/migrations/add_consultation_meeting_fields.sql: Consultation model had ~30 new columns (meetingId, invite tokens, UTMs, GDPR consent, region routing, CRM/EngagementLead FKs, etc.) defined in schema but never migrated to the live DB. prisma.consultation.findMany() returns all columns by default β P2022 on every /admin dashboard load. Migration uses ADD COLUMN IF NOT EXISTS throughout β safe to re-run. Update 3:34 AM Β· ZRosserMcIntosh
resolve 5 Vercel production errors meeting-cleanup cron: x-vercel-cron header value was 'true' should be '1'; CANCELLED enum doesn't exist in MeetingStatus β changed to ENDED; removed CANCELLED from participant reconcile IN clause home-cache: bump getNewArrivals timeout 5000β8000ms (matches all other calls); old deployed build was 2000ms, this ensures new deploy never regresses jewel-vox: revalidate 300β3600s β 5-min ISR was causing cold-start DB stampede (3 concurrent revalidations Γ article.count() exhausting PgBouncer connection_limit=1) admin/reviews: p."images" column does not exist β replaced with correlated subquery against ProductImage table; productImage now returned directly in row staff-alerts: StaffAlert.title column in Prisma schema was never migrated to DB; added prisma/migrations/add_staff_alert_title.sql with IF NOT EXISTS guard Update recently-viewed 2:58 AM Β· ZRosserMcIntosh
fetch live data instead of stale localStorage snapshots priceOnRequest showing wrong value (e.g. $1,250,000 shown instead of 'Price on Request') β price was baked into localStorage at view-time Old product image displayed after admin uploaded a new photo β image URL was baked into localStorage at view-time Clicking 777 ring β 404 β slug was baked into localStorage at view- time; slug changed since then (product edit/rename), stale slug 404s priceOnRequest field drives the price display (not raw price > 0) Images always come from the live DB (most recent upload) Slug always comes from the live DB (no stale 404 links) Deleted/unpublished products disappear automatically 2:51 AM Β· ZRosserMcIntosh
rewrite all metadata β kill 'Handcrafted Earrings & Minimalist Jewelry' siteConfig.tagline: 'Fine Jewelry Since 1999' (was 'Luxury Jewelry') siteConfig.description: Leeinator-approved copy SEO_CONFIG.brand.description: updated (was 'Handcrafted minimalist') Root layout default title: 'KATURA Fine Jewelry | Custom Engagement Rings, Pearls & Diamonds' Root layout OG title: 'KATURA Fine Jewelry Since 1999' Root layout OG description: 'Custom engagement rings, pearls, diamonds, and one-of-a-kind pieces in gold and platinum. Predictably unpredictable.' SEO_TEMPLATES.home: full rewrite in all 24 locales SEO_TEMPLATES.shop: full rewrite in all 24 locales SEO_TEMPLATES.about: full rewrite in all 24 locales Category fallback: no more 'Handcrafted Fine Jewelry' Product fallback: no more 'designed for daily wear' Keywords: removed 'minimalist jewelry', 'handcrafted jewelry', 'ethical jewelry'; added 'fine jewelry', 'custom engagement rings', 'pearls', 'diamonds', 'gold jewelry', 'platinum jewelry', 'one-of-a-kind jewelry', 'bespoke jewelry' https://developers.facebook.com/tools/debug/ (enter katura1999.com) Send link in WhatsApp to yourself to verify new card Security 2:40 AM Β· ZRosserMcIntosh
fix critical/high pentest findings + wishlist auth waste Account takeover via register route: passwordless users (Shopify imports, guest checkout) can no longer have their password set by anyone who knows their email. Now sends a signed verification email (same token model as forgot-password) requiring email access. check-email route: no longer returns 'set-password' action (was leaking account state). Returns identical 'continue' for all cases. LiveKit rooms: GET/DELETE now require requireKaturaAdmin() auth. Previously fully unauthenticated β anyone could list/delete rooms. Employee login open redirect: callbackUrl now validated via safeRedirectUrl() β rejects //, /\, protocol-relative, absolute. K99 platform login: same fix via safeRedirectUrl(). Customer login: reject protocol-relative //evil.com in callbackUrl. Kill switches: upgraded from auth() to requireKaturaAdmin({roles: ['OWNER']}) + tenant_katura check. Previously any authenticated user could toggle platform kill switches. ShipStation webhook: added SHIPSTATION_WEBHOOK_SECRET enforcement. Previously unauthenticated β spoofable User-Agent was only check. Token summary route: now requires requireKaturaAdmin(). Cron auth: created src/lib/cron-auth.ts helper that requires CRON_SECRET (rejects spoofable x-vercel-cron: 1 from externals). Applied to email/scheduled route as template for remaining crons. WishlistProvider now checks useSession() status before fetching. Unauthenticated users never hit /api/wishlist (zero wasted compute, eliminates the 401 spam in logs). Update hydration 2:28 AM Β· ZRosserMcIntosh
stop removing React-managed compat banner from DOM Root cause of 'Something went wrong' on every page + production DOMExceptions 'Node.insertBefore: Child to insert before is not a child of this node' and 'Node.removeChild: ...'. The k99-compat-banner <div> is rendered by React inside <body>. The inline ES5 script called b.parentNode.removeChild(b) once hydration succeeded (via window.__k99CancelCompat). That mutated React-owned DOM out from under the reconciler. In React 19 this is fatal: any subsequent re-render that touches the <body> child list (route change, Suspense reveal, hero grid resize, PageViewTracker mount, etc.) tries to insertBefore/removeChild against the now-missing banner node and throws β which the locale error boundary catches and renders as 'Something went wrong'. Fix: hide the banner with display:none + aria-hidden instead of removing it. The node stays where React expects it, reconciliation stays consistent, no DOMExceptions, no error boundary fallback. Update build 2:13 AM Β· ZRosserMcIntosh
add missing engagement carousel + DB resilience hardening pass src/components/engagement/love-stories-carousel.tsx and src/app/api/articles/engagement-stories/route.ts were created in an earlier session but never committed. The consultation page already imports the carousel, so the Vercel Turbopack build failed with 'Module not found'. Now tracked. src/lib/db-resilience.ts: Added 'database operation timed out' and '[home-cache]' to retryable message detection. src/lib/cache/home-cache.ts: Wrapped all homepage DB reads in withFallback() + withResilientQuery(). Sections degrade to empty arrays instead of crashing. src/app/admin/page.tsx: Replaced 7-way Promise.all() dashboard burst with sequential resilient reads. Dashboard widgets degrade to zeros on failure. src/app/[locale]/jewel-vox/page.tsx: Sequential resilient article/category fetch with typed serialized shapes. Added CategoryWithCount and SerializedArticle types. src/app/[locale]/jewel-vox/[slug]/page.tsx: View-count update made non-blocking. Related articles wrapped in fallback. Metadata lookup uses retry. src/app/[locale]/jewel-vox/article-list.tsx: publishedAt typed as string|null (JSON serialization converts Dates to strings). src/app/api/articles/route.ts: Sequential resilient list + count queries. src/app/api/admin/articles/route.ts: Same pattern. src/app/api/articles/engagement-stories/route.ts: Wrapped in resilient queries. Update hydration 1:48 AM Β· ZRosserMcIntosh
eliminate 'Node.insertBefore/removeChild' React hydration crash on every page No suppressHydrationWarning at the <html> level was needed (already existed). Calendar now produces identical HTML on server and client regardless of user locale. Footer year renders consistently. Update 1:24 AM Β· ZRosserMcIntosh
jewel-vox crash-proof with unstable_cache + ISR; replace hero ring with Stella 7.77ct (20% smaller); eliminate N+1 category count queries Update 1:13 AM Β· ZRosserMcIntosh
eliminate self-referential hero fetch (was causing 300s timeouts); reduce ALL crons to hourly minimum β zero sub-hourly crons remain Feature 1:08 AM Β· ZRosserMcIntosh
password visibility toggle (eye icon) on all login, register & signup forms Update 12:59 AM Β· ZRosserMcIntosh
cap function maxDuration (15s pages, 25s API, 30s crons) to prevent memory billing spikes; fix meeting-cleanup endReason column error Update routing 12:49 AM Β· ZRosserMcIntosh
merge articles/[slug] into articles/[id] β eliminates 'id !== slug' Next.js startup crash Update home 12:44 AM Β· ZRosserMcIntosh
hero crash guard + Suspense wrapper; perf: ISR creations, PDP cached related products + deferred reviewStats Sunday, May 17, 2026 12 updates pushed
Update home 11:42 PM Β· ZRosserMcIntosh
stream hangs β wrap DB components in Suspense + add query timeouts + parallelize new-arrivals ROOT CAUSE: DynamicCollections and NewArrivals were async server components with NO Suspense boundary, querying Prisma directly. When Supabase's connection pool (limit=10) was exhausted by cron jobs, pool_timeout=10s meant 5 sequential queries = 50s+ wait. Page shell never sent, TCP stream hung open until Vercel force-closed. Update csp 11:19 PM Β· ZRosserMcIntosh
remove nonce that blocks Next.js inline scripts + fix log drain 405 + remove noisy MW logging CSP Level 3 ignores 'unsafe-inline' when any nonce is present. Since Next.js hydration scripts don't carry the nonce, they were being blocked β breaking the entire site ('Connection closed' error). Removed nonce entirely; unsafe-inline alone is correct until Next.js gains first-class App Router nonce support. Also: added GET handler to log drain endpoint (Vercel health check needs it), removed per-request console.log in middleware (was firing on every request).
Schema drift detection built-in
All 10 existing migrations tracked as baseline
Ready for daily use (previously manual .sql files only)
src/app/[locale]/creations/page.tsx: revalidate 60s β 1800s (30 min)
src/app/[locale]/collections/[id]/page.tsx: revalidate 300s β 1800s (30 min)
With `revalidate = 60`, ISR revalidation fires 60Γ per hour
Under load, 3+ concurrent cold-start requests can exhaust PgBouncer's connection_limit=1 on the pooler, queuing all 3 behind each other
Each hits 8000ms timeout β all 3 fail with P2024 β Vercel retries β cascade
Increasing revalidate to 1800s reduces revalidation attempts by 30Γ (from 60/hr to 2/hr)
Stale data window (30 min) is acceptable for product catalog
Eliminates P2024 connection pool stampedes on creations/collections pages
Users see data max 30 minutes stale during traffic spikes
Matches revalidation strategy used on /jewel-vox (already at 3600s)
scripts/setup-uptimerobot.ts: Automated UptimeRobot monitor creation
package.json: new 'monitoring:setup' script
Automated monitor setup (no manual clicking on UptimeRobot dashboard)
Default email alerts to account email
Public status page option available (manual: https://uptimerobot.com/dashboard)
Detects outages ~2 min after they occur (vs 5+ hours manual discovery)
Marks 7.77ct Platinum solitaire as priceOnRequest = true
Prevents display of numeric price, shows 'Price on Request' instead
Already run in Supabase SQL Editor
Status: DONE
scripts/db-resolve-existing-migrations.sh: Already ran successfully (baseline all 10 migrations)
src/app/api/cron/{consultation-reminders,support-escalation,meeting-cleanup, calendar-reminders,blog-publish,openclaw-reclaim}/route.ts (requireCronAuth)
src/app/api/admin/email/snooze/route.ts (requireCronAuth on GET)
src/app/api/webhooks/shipstation/route.ts (removed secret checks)
vercel.json (added ?secret= to 3 cron paths)
package.json (db:migrate, db:deploy, db:status, monitoring:setup scripts)
docs/database/MIGRATIONS.md (updated with workflow)
scripts/db-resolve-existing-migrations.sh (one-time baseline script)
scripts/setup-uptimerobot.ts (monitor automation)
prisma/migrations/fix_777ct_price_on_request.sql (product price fix)
src/app/[locale]/creations/page.tsx (ISR: 60s β 1800s)
src/app/[locale]/collections/[id]/page.tsx (ISR: 300s β 1800s)
scripts/seed-edge-config.ts (new)
src/lib/cache.ts (new)
src/lib/edge-config.ts (new)
Various engagement/consultation components (refactored)
pnpm-lock.yaml (dependency updates)
Run: UPTIMEROBOT_API_KEY=ur_xxxx pnpm monitoring:setup
Check: https://dashboard.uptimerobot.com/monitors
/api/health should be checked every 2 minutes
/creations and /collections ISR revalidation will be less frequent (~2 per 30 min)
Expect stale data to clear within 30 min of updates
Create at: https://uptimerobot.com/dashboard β Status Pages
Link to it on website footer (shows system status 24/7)
docs/sessions/SESSION_2026_05_18.md (parent session summary)
docs/database/MIGRATIONS.md (workflow guide)
src/lib/cron-auth.ts (requireCronAuth implementation)
prisma.config.ts (Prisma configuration with directUrl support) Update crons 11:03 PM Β· ZRosserMcIntosh
crash-proof meeting-cleanup + apply policy frequency reductions + add Vercel log drain β Slack #alerts Update routing 10:54 PM Β· ZRosserMcIntosh
resolve [key] vs [locale] dynamic segment conflict β move IndexNow handler to middleware, delete conflicting [key].txt route Perf projects 10:34 PM Β· ZRosserMcIntosh
parallel DB queries for project detail β 14 queries in Promise.all instead of 1 giant nested include Update meetings 9:56 PM Β· ZRosserMcIntosh
overlay controls, STT watchdog, CC icon, toolbox reorg, mobile opt Control bar now overlays video (absolute positioning) β eliminates dead space STT health watchdog: 30s interval auto-restarts Deepgram WS on silent death Auto-retry with back-off (2 retries) on STT initial connect failure CC icon: replaced text 'CC' with proper SVG captions icon Meeting Intelligence + Diamond Intelligence moved to Sales Tools tray Settings: auto-hide controls, speaker labels, notification sounds toggles Mobile: smaller buttons (w-10), tighter gaps, safe-area padding Wider mouse trigger zone (bottom-15%/center-50%) for control reveal autoHideControls setting wired into hide timer Docs security 5:19 AM Β· ZRosserMcIntosh
add boring security wins + caveats + playbook docs/active/boring-security-wins.md (6 foundational security patterns) JWT role re-check (5-min TTL) Server-side magic byte validation Cross-tenant data injection guards Try/catch error handling Auth guards on all admin routes Audit logging for compliance Metrics & monitoring guidance Incident playbook src/lib/project-access.ts: Added TODO #51 caveat on TENANT visibility (read=fine, but TENANT edit needs eventual split to prevent chaos) src/app/api/admin/messenger/upload/route.ts: Audit log for rejected uploads (fileName, claimedType, userId, channelId, timestamp) IMPROVEMENTS_SESSION_2026_05_17.md: Added security section + updated next steps Build improvements 4:45 AM Β· ZRosserMcIntosh
complete #19-#50 batch (security, perf, UX, infra) #19: perf indexes audit + verification SQL for production #20: image priority overuse fix (priority={i < 2} for timepiece mosaic) #23: deepgram processor scoping (already correct, no changes) #37: i18n admin migration prep (tr() upgraded with overloads, guide written) #39: smoke tests for critical routes (11 tests: auth, checkout, meetings, upload) #50: session token rotation after privilege escalation (5-min TTL re-check) ProjectVisibility enum (PRIVATE, TEAM, TENANT) ProjectMemberRole enum (OWNER, ADMIN, EDITOR, COMMENTER, VIEWER) ProjectMember, ProjectTeam, ProjectTeamMember models Project.visibility and Project.teamId columns docs/active/i18n-admin-migration.md (4-step migration guide) e2e/smoke.spec.ts (11 Playwright smoke tests) src/lib/toast.ts (consistent toast durations: 4s/6s/8s/β) src/lib/project-access.ts (visibility & membership helpers) src/components/admin/tasks/ShareProjectDialog.tsx (share UI) src/app/api/admin/projects/[id]/members/* (member management) src/app/api/admin/teams/route.ts (teams API) src/app/api/admin/meetings/rooms/live/route.ts (LiveKit rooms list) scripts/one-off/security-incident-2026-04/* (forensic archival) src/lib/auth.ts (jwt callback re-reads role every 5 min) src/lib/livekit.ts (listRooms() export, error appending) src/app/admin/meetings/[id]/meeting-room-client.tsx (4-step progress) src/components/admin/messenger/MessageThread.tsx (memoization, callbacks) src/app/admin/meetings/meetings-client.tsx (empty state upgrade) src/components/admin/tasks/ProjectSidebar.tsx (visibility icons, draft persistence) src/components/admin/tasks/KanbanBoard.tsx (snap scrolling, tooltips) src/components/analytics/charts/customer-charts-part5.tsx (aria-sort) src/components/admin/messenger/utils.ts (tr() overloads + @deprecated) prisma/fix-invalid-images.ts (OOM fix: push filter to DB) Multiple Prisma schema files (schema splits, new models) Katura-Android.code-workspace (root, was in messages/) Security incident scripts (scripts/one-off/security-incident-2026-04/) Update 1:59 AM Β· ZRosserMcIntosh
update auth import in kill-switches route for NextAuth v5 Feature 1:29 AM Β· ZRosserMcIntosh
blog platform enhancements - accurate view tracking, two-step writer workflow, smart scheduling Move blog view counting from server-side to client-side (3s dwell timer) Eliminates inflated counts from bot crawls, SSR rerenders, cache hits Fires after human browser interaction via BlogViewTracker component POST /api/articles/[id]/view endpoint for count increment Add two-step blog generation workflow (ideas β select β write) POST /api/admin/blog/ideas: Generate 7 blog post ideas (~5s) POST /api/admin/blog/generate: Write full post with auto-scheduling (~45s) BlogActionsBar component with state machine (idle β ideas β writing β done) Both endpoints validate auth as Katura admin Implement smart auto-scheduling for new posts Auto-schedules posts for day after last queue entry at 09:00 AM Eastern Respects existing SCHEDULED and PUBLISHED posts, queues sequentially Prevents manual slot conflicts, enforces 1-post/day cadence Fix /admin/messages unwanted redirect behavior Store last-accessed channel slug in localStorage No longer auto-selects first channel (was forcing @antar redirect) Preserves channel selection across page reloads Update sidebar nav translations Change "Blog" label to "The Jewel Vox Blog" (en + pt) Add existing bulk schedule endpoint for KATURA_SEO drafts POST /api/admin/blog/schedule-drafts: Schedule all DRAFT articles Spreads over days (2 per day at 09:00 and 14:00 Eastern) Feature 12:22 AM Β· ZRosserMcIntosh
tenant-facing usage dashboard β /platform/admin/usage Add src/app/api/saas/tenant/usage/route.ts: GET endpoint scoped to the authenticated tenant via getPlatformAdminContext() Returns: billing control state (spend, limits, locks, status), per-feature rollup from SaasUsageRollup for current month, daily spend array for chart Serializes all Decimal fields to numbers Add src/app/platform/admin/usage/page.tsx + usage-client.tsx: TenantUsageClient (client component): Account lock banner (red) when billingLock=true Past due warning (yellow) with failed charge count Feature lock chips for per-feature pauses Three KPI cards: Total Spend, Pending Overage, Status badge AI and Infrastructure quota progress bars with color coding (green β yellow at 75% β red at 90%) Daily spend bar chart (pure CSS/Tailwind, no extra dep) Per-feature breakdown table with icons + event counts Overage summary: pending / charged / unpaid with Resolve CTA Empty state when no usage events exist yet Refresh button (optimistic spinner) Link to /admin/billing for payment updates Wire sidebar: add 'Usage' nav item to System section (between 'Billing & Plan' and 'Audit Log') Feature 12:01 AM Β· ZRosserMcIntosh
admin alerts β quota warnings, billing locks, kill switch notifications Add src/lib/saas/billing-alerts.ts: alertQuotaWarning(): fires when tenant hits β₯90% of any feature quota (ALLOW_WITH_WARNING); fetches tenant name/slug lazily, posts to #alerts and #tenant-{slug}; fully fire-and-forget alertBillingLock(): fires on billingLock=true from overage cron or billing reset; posts critical alert to #alerts + #tenant-{slug} with admin billing link alertKillSwitchEnabled/Disabled(): fires on every kill switch toggle; critical alert with switch key, reason, and activating admin alertChargeRequiresAction(): fires when Stripe requires 3DS/SCA on an off-session overage charge Wire alertQuotaWarning into usage-gateway.ts: Fires fire-and-forget at ALLOW_WITH_WARNING decision point Skipped on dryRun requests Wire alertBillingLock into overage-charge cron: Fires at both exception and result-failure lock paths Also fires alertChargeRequiresAction on requires_action outcome Includes tenant name/slug via query include Wire alertBillingLock into billing-period-reset cron: Fires when end-of-period unpaid overage exceeds lock threshold Add src/app/api/admin/saas/kill-switches/route.ts: GET: list all platform kill switches (admin only) PATCH: toggle isEnabled + set reason/activatedBy; fires Slack alert on every state change (enable β critical alert, disable β info)