Files
Wabenhain/package.json
T
Nick SzaunigandClaude Opus 5.5 93b589ff04
Docker Image bauen und veroeffentlichen / build-and-push (push) Successful in 3m40s
feat(stock): keep shop stock in sync with ApiCore, write sales back
ApiCore now owns the remaining stock per batch; the shop sells from it
and reports every paid sale and every return back.

- Outbox apicore_stock_events, written in the same transaction as the
  status change: paid -> SALE, cancelled-after-payment / refunded return
  -> RETURN onto the batches of the sale, reopened paid order -> SALE.
  Whether a return is due is decided by the open sales in the outbox,
  so unpaid orders never book and nothing is booked twice.
- Delivery right after the response (next/server after()) plus CronJob
  wabenhain-apicore-stock every 10 minutes with 1/5/15/60 min backoff;
  ApiCore deduplicates by event id. Rejected bookings stop and show up
  on the dashboard.
- Reconcile: shop stock = ApiCore remaining - unconfirmed bookings -
  reservations of unpaid orders, in a serializable transaction like the
  checkout. Triggered after bookings, by the signed ApiCore webhook
  stock.changed (ids only, numbers are fetched) and by the sync button.
- Manufactured goods (candles, propolis products, ...): one shop product
  per ApiCore article via Product.apicoreProductId, drafts created by the
  sync, existing products linkable in the product form; new category
  SONSTIGES. Stock field is read-only for linked products.
- OrderItem.apicoreAllocations keeps which lots were sold (recalls).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-05 21:16:54 +02:00

74 lines
2.4 KiB
JSON

{
"name": "wabenhain",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "node scripts/generate-prisma-clients.mjs && next dev",
"build": "node scripts/generate-prisma-clients.mjs && next build",
"start": "node scripts/generate-prisma-clients.mjs && next start",
"lint": "eslint",
"postinstall": "node scripts/generate-prisma-clients.mjs",
"db:push": "node scripts/prisma-provider.mjs && prisma db push",
"db:migrate": "node scripts/prisma-provider.mjs && prisma migrate dev",
"db:deploy": "node scripts/prisma-provider.mjs && prisma migrate deploy",
"db:seed": "prisma db seed",
"db:seed:demo": "tsx prisma/seed-demo.ts",
"db:studio": "node scripts/prisma-provider.mjs && prisma studio",
"test": "vitest run",
"test:watch": "vitest",
"test:e2e": "playwright test",
"preflight": "tsx scripts/preflight.ts",
"places:find": "tsx scripts/find-place-id.ts",
"orders:release-stale": "tsx scripts/release-stale-orders.ts",
"stock:apicore-sync": "tsx scripts/apicore-stock-sync.ts"
},
"dependencies": {
"@prisma/adapter-mariadb": "^7.10.0",
"@prisma/adapter-pg": "^7.10.0",
"@prisma/client": "^7.10.0",
"@stripe/react-stripe-js": "^6.12.0",
"@stripe/stripe-js": "^9.17.0",
"bcryptjs": "^3.0.3",
"ffmpeg-static": "^5.3.0",
"jose": "^6.2.8",
"mariadb": "^3.5.3",
"motion": "^13.0.0",
"next": "16.3.5",
"nodemailer": "^9.1.1",
"otpauth": "^9.5.1",
"pdfkit": "^0.19.1",
"prisma": "^7.10.0",
"qrcode": "^1.5.4",
"react": "19.2.8",
"react-dom": "19.2.8",
"sharp": "^0.35.4",
"stripe": "^22.4.0",
"zod": "^4.4.3",
"zustand": "^5.0.14"
},
"devDependencies": {
"@playwright/test": "^1.62.1",
"@tailwindcss/postcss": "^4",
"@testing-library/jest-dom": "^7.0.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.4",
"@types/bcryptjs": "^3.0.0",
"@types/node": "^20.19.43",
"@types/nodemailer": "^8.0.1",
"@types/pdfkit": "^0.17.6",
"@types/qrcode": "^1.5.6",
"@types/react": "^19",
"@types/react-dom": "^19",
"@vitejs/plugin-react": "^6.0.5",
"dotenv": "^17.4.2",
"eslint": "^9",
"eslint-config-next": "16.3.5",
"jsdom": "^30.0.1",
"tailwindcss": "^4",
"tsx": "^4",
"typescript": "^5",
"vitest": "^4.1.10"
},
"packageManager": "[email protected]"
}