BUILD LEDGER · ACCESSION RECORD

Bshopify — everything built, in order

A Persian-language bookstore storefront, account area and admin console, reconstructed from scratch and now carrying a real 9,092-title catalog. This record covers every phase from the first scaffold to the live, deployed site.

Live at bshopify.padrasm.xyz Stack Angular 20 · Express · MySQL Status in production Repo github.com/pedramas797/Bshopify (private) This ledger ledger.bshopify.padrasm.xyz

Accession 00 — Summary

What this project is, and where it stands

Bshopify rebuilds the page structure, navigation and shopping journeys observed on pbook.shop as an original Persian (RTL) bookstore UI — its own brand, its own visual system, never pbook's logo or promotional art. It began as a fully mocked prototype and now runs a real, self-hosted catalog of 9,092 books behind it.

§1 At a glance

9,092
real books imported
9,087
covers downloaded, 0 failed
50+
screens across storefront, account, admin
21
new database tables
6
new backend API domains
5
bugs found & fixed in-session

§2 System map

One Angular 20 app covers three audiences — shoppers, account holders, and store admins — on one Express/MySQL backend. Everything to the left of the database was built this project; the import pipeline on the right is what fills it with real inventory.

Browser RTL · fa-IR Angular 20 storefront / account / admin nginx static build · /api · /catalog-media bshopify-api Express, systemd-managed MySQL db: bshopify pbook.shop snapshot 58MB JSON · 9,092 products import-pbook-catalog.ts PLANNED, NOT YET BUILT — QR PRICE & INVENTORY (SEE TAB 08) Admin: QR reader camera or photo upload Admin: books editor + advanced search Admin: inventory counts · +1 / −1 · set /api/admin/* books · qr/resolve · inventory HTML parser price · image · specs · stock Scheduler (cron) price + stock sync jobs New tables in MySQL book_sources · sync_runs · stock movements Publisher pages olgoobooks.ir QR links · other price links Stock API (if one exists) otherwise counts are kept by hand solid = live today · dashed teal = planned · dashed brass = outside source

Mock stores (cart, orders, wallet, admin) still run client-side; only the catalog domain is now backed by this pipeline. The dashed lower half is the planned QR price & inventory system — designed, not built.

§3 Build phases, in order

Full UI build

Every storefront, account and admin screen built as a UI-only, fully mocked Angular 20 app — Material M3 theme, RTL layout, signal-based mock stores.

Live deployment stood up

GitHub repo, nginx static site with TLS, and an installed bshopify deploy CLI.

Visual design pass

Re-themed to match pbook.shop's actual computed styles (palette, radii, card patterns), then swapped typography to Markazi Text for a more authentically Persian face.

Stale-chunk navigation bug fixed

Added a hard-reload recovery for post-deploy chunk-load failures that were reading to users as "buttons don't work."

Real catalog import

Migrated the database, imported 9,092 real products with images, authors, taxonomy, navigation and homepage sections, and wired the storefront to a new read API.

Production cutover

Backend promoted to a systemd service; nginx extended with /api and /catalog-media proxies; verified live with zero regressions to sibling sites.

Design audit against real data

Found and fixed a homepage bug where five shelves showed identical books, and a media-path collision that would have 404'd every cover in production.

Accession 01 — Interface

Storefront, account and admin, screen by screen

Built as three separate audiences sharing one codebase: shoppers on the storefront, signed-in customers in the account area, and staff in a visually distinct admin console.

§1 Storefront (7 flows)

  • Home — data-driven homepage sections (MainSection[]), built so a future full-screen redesign can replace just the renderer.
  • Catalog — one template serves search, category, publisher and collection views, with URL-driven filters, sort and pagination.
  • Product detail — gallery, specs, used-copy offers as distinct purchasable line items, reviews and questions.
  • Cart & checkout — full cart page plus a drawer preview, a stepper checkout (delivery → discount → payment), card-to-card receipt upload.
  • Payment result — four distinct states: confirmed, failed, verifying, receipt pending review.
  • Auth — phone entry → 6-digit OTP with resend cooldown, preserving the shopper's return destination.

§2 Account area (10 screens)

Everything under /dashboard: overview, orders and order detail, addresses, profile, reviews & questions, support tickets, favorites, wallet, and a customer club with points, rewards and a spin-to-win wheel.

§3 Admin console (10 screens)

A separately themed, denser .theme-admin shell under /admin: catalog CRUD, a homepage sections/collections editor whose edits reflect on the storefront immediately, order and receipt review, customer wallet and club management, moderation queues, content and campaign editing, settings, and roles.

§4 Shared component library

16
custom UI components
6
Material-wrapped components
17
unit tests, all passing

Book card, price display, rating stars, hero carousel, shelf, search-with-suggestions and more — built from design tokens rather than stock Material, so storefront and admin read as visually distinct systems.

Accession 02 — Visual System

Matching pbook.shop's visual language — not its brand

Rather than guessing at a "bookstore look," the actual computed styles of pbook.shop were inspected live with headless Chrome — real colors, radii and card patterns — then rebuilt as an original system. The logo, wordmark and promotional art were deliberately left out.

§1 Palette, extracted and rebuilt

#2000F3 primary
#2E1065 hero
#DC3545 discount
#F2740C promo
#0EC1B2 used-books
#FDE047 rating

Regenerated as a full Material M3 theme from the #2000F3 seed, with structural components (dialogs, drawers, tabs) on the Material theme and storefront-specific pieces (cards, carousel, pricing) on raw design tokens so they read distinctly from Material chrome.

§2 Typography journey

PassTypefaceReason
Initial buildVazirmatn + Noto Naskh ArabicBroad Persian coverage, literary display pairing
Follow-upMarkazi Text VariableDesigned specifically for Persian; more authentic feel, requested by the owner

Both are open-license (SIL OFL) and self-hosted — no external font requests, no dependency on pbook's commercial iranYekan/YekanBakh faces.

§3 What was deliberately not copied

  • pbook's logo and wordmark
  • Their promotional campaign art (e.g. a phone-giveaway banner)
  • Their literal page copy and legal text

The hero carousel instead uses a small generated stacked-books motif, and the 39 icons brought in later were confirmed generic UI glyphs — chevrons, hearts, search, bell — never brand marks.

Accession 03 — Infrastructure

Getting it onto the internet, and keeping it reliable

The site runs as static files served by nginx with TLS, deployed through a small installed CLI — and one real production bug, caused by the deploy process itself, was diagnosed and fixed.

§1 Hosting

  • Repository — private GitHub repo, pedramas797/Bshopify
  • Site — bshopify.padrasm.xyz, nginx + Certbot TLS, alongside this server's other sites without conflict
  • Deploy CLI — bshopify deploy rebuilds and syncs to the web root with a live health check; bshopify status reports the last deploy time

§2 Fixed: "buttons in different sections stopped working"

Stale lazy-chunk navigation failurefixed

Diagnosed with 20+ scripted interaction tests against the live site — all passed in a fresh session, which pointed at a deploy-timing race instead of a UI defect. Each deploy's rsync --delete removes the previous build's hashed chunk files; a tab left open from before a deploy would 404 the first time it needed an unvisited route. Fixed with a router-level handler that detects a chunk-load failure and reloads automatically.

Accession 04 — Catalog Import

9,092 real books, from scrape to storefront

The owner supplied a structured public-data capture of pbook.shop — products, offers, images, navigation, homepage sections, filters and video reviews — with an explicit mandate: real database, self-hosted images, no copied logo.

§1 What the capture contained

9,092
products
9,087
product images
41,383
product attributes
8,299
product relations
2,176
taxonomy terms
325
collections
255
video reviews
148
navigation items
39
generic UI icons
9,092 total titles 5,075 new 4,017 used

Each used copy is kept as its own catalog row, resolved to its new-book listing — never merged, even when source URLs look identical.

§2 Pipeline

JSON snapshot 58MB, read from disk migration 002 21 new tables, additive import-pbook-catalog.ts idempotent upserts, batched download-book-images.ts 9,087 / 9,087 succeeded books-service.ts read API → storefront

§3 Bugs the import verification caught

Column too narrow for real datafixed

Grade and study-field values turned out to be comma-joined lists up to 74 characters (e.g. "علوم انسانی, علوم تجربی, ریاضی فیزیک"), not short tokens — overflowing a VARCHAR(64) column 31 rows into the import. Widened via a follow-up migration rather than editing the applied one.

Used-copy relation direction was backwardsfixed

The source's used_offer_related relation runs new → used, not the reverse assumed on first pass — so zero used copies resolved to their new book. Confirmed by sampling actual rows, then corrected; all 4,017 used copies now resolve correctly, none merged.

Accession 05 — Cutover

Putting the real backend into production

The backend had never run as a persistent service before — this is the first time anything beyond the static frontend has been deployed for Bshopify.

§1 What changed on the server

  • bshopify-api.service — new systemd unit, auto-restart, reading credentials from the existing backend/.env
  • nginx — two new location blocks on the existing site config, proxying /api and /catalog-media to the backend, leaving the static SPA route untouched
  • Frontend rewiring — a scoped BooksApi service used only by home, shop, product detail and search; everything else (cart, checkout, orders, favorites, admin) stayed on the existing mock layer, unmodified

§2 Live verification

CheckResult
Home page book covers100 real covers rendered
Shop page result count5,075 — matches the new-book total exactly
Add-to-cart pricingCorrect real price confirmed, not a silent zero
Sibling sites after nginx reloadjj.padrasm.xyz, takupi.padrasm.xyz unaffected
Console / network errorsNone, across the full sweep

Accession 06 — Design Audit

What held up under real content, what didn't

The existing visual system was built against clean mock data; a pass against the real, messier catalog surfaced two genuine issues and ruled out three false alarms.

§1 Found and fixed

Five homepage shelves showed identical booksfixed

Traced to the source capture itself, not the import — its per-section item lists are identical across all five "best of" shelves. Since each shelf's title says exactly what it should contain, each now pulls its own real results (by study field, discount or recency) instead of trusting that join.

/media path collisionfixed

Angular's own build already writes self-hosted font files to a media/ folder — the backend's original image-serving prefix collided with it. Renamed to /catalog-media before it could 404 fonts in production.

§2 Investigated, not bugs

  • Blank book covers mid-scroll — correct native lazy-loading deferring off-screen carousel items, confirmed by bounding-box inspection.
  • Mobile nav appearing mid-grid — a full-page screenshot artifact; the nav is correctly position: fixed on-device.
  • A handful of oversized source images — 21 of 9,087 are full-resolution originals up to 3MB; real but marginal, not worth a thumbnail pipeline.

Accession 07 — Open Items

What's still mocked, on purpose

Scoped deliberately, not overlooked — each of these was a conscious cut to keep the catalog-import pass bounded.

Accession 08 — Design, Not Yet Built

QR-linked pricing and inventory — business map

A new system, planned before any code: every physical book carries a QR code that resolves to its publisher's own product page — image, price, and specs, kept current by the publisher, not by us. The plan is to read price and stock from that page automatically instead of re-entering it by hand, and to keep that working for books added without a QR too.

§0 Admin panel business plan, as given

Reproduced close to the owner's own structure, so the design below can be checked against it directly rather than only against my own restatement.

  1. Admin panel to add books. Each book carries: category, genre, sub-genre, settings, price, name, publisher, writer, published year, subtitle, title, volume, series, editors, printer, etc. (full list in §3).
  2. Admin manages books through this panel — create, edit, and organize them by those fields.
  3. Books can be added via their QR code:
    1. a QR code reader in the admin flow,
    2. an HTML parser that reads the book's data off the publisher's link,
    3. an app-wide scheduler task that keeps re-checking that link and updating the price for every book added this way.
  4. Books added without a QR — but that have a price link (including ones migrated in with a link already on record) — go through the exact same scheduler flow as QR-added books.
  5. Admin also manages inventory:
    1. a book list with advanced search,
    2. an inventory count-down/count-up option, reading each book's remaining count from an API,
    3. or the admin sets the remaining count by hand, and the app decrements it automatically as the book is added to baskets.
  6. A dedicated inventory page:
    1. a scheduler task updates remaining counts from the API (for books that already have a link),
    2. counts down and up as books move.

§1–§6 below are the elaboration of this plan: what each point implies for the data model, the two sync loops (price and inventory), and what needs confirming before any of it is built.

§1 The trigger

A book's QR code resolves to a publisher product page, e.g.:

Example linkWhat's on it
olgoobooks.ir/qrcode/1c3fc9ae/Cover image, current price, and the publisher's own listing details for that exact title

That page is the source of truth for price (and, where the publisher's page shows it, stock) — this system's job is to read it on a schedule and keep our own catalog in sync, not to re-key it by hand every time it changes.

§2 Business map

Two ways a book enters the sync pipeline — scanned via QR, or linked manually for books migrated without one — both land in the same scheduler. Inventory has its own, separate two-path split: synced from a source where one exists, or tracked manually and decremented automatically at checkout.

Admin scans QR on book camera / image upload Admin pastes price link books migrated w/o a QR Book record source_url saved either way Scheduler (cron) visits every book with source_url HTML parser extracts price (+ stock if shown) Catalog price updated last_synced_at stamped INVENTORY — SEPARATE FROM PRICE SYNC Source exposes stock scheduler reads it like price No stock source admin sets count by hand current_stock (per book) one number, either source Order placed at checkout existing Bshopify cart flow Count decremented automatic, on each sale

Price sync (top) and inventory (bottom) share the same book record but run as two independent loops — a book can have accurate pricing with manually-tracked stock, or vice versa.

§2a New-features site map

The same box-and-arrow style as the Overview system map, covering only the new QR price and inventory features and where they attach to what already runs.

Admin: QR reader camera or photo upload Admin: books 15-field editor · advanced search Admin: inventory counts · +1 / −1 · set Storefront checkout exists · decrements stock nginx exists · /api proxy /api/admin/* books · qr/resolve · inventory HTML parser price · image · specs · stock Scheduler (cron) price + stock sync jobs /api/books + orders exists · order hook added MySQL: new tables book_sources · sync_runs · stock moves Publisher pages olgoobooks.ir QR · other price links Stock API (if one exists) else counts kept by hand MySQL: books, orders exists · price + stock columns teal = new · grey = exists today · dashed brass = outside source

Admin requests go through the existing nginx /api proxy to the new admin endpoints; the scheduler reuses the same parser the QR intake uses, and checkout keeps decrementing stock through the existing order flow.

§2b System architecture

Every part of the plan placed on the existing stack: what lives in the Angular admin, what the Express API and its background jobs do, which tables hold it, and which outside systems it reads from. Teal boxes are new; grey boxes already exist today.

CLIENTS — ANGULAR 20 BSHOPIFY-API — EXPRESS (systemd) MYSQL — db: bshopify OUTSIDE SYSTEMS Admin: Book editor 15 fields · category / genre sub-genre · writer · series… source link (optional) Admin: QR reader camera or photo upload decodes → publisher URL prefills the book editor Admin: Book list advanced search on all fields · sync status last synced · source type Admin: Inventory page stock per book · +/− buttons mode: synced / manual movement history Storefront (exists) shows synced price + stock cart / checkout places order out-of-stock blocks add-to-cart /api/admin/books CRUD + search + filters admin-auth protected /api/admin/qr/resolve URL → parser → draft book for admin to confirm HTML parser service fetch + extract price, image, specs, stock /api/admin/inventory GET count · POST +1 / −1 set count · history /api/books (exists) + order hook: decrement stock when an order is placed Scheduler (cron) price + stock jobs, rate-limited books (+ new cols) genre · sub_genre · volume editors · printer · settings current_stock · stock_mode book_sources source_url · type: qr / link qr_code · last_synced_at last_error · sync_enabled sync_runs job · started / finished checked · changed · failed price_history per book inventory_movements book · delta · reason sync / manual / order who · when orders (exists) placing one writes a −qty movement Physical book + QR code olgoobooks.ir/qrcode/1c3fc9ae/ scanned once, at intake Publisher product pages olgoobooks.ir (QR) + other price links source of truth for price Stock API (if one exists) remaining count per book else: manual counts only teal = new · grey = exists today · dashed brass = outside systems · dashed teal arrow = scheduled

One Express process carries both the admin API and the scheduler; the parser is shared by the one-time QR intake and the recurring sync, so a page-layout change at the publisher only needs fixing in one place.

§3 Admin panel — book fields

Every field the owner specified for a book record, as given:

  • F-01Category
  • F-02Genre
  • F-03Sub-genre
  • F-04Settings — meaning to confirm, see §6
  • F-05Pricesynced
  • F-06Name
  • F-07Publisher
  • F-08Writer
  • F-09Published year
  • F-10Subtitle
  • F-11Title
  • F-12Volume
  • F-13Series
  • F-14Editors
  • F-15Printer

Plus, outside the per-book field list: source_url (the QR-resolved or manually-pasted link), source_type (qr / manual-link / none), last_synced_at, current_stock, and stock_mode (synced / manual) — needed to make the sync and inventory loops work, not asked for explicitly but implied by them.

§4 System components

ComponentJob
QR readerDecodes a QR code (device camera or an uploaded photo) to the publisher link, in the admin book-create flow
HTML parserFetches a book's source_url and extracts price (and stock, where shown) from the publisher's page markup
SchedulerCron-style job iterating every book with a source_url, re-running the parser and writing price/stock updates
Inventory engineTwo modes per book: synced automatically like price, or admin-set and auto-decremented on each order
Book listAdvanced search/filter admin view across all the fields in §3, plus sync status and stock mode

§5 Open questions before building

What does "settings" mean as a book field?to confirm

Listed alongside category/genre/price but not described — could be visibility (published/draft), a feature flag, or something else specific to how olgoobooks.ir or the admin workflow uses the word.

Is there a real stock API, or is "API" the one we're building?to confirm

The brief says inventory can be read "from the api" — worth confirming whether that means the publisher's site exposes one (uncommon for a storefront page), or whether it means the internal count-up/count-down endpoints this system itself would expose to the admin UI.

Scrape politely, and confirm it's allowedto confirm

Olgoobooks.ir is the publisher's own site and this is for the publisher's own book prices, which is a reasonable operational use — but before a scheduler hits it on a recurring basis, worth checking robots.txt/terms and picking a conservative interval and request rate.

§6 Status

design only Nothing in this section is built yet — this is the business map to review before any schema, scraper, or admin-UI code is written, per the owner's explicit request to design first.