3 Commits

Author SHA1 Message Date
metatroncubeswdev
cc20f20fe3 fix: uncontrolled Polaris TextFields couldn't be typed into
Some checks failed
CI / Lint, Unit & Integration Tests (push) Has been cancelled
app.locations.new.tsx's "Location name"/"Address" fields and
app.blackouts._index.tsx's "Date"/"Reason" fields were missing
value/onChange — Polaris TextField is fully controlled, so without that
wiring every keystroke gets overwritten back to an empty string on
re-render, making the field appear frozen. Every other form in the app
already followed the value/onChange + useState pattern; these four fields
were the only ones missed, and went uncaught until live browser testing
was actually possible tonight (shopify.web.toml was missing until now).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-25 02:23:22 -04:00
metatroncubeswdev
d150509978 feat(phase-8): Billing API with server-side feature gating
Some checks failed
CI / Lint, Unit & Integration Tests (push) Has been cancelled
Add real Shopify Billing API integration: Free/Starter/Growth/Pro plans
(app/lib/billing-plans.ts, priced per PRODUCT_STRATEGY.md §6) wired into
shopify.server.ts's billing config, a merchant-facing plan page
(app/routes/app.billing.tsx) using billing.request/billing.cancel, and
webhooks.app_subscriptions.update.tsx as the durable sync path for
Shop.tier (fires even when a merchant cancels from Shopify's own billing
page, not just from this app).

Gate the features actually built so far in both loader and action (never
just hidden in the UI, so a direct POST can't bypass a tier limit):
delivery zones/rates require Growth+, the dispatch dashboard requires
Starter+, and location count is capped per tier (Free=1, Starter=3,
Growth/Pro=unlimited). Split pure tier logic (app/lib/billing-plans.ts)
from DB-backed reads/writes (app/services/billing.server.ts) so the
client-rendered UpsellState component can import the Tier type without
pulling server code into the client bundle — same split as currency.ts.

Covered by tests/unit/billing-plans.test.ts (pure tier ranking/mapping)
and tests/integration/billing.test.ts (tier persistence and location-limit
enforcement against live Postgres).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 09:29:42 -04:00
metatroncubeswdev
21f0ee704b feat: Phase 1 — core data model & admin CRUD
Adds the scheduling core to Prisma (Shop, Location, Method enum,
SlotTemplate, SlotOverride, BlackoutDate — IMPLEMENTATION_PLAN.md §4) and
Polaris admin screens to manage them:

- /app/locations: list/create/edit/delete locations, one-click vertical
  template seeding (bakery/florist/grocer)
- /app/slots: weekly slot template editor, scoped per location
- /app/blackouts: blackout dates, scoped to one location or all of them

services/templates.server.ts keeps the vertical presets as a pure,
unit-tested function (getVerticalTemplate) separate from the thin I/O
wrapper (seedVerticalTemplate) that does the actual Prisma writes, per
CLAUDE.md's "pure functions, inject data, no I/O in the math" rule.

Switched dev DB from SQLite to Postgres (docker-compose.yml, ports 5433/6380
to avoid clashing with other local projects already on 5432/6379): SQLite
doesn't support Prisma enums at all, and IMPLEMENTATION_PLAN.md's schema
relies on them (Method) plus Postgres-only array fields in later phases
(Zone.postalCodes, ProductRule.allowedLocationIds). Only one throwaway
migration existed, so switching now avoids compounding the rework later.

Also fixed a Remix/Polaris integration issue hit while building these forms:
this Polaris version's TextField/Checkbox are fully controlled (no
defaultValue/defaultChecked), and `data()` imported from `@remix-run/react`
(rather than `@remix-run/node`) breaks useActionData's type inference —
both are now handled correctly across the new routes.

Verified: lint, typecheck, unit tests (incl. template-seeding fixtures),
build, and a live end-to-end run of seedVerticalTemplate against the
Postgres container all pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 17:47:59 -04:00