CLAUDE.md – map of this shop for your AI assistant

This file is written for Claude (or another AI coding assistant) working on a copy of Open Small Shop. The person you are helping is probably not a programmer. Explain in plain words, change as little as needed, and test locally before they upload anything.

What this is

A small online shop in plain PHP 8.2+ with SQLite. No framework, no Composer, no build step, no database server. It runs on ordinary shared hosting (Apache with .htaccess, PHP, cron). Two small libraries are vendored: PHPMailer (email) and tFPDF (PDF invoices and customs forms).

It was written for a real shop: a small exporter in India selling motorcycle parts worldwide with India Post, prices in euros, payment by PayPal, five languages (English, German, French, Spanish, Portuguese). The demo content keeps that setup, because all the country-specific parts (carrier rates in rupees, US import duty, CN22/CN23 customs forms) then work together as one example. Most users will adapt exactly those parts.

Run it locally

cp config.example.php private/config.php      # set 'admin_initial_password' to 10+ characters
php -S 127.0.0.1:8080 index.php

Open http://127.0.0.1:8080 and http://127.0.0.1:8080/admin/ (log in with admin_initial_password). With 'env' => 'dev': emails are written to private/logs/mail/ instead of being sent, and 'paypal' => ['mode' => 'fake'] simulates PayPal without network (the PayPal button itself needs the real SDK; to test the order flow, POST to /api/create-order.php then /api/capture-order.php). The dev server also serves /api/*.php, /admin/*.php, /health.php and /download.php through index.php (Apache runs them directly).

Request flow

Where things are

Topic File(s)
Shop name, address, email, logo, menu, home texts, customs details data/site.json (shop block)
Products (starting point) data/products.json; edits made in Admin → Products live in the DB (product_edits) and win; merged in all_products() (lib/bootstrap.php)
Stock DB table stock (seeded once from data/stock-initial.json); Admin → Stock
Translations data/i18n/<lang>/ui.json (interface, keyed by the English text), products.json (by slug), pages.json + data/pages/<lang>/*.html
Content pages data/pages.json + data/pages/*.html (English); a missing translation falls back to English (noindex)
Languages list LANGS in lib/i18n.php; t() translates; money format money_lang()
Shipping prices and countries data/zones.json (groups of countries, prices in INR, blocked countries, special rules) + shipping_quote() in lib/shipping.php
Exchange rate INR→EUR, US duty % settings() in lib/shipping.php, Admin → Settings (private/settings.json)
Letter shipping (flat price) product field shipping_class: letter, letter_eur_cents in zones.json
Customs forms CN22/CN23 + address label lib/shipdocs.php, background images in data/shipping/; coordinates in mm
Invoice PDF lib/invoice.php (seller block from site.json)
Emails lib/orders.php (send_order_emails, send_shipped_email), lib/accounts.php (password reset), lib/downloads.php; sending: lib/mail.php
PayPal lib/paypal.php (Orders v2 API), api/*.php
Customer accounts lib/accounts.php, templates/account.php
Digital product (download) lib/downloads.php: personal link per order, the first PDF in private/downloads/
Database schema + migrations lib/db.php (PRAGMA user_version, add a new numbered step for changes)
Admin pages admin/*.php (login in lib/admin.php)
Backups lib/backup.php (after each new paid order, via cron), Admin → Backup
Maintenance mode lib/maintenance.php, Admin → Settings
Server self-test admin/check.php (keep SHOP_FILES up to date when adding files), health.php

Rules that keep it safe

Typical adaptations (what users ask for)

  1. Own shop details – data/site.json (shop, site_name, logo, menu), assets/invoice-logo.png (PNG without transparency), pages in data/pages/, the legal pages (they are templates!).
  2. Other carrier / other country of dispatch – rewrite data/zones.json (groups and prices; the *_inr prices and inr_to_eur_cents() assume rupees – for another currency of the carrier, change the conversion in lib/shipping.php or store prices directly in euro cents), remove or change the US duty rule (duty_prepaid in zones.json, us_duty_percent), replace or drop the CN22/CN23 module (lib/shipdocs.php; called from send_order_emails() in lib/orders.php and admin/order.php).
  3. Other shop currency – prices are euro cents; money()/money_lang() and the PayPal calls (currency_code 'EUR' in lib/paypal.php and api code) need the new currency.
  4. Taxes (VAT / sales tax) – not built in (the original seller exports from India, zero-rated). Sellers in the EU or US must add tax rules in build_quote() and show tax on the invoice.
  5. Other payment provider (e.g. Stripe) – add an api/ endpoint pair like PayPal's and a button in templates/checkout.php + assets/cart.js; mark_paid() in lib/orders.php does everything after payment.
  6. Fewer or more languages – LANGS in lib/i18n.php plus the files in data/i18n/.

Testing checklist before going live

Fake order locally (dev) → test site with PayPal sandbox keys and the sandbox webhook → orders in every language, a country with duty, a download product, a backorder, a closed browser tab after approval (the webhook must finish it), cancel in PayPal, customer account, password reset, admin status "Completed" with tracking (shipped email), Admin → Server check all green, then live keys.