// project ·
Full-Stack E-Commerce Platform
Built a shop to learn boring checkout state without breaking it. Stack: Angular, Hasura GraphQL, TypeScript.
Role: Personal project · Year: 2023 - 2024 · Status: shipped
tldr: Shoply is an Angular storefront over a Hasura GraphQL catalog. The server handles search, filtering, sorting, and pagination; the cart and wishlist live in the browser. Most of the work went into client state that survives refreshes, stale data, and bad input.
Problem
A storefront looks simple until the state piles up. Catalog filters, the cart, the wishlist, and a multi-step checkout all have to agree with each other and survive a page refresh. I built Shoply to work through that state carefully instead of hand-waving it.
Constraints
- The catalog is remote and read-only. Products come from a hosted Hasura instance. The frontend never writes to it, so it can’t assume a product saved in the cart last week still has the same stock.
- Browser storage is untrusted input. Cart and wishlist data persist in
localStorage, where anything can end up: an old format, an edited value, half-written JSON. - Tests can’t depend on the hosted backend. If Hasura is down, the test suite still has to pass.
Decisions
- Server-side catalog queries. Search, category and price filters, sorting, and pagination go into one GraphQL query, so the browser only receives the page it shows.
- Signals for state. The cart, wishlist, and checkout are signal-based services with computed totals.
- A versioned cart format. The stored cart carries a
versionfield. On load, every line is validated, quantities are clamped to available stock, and carts saved in the older format are migrated instead of thrown away. - Lazy loading. Every route is lazy, and the Apollo providers load with the catalog, which keeps GraphQL code out of the initial shell.
- Checkout is a demo flow. Shipping details are validated, and the payment step offers card, PayPal, and bank transfer as demo choices. No payment is processed.
Outcome
The Jest suite enforces 100% coverage for branches, functions, lines, and statements. Cypress covers the home, catalog, cart, and wishlist flows against deterministic GraphQL fixtures, so the end-to-end tests never touch the hosted service. The store is live on Netlify.