5 Commits

Author SHA1 Message Date
metatroncubeswdev
8c2b8a9e1c feat: Phase 2 — scheduling engine (timezone/DST-safe, pure, unit-tested)
Implements the "heart" of the app per IMPLEMENTATION_PLAN.md §6 Phase 2,
no UI yet by design:

- app/lib/time.ts: Luxon-based wall-clock helpers. slotDateTime() builds a
  slot's instant from calendar-date + minutes-from-midnight by setting
  hour/minute fields directly rather than adding an elapsed-time duration
  to midnight — the latter is wrong by exactly one hour for any wall-clock
  time on a spring-forward day, since a real elapsed-time addition crosses
  the lost hour. Also detects and rejects wall-clock times that don't exist
  in a spring-forward gap (Luxon silently rolls these forward instead of
  invalidating them, so this required an explicit post-set field check).
- app/services/scheduling.server.ts: getAvailability(), a pure function
  (no DB/Shopify calls — every input injected, including `now`) that
  applies slot templates, date overrides, blackout dates, cutoff/lead-time,
  and capacity to produce the bookable slots per date. Excludes unavailable
  slots entirely rather than flagging them, per PRODUCT_STRATEGY.md §2.
- app/services/capacity.server.ts: remainingCapacity()/hasCapacity() — kept
  as pure functions over an injected `consumed` count so this doesn't need
  to change once Phase 4 adds real Booking/SlotHold-backed consumption.

41 unit tests total (up from 8), including DST regression tests that would
fail against a naive "midnight + elapsed minutes" implementation, an
ambiguous-time (fall-back) case, a nonexistent-time (spring-forward gap)
case, and a getAvailability run across the actual 2024 spring-forward date
verifying both the UTC offset change and that wall-clock hours stay correct
on both sides of it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 17:53:39 -04:00
metatroncubeswdev
a35a4f89be docs: update README for Postgres-based local dev and Phase 1 status
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 17:48:19 -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
metatroncubeswdev
0303eba07a feat: scaffold Phase 0 — Remix app template, CI, Redis/BullMQ, test harness
Bootstraps from Shopify's official shopify-app-template-remix (cloned
directly rather than via `shopify app init`, which requires an interactive
Partner login unavailable in this session):

- Prisma (SQLite dev / Postgres-ready) with baseline Session model + migration
- Vitest configured for unit tests, Playwright configured for E2E
- Redis client + BullMQ worker skeleton (app/lib/redis.server.ts, jobs/worker.ts)
- shopify.app.toml: minimal scopes, GDPR + orders webhooks wired (stub handlers),
  app proxy config for the future storefront widget
- Stripped template-repo-only meta files (CLA, issue templates, demo product
  page) and replaced CI with a lint+typecheck+test workflow
- Bumped @shopify/shopify-app-session-storage-prisma to resolve a duplicate
  @shopify/shopify-api install that broke typecheck
- Dropped the Jest-only ESLint config (template default) since the project
  standardizes on Vitest per IMPLEMENTATION_PLAN.md

Verified: npm install, lint, typecheck, unit tests, prisma migrate dev, and
npm run build all pass on Node 22 LTS.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 15:45:28 -04:00
metatroncubeswdev
952d274bea docs: add product strategy and implementation plan
Initial planning docs for the delivery date/time scheduling app.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 15:33:49 -04:00