Featureemail6:04 AM · Scoz
cart reminder invites the customer to talk to a specialist
- Replaces the 10% discount e-mail. The CTA opens the consultation landing with the cart's first product; copy is real pt, en and es under the cartRecovery namespace (other locales fall back to English). The admin preview, test send and dev console now render the same template.
Featurecart6:04 AM · Scoz
remember the shopper's language on the cart
- Cart.locale is set from NEXT_LOCALE when an item is added (validated against the supported locales) and carried across a guest-cart merge. It picks the language of the recovery e-mail.
Updatestorefront2:15 AM · ZRosserMcIntosh
show the phone number on /contact; trim the footer
- Contact: the phone number was sign-in only, though the same number is public on the WhatsApp button beside it.
- Footer: drop Investors, Software Updates, Authorized Dealer Login, Environment, Personal Wedding Site, the K99 platform promo and the Developer / K99 Platform links; Employee Login stays, without the glow. The Journal link stays (it is the blog's only internal link).
Featureadmin/orders2:00 AM · ZRosserMcIntosh
show the charged amount on non-dollar orders
- A BRL checkout now reads "$37.00 / charged R$192.17" instead of a bare
- dollar figure. (KAT-MT38YEVO still stores R$192.17 as its total until
- its data fix runs; this makes that visible.)
Updateactivity1:57 AM · ZRosserMcIntosh
label lead statuses as leads, not tasks
- The lead feed and the readable-status labels landed in parallel; leads fell
- through to the task label map.
1:54 AM · ZRosserMcIntosh
Merge branch 'fix/admin-ops-2026-10-03'
1:54 AM · ZRosserMcIntosh
Merge branch 'fix/admin-display-2026-10-03'
Featureactivity1:54 AM · ZRosserMcIntosh
list new leads from the last 60 days
- EngagementLead rows (Katura tenant, last 60 days) join orders and tasks in
- /admin/activity, labelled with getLeadSource(notes).source and linking to
- /admin/leads/[id]. Emails ending @synthetic.local or @example.com are
- skipped. Leads are only listed to users who can view /admin/leads.
Updatebriefing1:54 AM · ZRosserMcIntosh
write Virgil's daily briefing with Claude Haiku 4.5; flag stale ones
- The last stored briefing is 2026-09-27: generation went through OpenAI
- gpt-4o-mini, whose account ran out of credits, and the dashboard fell back
- to the newest stored row. Switch to the Anthropic SDK (claude-haiku-4-5,
- ANTHROPIC_API_KEY, output_config JSON schema), the same way the blog-agent
- cron moved in 9e6abd48. The cron entry (0 13 * * *) is unchanged.
- The dashboard card now labels a briefing older than 2 days 'Stale · N days
- old' instead of presenting it as today's.
Updatecalendar1:54 AM · ZRosserMcIntosh
local 'today' in the mini calendar; open tasks on Deadlines
- The mini calendar is server-rendered with a UTC 'now' and React keeps the server className on hydration, so after 21:00 in Sao Paulo it highlighted tomorrow while the client-only main grid showed today. Render its day grid after mount so both use the browser's local date.
- The events API adds Tasks with a dueDate and status not DONE as read-only all-day events on the 'Deadlines' calendar (toggled by its checkbox). OWNER sees all tasks; others see tasks assigned to them. The popover links to the task instead of offering edit/delete.
- EventPopover referenced an out-of-scope 't' (ReferenceError for any event with a conference link); use a plain label.
Updatemeetings1:54 AM · ZRosserMcIntosh
owner-only engine panel; stale LIVE rooms move to Recent as Not ended
- The Katura/Railgun engine switch and the Classic/Railgun Beta toggle are developer controls: render them for OWNERs only, behind a 'Developer: meeting engine' disclosure. Anyone already on the beta still sees the toggle so they can switch back. Engine behavior is unchanged.
- Engine API reports configured:false when RAILGUN_MEET_API_KEY is absent; the panel shows a neutral 'not configured' instead of red error text. Switching engines (POST) now requires OWNER.
- A LIVE meeting that started >12 h ago with no endedAt no longer counts as live/upcoming: it shows under Recent labelled 'Not ended', keeps the End button, and has no Join or Delete. Display only; no data is changed.
Updateinvoices1:46 AM · ZRosserMcIntosh
show the invoice-due card at most once per session
- Signed-in customers with an open invoice got the card over the homepage hero
- on every page load until they dismissed it. It now shows once per browser
- session per invoice (sessionStorage, try/catch like the dismissal store);
- the 24-hour dismissal and the View & Pay flow are unchanged.
Updatehome1:45 AM · ZRosserMcIntosh
keep the chat bubble off the hero CTAs on phones
- On a 390 px screen the floating WhatsApp button sat on top of the hero's
- stacked Explore button. On the homepage below md it now appears only once
- the first half-screen has scrolled away. The cart/checkout max-lg rule and
- the data-sticky-buy-bar CSS hook are unchanged.
Featureadmin/leads1:44 AM · ZRosserMcIntosh
search, lead-type filter and hide-newsletter toggle
Updateadmin/crm1:44 AM · ZRosserMcIntosh
hide Join after a consultation ends; add a Past count
- A consultation is over at start + duration. Join is hidden after that (and
- for cancelled ones). Nothing records an outcome (all rows stay status
- "scheduled"), so ended consultations are counted as Past rather than
- claimed as Completed.
Featureadmin/products1:44 AM · ZRosserMcIntosh
client-side search and status filter above the list
Updateadmin/tasks1:44 AM · ZRosserMcIntosh
save and filter by project; standard New Task button
- The tasks page sends projectId on create, edit and list, but
- /api/admin/tasks dropped it everywhere: every task was saved with no
- project (all 36 in prod have projectId NULL), so each project's sidebar
- count was 0 and selecting a project still listed every task. POST and PUT
- now store projectId, GET filters by it and returns task.project so the edit
- dialog keeps it. New Task uses the default primary button, not pink.
Updateadmin/invoices1:43 AM · ZRosserMcIntosh
use the standard PageHeader instead of a letter-spaced title
Updateadmin/customers1:43 AM · ZRosserMcIntosh
format lifetime value with thousands separators
Updateadmin/orders1:43 AM · ZRosserMcIntosh
hide cancelled by default and format totals consistently
- Exclude Statuses now starts with Cancelled ticked (mostly test checkouts);
- staff can un-tick it. A picked status overrides the exclusion, since the API
- replaces the status filter with the exclude list. Totals use Intl currency
- formatting ($297.50, $1,500.00) in both the table and phone cards.
Updateadmin1:43 AM · ZRosserMcIntosh
show order numbers, readable statuses and lead types on dashboard and activity
- Recent Orders and /admin/activity printed an id fragment (CMT38YEV) and the
- raw enum (IN_PRODUCTION). They now show Order.orderNumber (KAT-…) and the
- translated status labels the orders page already uses. Engagement Leads
- showed an id fragment and "Not specified" budget on every row; it now
- shows what the lead asked for via getLeadSource(notes).
Updateheader1:42 AM · ZRosserMcIntosh
keep the search icon visible on the dark header
- On /design-your-ring (and the other dark-header pages) the search trigger
- still rendered, but in the default dark text on the #030712 header, so it
- vanished. SearchDialog takes a triggerClassName and the header passes the
- same white styling the bag icon already uses there.
Updatepdp1:41 AM · ZRosserMcIntosh
plain in-stock shipping line and a labelled share button
- Ships-immediately pieces read "In stock · ships in 1–2 business days" (Merchant Center handling is 0–2 days) instead of "Atelier Creation & Resizing Time: In Stock - Ships Immediately"; atelier lead times are unchanged. New product.inStockShips key is copied in English to every locale because the message merge is shallow per namespace.
- The share control was an unlabelled envelope that read as "email us". It is now a share glyph in the same ghost icon button as the wishlist heart, with a "Share this product" hover label; the heart gets a matching one.
Updatecheckout1:39 AM · ZRosserMcIntosh
minimal footer without the newsletter box
- /checkout rendered the full marketing footer, including the "Join the world
- of Katura" signup. The footer now reads the pathname and, on /checkout only,
- renders just the copyright line with Privacy, Terms and Returns.
Updatecheckout1:38 AM · ZRosserMcIntosh
show what is being bought at the top on phones
- Below lg the Order Summary stacked under the payment form, so a shopper
- paying on a phone never saw the piece. A compact collapsible summary
- (thumbnail, name, total; tap for each line) now sits above the form on
- phones; the desktop sidebar is unchanged. Thumbnails get a real `sizes`
- so an 80 px image no longer requests a full-viewport-width file.
Updatebag1:37 AM · ZRosserMcIntosh
cap the quantity stepper at available stock
- The bag's "+" let a shopper step a one-of-a-kind piece to 2, which checkout then rejected. Cart responses now carry maxQuantity (checkout's rule: a tracked product stops at quantity
- reserved, an untracked ships-immediately product is out of stock, everything else stops at 10), the stepper disables "+" at that cap, and PATCH /api/cart/[itemId] refuses increases past it. Cart lines also take the product's primary photo first, as the storefront cards do, instead of whichever image has the lowest sortOrder.
Updatecreations1:30 AM · ZRosserMcIntosh
products above the fold on phones, all categories, clearer sort and badges
- Filters share one row on phones; hero, filter bar and grid padding shrink on mobile
- Category chips add Earrings and Bracelets and scroll sideways on phones
- Default sort "smart" now reads "Featured"; the old shuffled "featured" reads "Our picks"
- Drop the Handmade badge every card carried; keep One of one
Updateconsultation1:21 AM · ZRosserMcIntosh
let the main CTA wrap on phones
- On a 390px screen the one-line "SCHEDULE YOUR PRIVATE CONSULTATION" label
- overflowed the button and was clipped at both ends. The offer pages already
- wrap; this brings the main consultation page in line.
Updateux1:18 AM · ZRosserMcIntosh
truthful ring-sizer and payment copy, readable leads, visible lead tasks
- Ring sizer: drop the invented "Over 2,000 sizers shipped this year"; "Mailed tomorrow / in 24 hours" becomes "next business day" (page, meta, form, confirmation email); no more "watch for tracking".
- Checkout and FAQ no longer promise PayPal (it is excluded at checkout), in all 24 languages.
- Lead follow-up tasks go to the admin Tasks page (the Task model staff use, assigned to Lee) instead of CrmTask, which has no screen.
- Lead detail: shows the real lead type (ring sizer, 7.77 alert, concierge, Saturday, custom ring...), a readable "Ship sizer to" block, times in US Eastern with a label; the duplicate read-only notes card is gone.
- New ring-sizer leads store a readable ship-to line instead of JSON.
- Lead cards show the lead type; subtitle no longer says every lead is "from custom ring design".
- CRM honors /admin/crm?contact=<id> ("View in CRM" was a dead link).
- Breadcrumbs show "Details" instead of raw record ids; CRM/SaaS/iOS cased.
- "1 item", "1 upcoming meeting"; dashboard drops "(12 months)" from cards that are labelled 30D.
Updateconsent1:07 AM · Scoz
banner content follows the page container; equal action widths; focus moves into the customise panel
Updateinvoice1:03 AM · Scoz
public invoice, emails and account panel state one charged amount
- The public /i/ invoice reads the amount through orderChargedAmount like the
- invoice emails, so both show what the customer is charged (line items scaled
- at the order's rate). Check, Zelle and wire payers also see the USD total they
- settle in. formatMoney stays private to the invoice service.
Updatepaper-archive1:03 AM · Scoz
promoted orders in another currency record the charged amount
- Paper-archive orders keep every amount in their own currency, so the charged
- amount is the total. Invoices, emails and the public invoice label them in that
- currency instead of as USD.
Updatetracking1:01 AM · Scoz
match an already-processed purchase by order and writer so earlier rows still count
Featureleads12:55 AM · ZRosserMcIntosh
every lead emails Rosser, Lee and Zack and lands in the CRM
- availability/concierge/Saturday notices went only to engagement@katura1999.com, fire-and-forget, and could be dropped when the function froze; now awaited and sent to the team.
- engagement-email-signup passed non-existent columns (source, tags), so every lead create failed silently; it now saves.
- converting a lead to a deal set CLOSED_WON; it now moves NEW leads to CONTACTED.
- phone-only requests (concierge text) still notify.
Updatetracking12:52 AM · Scoz
record the purchase row on manual mark-paid too, tolerate racing writers, flag wholesale rows
Choreskills12:47 AM · ZRosserMcIntosh
add the Upstash rate-limit and Redis skills for Claude sessions
- Installed 2026-10-02 alongside the Upstash rate-limit store.
Docsmarketing12:43 AM · ZRosserMcIntosh
Pinterest batch 2, a second daily pin through Nov 1
Updateleads12:43 AM · ZRosserMcIntosh
email the team on ring-sizer requests; keep the self-test out of leads
- Ring-sizer requests promised the customer a USPS mailing the next morning
- but only saved a lead row, so nobody on the team heard about them. They
- now also email CONTACT_NOTIFY_EMAIL (or the support fallback) with the
- name and ship-to address. The 6-hourly self-test's newsletter signup
- (test@synthetic.local) is answered without saving a lead, so it no
- longer counts as an engagement lead on the admin dashboard.
Updateconsent12:38 AM · Scoz
honour the choice for cookies a visitor already had
- Reject now clears tracking cookies from before the banner on every save, not
- only on a withdrawal. Checkout and payment-intent read _ga*/_fbp/_fbc only for
- the category the visitor allows, as does the consultation attribution hook.
Updatetracking12:19 AM · Scoz
record the purchase row for zero-charge orders as well
- A fully discounted or gift-balance order is marked PAID inside
- create-payment-intent without a Stripe payment, so neither the webhook nor
- the success page (which skips $0 orders) reported it to the funnel.