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.xyzStack Angular 20 · Express · MySQLStatus in productionRepo 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.
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
Pass
Typeface
Reason
Initial build
Vazirmatn + Noto Naskh Arabic
Broad Persian coverage, literary display pairing
Follow-up
Markazi Text Variable
Designed 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.
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
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
§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
Check
Result
Home page book covers
100 real covers rendered
Shop page result count
5,075 — matches the new-book total exactly
Add-to-cart pricing
Correct real price confirmed, not a silent zero
Sibling sites after nginx reload
jj.padrasm.xyz, takupi.padrasm.xyz unaffected
Console / network errors
None, 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.
LIM-01Admin catalog editing doesn't persist. AD02/AD03 still write to the mock store; browsing and buying real books works, editing them from /admin does not yet reach the database.mocked
LIM-02Two homepage section kinds stay mocked.video_shelf and publisher_shelf still render from the old ContentStore/CatalogStore rather than the real imported videos and publishers.mocked
LIM-03Hero and promo imagery stays placeholder art. Deliberate: pbook's own campaign creative (e.g. a phone-giveaway banner) is excluded under the project's standing policy against copying promotional art.policy
LIM-04No backend test suite yet. Type-checking is clean and every import/API flow was verified by hand; automated backend tests don't exist yet (pre-existing gap, not introduced here).gap
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.
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).
Admin manages books through this panel — create, edit, and organize them by those fields.
Books can be added via their QR code:
a QR code reader in the admin flow,
an HTML parser that reads the book's data off the publisher's link,
an app-wide scheduler task that keeps re-checking that link and updating the price for every book added this way.
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.
Admin also manages inventory:
a book list with advanced search,
an inventory count-down/count-up option, reading each book's remaining count from an API,
or the admin sets the remaining count by hand, and the app decrements it automatically as the book is added to baskets.
A dedicated inventory page:
a scheduler task updates remaining counts from the API (for books that already have a link),
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 link
What'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.
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 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.
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
Component
Job
QR reader
Decodes a QR code (device camera or an uploaded photo) to the publisher link, in the admin book-create flow
HTML parser
Fetches a book's source_url and extracts price (and stock, where shown) from the publisher's page markup
Scheduler
Cron-style job iterating every book with a source_url, re-running the parser and writing price/stock updates
Inventory engine
Two modes per book: synced automatically like price, or admin-set and auto-decremented on each order
Book list
Advanced 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.