Premium kitchenware e-commerce platform built as a modular client-side application.
The current repository ships a static storefront with product catalog rendering, cart management, modal flows, checkout, toast notifications, and localStorage-backed persistence.
- Introduction
- Live Demo
- Repository
- Features
- Screenshots
- GIF Demo
- Tech Stack
- System Architecture
- Folder Structure
- Module Overview
- Data Flow
- OOP
- SOLID
- Design Patterns
- Component Structure
- Naming Convention
- Coding Standards
- Installation
- Environment
- Scripts
- Development Workflow
- Build
- Production Build
- Deployment
- Git Workflow
- Branch Strategy
- Coding Convention
- Lint
- Format
- Troubleshooting
- Known Issues
- Roadmap
- Performance
- Optimization
- Browser Support
- Accessibility
- Security
- Testing
- Future Improvements
- FAQ
- Changelog
- Versioning
- License
- Author
- Contact
- Contributing
- Credits
- Acknowledgements
- Support
- Star History
- Footer
TriAD là một storefront thương mại điện tử dạng static, tập trung vào sản phẩm kitchenware của thương hiệu TriAD. Ứng dụng hiện được triển khai như một web app client-side, dùng native ES modules, HTML templates nạp động và localStorage để lưu trạng thái.
Trong mã nguồn hiện tại, ứng dụng khởi động từ src/index.js rồi bootstrap các component HTML từ thư mục pages/ trước khi khởi tạo các controller trong src/app/app.js.
- Trình diễn một kiến trúc frontend có tổ chức, tách rõ controller, service, repository, renderer và model.
- Thể hiện khả năng xây dựng một trải nghiệm mua sắm đầy đủ từ khám phá sản phẩm đến checkout.
- Tạo một portfolio repository đủ rõ ràng để nhà tuyển dụng đọc nhanh cấu trúc, luồng dữ liệu và tư duy kỹ thuật.
- Giảm độ rối của một storefront frontend bằng cách chia chức năng thành các module độc lập.
- Duy trì trạng thái giỏ hàng, bộ lọc, và đơn hàng ngay trên trình duyệt mà không phụ thuộc backend.
- Tạo luồng tương tác liền mạch cho tìm kiếm, lọc, modal chi tiết, toast và checkout trong cùng một ứng dụng.
Note
Tất cả mô tả trong README này chỉ dựa trên source code hiện có. Những phần chưa xác minh sẽ được ghi là Placeholder hoặc > TODO ở các phần tiếp theo.
| Item | Link |
|---|---|
| Live Demo | https://thang4869.github.io/TriAD-12/ |
| Repository | https://github.com/Thang4869/TriAD-12 |
Tip
Demo hiện có các luồng có thể kiểm chứng từ source: catalog sản phẩm, tìm kiếm có debounce, gợi ý tìm kiếm, cart drawer, product modal, checkout modal, success modal và toast.
| Field | Value |
|---|---|
| Owner | Thang4869 |
| Repository | TriAD-12 |
| Live Site | thang4869.github.io/TriAD-12 |
| License | See the badge above |
| Feature | Evidence in source | Notes |
|---|---|---|
| Product catalog | src/config/products.config.js | 5 TriAD product entries are loaded into the storefront |
| Product rendering | src/modules/products/index.js | Catalog is rendered by the products module |
| Search with debounce | src/modules/products/products.controller.js | Search input is debounced before updating filters |
| Search suggestions | src/modules/products/products.controller.js | Suggestions are rendered while typing |
| Sort and price filters | src/modules/products/products.controller.js | Sort select and price filter are wired into the service layer |
| Cart drawer | src/modules/cart/index.js | Drawer open/close behavior is controlled from the cart module |
| Add-to-cart flow | src/modules/products/products.controller.js | Product actions can add items to cart |
| Fly-to-cart animation | src/modules/fly-to-cart/index.js | Separate animation module is imported at app start |
| Product detail modal | src/modules/modal/index.js | Modal opens from the product catalog |
| Checkout flow | src/modules/checkout/index.js | Checkout modal, validation, processing, and success modal are implemented |
| Toast notifications | src/modules/toast/index.js | Toast service renders success, info, warning, and error messages |
| Persistence | src/shared/services/storage.service.js | Cart, products, filters, and orders use localStorage abstraction |
- Debounced search with suggestion list and keyboard focus shortcut
Ctrl/Cmd + K. - Modal-driven product detail flow with close-on-Escape behavior.
- Checkout validation before order processing.
- Success modal after order completion.
- Responsive navigation and cart interactions for mobile and desktop layouts.
- Event-driven updates through a shared event bus.
- Welcome and error toast feedback from the application bootstrap layer.
TODO Replace the placeholders below with real captures from the live demo.
| Desktop | Tablet | Mobile |
|---|---|---|
![]() |
![]() |
![]() |
Placeholder Add a short recorded demo showing product browsing, add-to-cart, modal opening, checkout, and success confirmation.
| Category | Technology | Notes |
|---|---|---|
| Frontend | HTML5, CSS3, JavaScript (ES Modules) | Core UI, styling, and application logic |
| Backend | None at runtime | The repository is a client-side application; source includes a simulated API service scaffold |
| Database | localStorage | Used through the storage abstraction for cart and order persistence |
| Tools | Git, GitHub, native browser APIs, Mermaid, Event Bus | Supporting workflow and application infrastructure |
| Design | Tailwind CSS CDN, Google Fonts (Jost), Phosphor Icons | Visual system and typography used by the UI |
| Deployment | GitHub Pages | Static hosting for the live demo |
flowchart LR
subgraph "Presentation Layer"
HTML["HTML Templates\nindex.html + pages/*"]
CSS["CSS Layer\nsrc/styles/*"]
UI["UI Components\nsrc/ui/components/*"]
end
subgraph "Application Layer"
Bootstrap["bootstrap()"]
App["App Orchestrator"]
Controllers["Cart\nProducts\nModal\nCheckout"]
end
subgraph "Domain Layer"
Models["Product\nCartItem\nOrder"]
Rules["Validation\nBusiness Rules"]
end
subgraph "Data Layer"
Repos["Repositories"]
Storage["StorageService"]
Local["localStorage"]
end
HTML --> Bootstrap
Bootstrap --> App
App --> Controllers
Controllers --> Models
Controllers --> Rules
Controllers --> Repos
Repos --> Storage
Storage --> Local
Controllers --> UI
| Layer | Responsibilities | Verified Components |
|---|---|---|
| Presentation | Render layout, sections, product cards, modal containers, styles | index.html, pages/*.html, src/styles/*, src/ui/components/product-card.component.js |
| Application | Bootstrap the app, initialize controllers, wire global behaviors | src/index.js, src/app/bootstrap.js, src/app/app.js |
| Domain | Encapsulate business entities and computed values | src/shared/models/product.model.js, src/shared/models/cart-item.model.js, src/shared/models/order.model.js |
| Business Logic | Apply filters, validation, checkout processing, modal state | src/modules/products/*, src/modules/cart/*, src/modules/checkout/*, src/modules/modal/* |
| Data Access | Persist and hydrate application state | src/shared/repositories/base.repository.js, src/modules/*/*.repository.js, src/shared/services/storage.service.js |
TriAD-12/
├── index.html
├── README.md
├── images/
├── pages/
│ ├── about.html
│ ├── cart-drawer.html
│ ├── checkout-modal.html
│ ├── features.html
│ ├── footer.html
│ ├── header.html
│ ├── hero.html
│ ├── product-modal.html
│ ├── products.html
│ └── success-modal.html
└── src/
├── index.js
├── app/
│ ├── app.js
│ ├── bootstrap.js
│ ├── header.service.js
│ └── scroll-reveal.service.js
├── config/
│ ├── products.config.js
│ └── settings.config.js
├── modules/
│ ├── cart/
│ │ ├── cart.controller.js
│ │ ├── cart.renderer.js
│ │ ├── cart.repository.js
│ │ ├── cart.service.js
│ │ └── index.js
│ ├── checkout/
│ ├── fly-to-cart/
│ ├── modal/
│ ├── products/
│ └── toast/
├── shared/
│ ├── constants/
│ ├── models/
│ ├── repositories/
│ ├── services/
│ └── utils/
├── styles/
│ ├── animations/
│ ├── base/
│ ├── components/
│ └── utilities/
└── ui/
└── components/
└── product-card.component.js
TODO If the repository grows, consider generating this tree automatically in CI so the README stays synchronized with the codebase.
| Module | Responsibility | Key Files |
|---|---|---|
| Cart | Add/remove items, quantity changes, drawer state, badge updates | src/modules/cart/cart.controller.js, cart.service.js, cart.repository.js, cart.renderer.js |
| Products | Load catalog, search, filter, sort, paginate, render cards and suggestions | src/modules/products/products.controller.js, products.service.js, products.repository.js, products.renderer.js |
| Checkout | Validate form data, calculate totals, create orders, show success flow | src/modules/checkout/checkout.controller.js, checkout.service.js, checkout.validator.js |
| Modal | Open/close product detail modal and coordinate quantity state | src/modules/modal/modal.controller.js, modal.service.js |
| Toast | Render transient notifications with auto-dismiss and limits | src/modules/toast/toast.service.js, toast.renderer.js |
| Fly-to-Cart | Animate product image toward the cart badge | src/modules/fly-to-cart/index.js |
sequenceDiagram
participant User
participant ProductsController
participant CartController
participant CartService
participant EventBus
participant StorageService
User->>ProductsController: Search / sort / add product
ProductsController->>CartController: addToCart(product)
CartController->>CartService: add(product, quantity)
CartService->>StorageService: save(cart)
CartService->>EventBus: emit(CART_UPDATED)
EventBus->>CartController: update drawer badge + totals
CartController->>User: refresh cart UI
flowchart LR
User[User Action] --> Controller[Controller]
Controller --> Service[Service]
Service --> Repository[Repository]
Repository --> Storage[(StorageService / localStorage)]
Service --> Bus[EventBus]
Bus --> Renderer[Renderer]
Renderer --> View[UI Update]
Product,CartItem, andOrderkeep fields private via underscored properties and expose controlled getters.StorageServicehides the storage backend behind a small API.- Controller state such as drawer or modal visibility is owned by the corresponding controller or service.
CartItemextendsProductto reuse product fields and computed price data.CartRepositoryandProductsRepositoryextendBaseRepositoryto share repository conventions.
BaseRepositorydefines the repository contract, while concrete repositories overridefindAll,findById, andsavebehavior where needed.Product.fromJSON(),CartItem.fromJSON(), andOrder.fromJSON()provide uniform object hydration from stored JSON.
- Business rules are split into services instead of being embedded in UI handlers.
- Validation is isolated in
CheckoutValidator. - Persistence is abstracted through repositories and
StorageServicerather than directlocalStoragecalls in controllers.
| Principle | Implementation Evidence |
|---|---|
| Single Responsibility | Controllers coordinate, services apply business rules, repositories persist data, renderers output UI |
| Open/Closed | Repositories and services can be extended without rewriting shared abstractions such as BaseRepository |
| Liskov Substitution | CartRepository and ProductsRepository can be used through BaseRepository-style behavior |
| Interface Segregation | Each module exposes a focused surface instead of a monolithic API |
| Dependency Inversion | Controllers depend on services and repositories, while storage details are hidden behind abstractions |
| Pattern | Status in repo | Evidence |
|---|---|---|
| Factory | Used | fromJSON() methods in Product, CartItem, Order |
| Strategy | Used | ProductsService.applySort() switches sort behavior by mode |
| Observer | Used | EventBus with on, once, off, emit |
| Singleton | Used | Exported shared instances such as eventBus, storage, and toast |
| Module | Used | Native ES modules across src/ |
| MVC | Used | Controllers, services, repositories, and renderers are separated by responsibility |
| Repository | Used | BaseRepository, CartRepository, ProductsRepository |
| Adapter | Not used | No dedicated adapter layer was found in the current source tree |
| Component Type | Examples | Role |
|---|---|---|
| HTML partials | pages/header.html, pages/hero.html, pages/products.html |
Page sections loaded dynamically at bootstrap |
| UI components | src/ui/components/product-card.component.js |
Reusable card markup for catalog items |
| Renderers | cart.renderer.js, products.renderer.js, toast.renderer.js |
Convert application state into DOM output |
| Controllers | cart.controller.js, products.controller.js, modal.controller.js, checkout.controller.js |
Bind DOM events and orchestrate flows |
| Services | cart.service.js, products.service.js, modal.service.js, checkout.service.js |
Enforce business logic and state transitions |
- Files use kebab-case with role suffixes such as
.controller.js,.service.js,.repository.js,.renderer.js,.model.js, and.config.js. - Classes use PascalCase, for example
CartController,ProductsService,CheckoutValidator, andProductCardComponent. - Constants use UPPER_SNAKE_CASE, such as
APP_CONFIG,EVENTS, and storage keys. - DOM identifiers are descriptive and semantic, for example
checkout-modal,cart-overlay,search-input, andtoast-container.
- Keep controllers thin and move data logic into services or repositories.
- Prefer explicit event names over implicit cross-module coupling.
- Use small, composable methods with a single responsibility.
- Preserve immutable-style updates when creating model instances or cart item changes.
- Use
debounce()for high-frequency inputs to avoid unnecessary re-renders. - Keep UI rendering inside renderer classes or reusable components.
- Avoid direct
localStorageaccess outside the storage abstraction.
The repository does not include a package.json, build tool, or dependency manager configuration. This is a static HTML/CSS/JavaScript project that runs directly in the browser.
- Clone the repository.
- Open the project in VS Code or any local web server.
- Serve the root folder through HTTP, then open
index.htmlfrom that server.
# Example local server options
python -m http.server 8000
# or
npx serve .Important
Do not open index.html directly with file://. The app loads HTML partials with fetch(), so a local HTTP server is required.
| Item | Value |
|---|---|
| Runtime | Browser-native ES modules |
| Styling | Tailwind CSS CDN |
| Fonts | Google Fonts (Jost) |
| Icons | Phosphor Icons CDN |
| Data persistence | localStorage via StorageService |
| Demo hosting | GitHub Pages |
- No
.envfile, API keys, or backend credentials are required for the current codebase. - The app reads product seed data from
src/config/products.config.jsand stores runtime state in browser storage. src/shared/services/api.service.jsexists as a scaffold for future backend work, but the current UI does not depend on a live API.
There are no repository-defined npm scripts because the project does not ship a package.json file.
| Script | Status | Notes |
|---|---|---|
install |
Not available | No package manifest is present |
dev |
Not available | Use a local static server instead |
build |
Not available | The app is served as static files |
lint |
Not available | No lint configuration was found |
test |
Not available | No test runner is configured |
- Edit HTML partials under
pages/for layout and section content. - Edit module logic under
src/modules/for feature behavior. - Update shared models, services, and utilities under
src/shared/when behavior is reused. - Refresh the browser through the local server to verify UI changes.
Edit source -> Refresh browser -> Verify modal/cart/checkout flow -> Commit changes
No compile step is required for the current repository state.
The production artifact is the same static file set already in the repository:
index.htmlpages/*src/*images/*README.md
TODO If the project later adopts a bundler, document the output directory and asset pipeline here.
For the current version, production means:
- Serving the static site over HTTPS or a local HTTP server.
- Ensuring relative asset paths resolve correctly.
- Verifying the live demo after deployment.
The repository is already published at https://thang4869.github.io/TriAD-12/.
- Push the static site to the repository.
- Configure GitHub Pages in repository settings.
- Point Pages to the branch or folder that contains
index.html. - Verify that the
/pagesand/srcrelative paths resolve on the published site.
Note
Because the app uses fetch() to load partial HTML, the published Pages base path must preserve the repository-relative asset structure.
| Step | Practice |
|---|---|
| 1 | Make focused changes in a single feature area when possible |
| 2 | Verify the browser flow locally through the static server |
| 3 | Review the diff before pushing |
| 4 | Commit with a message that describes the behavior change |
| 5 | Push to the remote repository and re-check the GitHub Pages demo |
TODO The repository does not expose an explicit branching policy in code, so the safest documented strategy is:
mainfor the deployable site.- Short-lived feature branches for isolated work.
- A release branch only if the project later introduces staged approvals.
- Keep filenames aligned with responsibility suffixes, for example
*.controller.js,*.service.js,*.repository.js,*.renderer.js, and*.model.js. - Keep DOM selectors descriptive and stable because they are used across modules.
- Prefer
constandletovervar. - Keep user-facing strings centralized where practical, especially in config and service layers.
- Avoid direct storage access outside the persistence abstraction.
No lint configuration was found in the repository.
TODO If linting is added later, document the exact command and rule set here.
No formatter configuration was found in the repository.
TODO If formatting tools are added later, document the exact command here.
- Confirm the site is opened through
http://localhostor the GitHub Pages URL. - Do not use
file://. - Verify that the
pages/directory is present and the relative paths insrc/app/bootstrap.jsare unchanged.
- Verify the image paths in
src/config/products.config.jsstill point to existing files underimages/. - Confirm the server root preserves the repository directory structure.
- Check that the relevant HTML partial has loaded before interacting with the page.
- Confirm the DOM IDs used by the controller match the HTML in
pages/*.html. - Inspect the browser console for runtime errors.
- Verify all required fields pass
CheckoutValidator. - Check whether the cart is empty before opening checkout.
- Confirm the cart drawer and checkout modal elements are present in the loaded page.
- Reload the page to reset the in-memory controller state.
- Clear browser storage if you want to reset saved filters and cart data.
- There is no
package.json, so npm-based scripts and toolchain commands are not available yet. - No automated test suite is configured in the current repository.
- No lint or format config is present in the repository root.
- Placeholder images are still used in this README for screenshots and GIF demo until real assets are added.
- Static storefront structure
- Product catalog rendering
- Search, sort, and price filters
- Cart drawer and cart state persistence
- Product modal and checkout flow
- Toast notifications
- Add real screenshot assets
- Add GIF demo asset
- Add automated tests
- Add lint and format tooling
- Add package manifest and npm scripts
- Introduce a backend API layer if the product scope expands
The current codebase already uses several lightweight performance choices that are visible in source:
debounce()for search input handling.IntersectionObserverfor load-more behavior.- Lazy-loaded product images in the product card component.
- Separate renderers so UI updates stay localized.
- Native browser APIs instead of a heavy client framework.
| Area | Current Approach | Potential Next Step |
|---|---|---|
| Search | Debounced input updates | Add cached suggestion rendering |
| Catalog | Pagination and load-more behavior | Virtualize very large lists |
| Images | Lazy loading on product cards | Preload critical hero assets |
| State | localStorage-backed persistence | Introduce server sync when backend exists |
| UI updates | Renderer classes per feature | Batch DOM writes where needed |
This repository targets modern evergreen browsers because it uses:
- Native ES modules.
fetch()for HTML partial loading.IntersectionObserver.requestAnimationFrame.- Modern CSS classes and responsive layout behavior.
TODO If you need legacy browser support, add a compatibility layer and document the supported matrix here.
Verified accessibility-related implementation details:
- Toast elements use
role="alert"andaria-live="polite"in the renderer. - Button elements are used for interactive actions such as closing toasts and opening checkout.
- The app supports keyboard shortcuts for focus and modal dismissal.
- Images carry
altattributes in the product card component.
- Add a documented focus trap for modal dialogs.
- Audit color contrast in the final visual design.
- Add skip links if the page layout grows.
- Ensure all dynamic sections have clear headings and landmarks.
The current project is a client-side storefront, so the security surface is intentionally small.
- No credentials or secrets are stored in the repository.
- No remote API calls are required for the current user flow.
- Form validation happens before checkout processing.
- State persistence is limited to browser storage.
- Treat
localStorageas user-controlled data. - Never store sensitive payment data in the browser in a real production deployment.
- Escape or sanitize any future backend-supplied HTML before rendering it.
No automated test suite is configured in the repository at the moment.
- Open the site through a local HTTP server.
- Verify product cards render from
src/config/products.config.js. - Search for a product and confirm the suggestion list appears.
- Change sort and price filters and verify the catalog updates.
- Add and remove items from the cart.
- Open the product modal and checkout modal.
- Complete checkout with valid and invalid data.
- Refresh the page and confirm persisted cart or order state behaves as expected.
- Add a real screenshot set for desktop, tablet, and mobile.
- Record and embed a short product demo GIF.
- Add unit tests for services, validators, and repositories.
- Add end-to-end tests for the main shopping flow.
- Add a bundler and npm scripts if the project scope expands.
- Replace placeholder demo assets with branded production assets.
- Add a backend API if order storage or inventory management becomes server-side.
| # | Question | Answer |
|---|---|---|
| 1 | Is this project a frontend-only application? | Yes. The current repository is a static client-side storefront. |
| 2 | Does it require a backend to run? | No. The current user flow works without a backend. |
| 3 | Why must I use a local server? | Because HTML partials are loaded with fetch(). |
| 4 | Can I open index.html directly? |
Not reliably. Use HTTP instead of file://. |
| 5 | Where do products come from? | From src/config/products.config.js, then from browser storage if already cached. |
| 6 | Is the cart persisted? | Yes, through StorageService and localStorage. |
| 7 | Are search and filters persisted? | Yes, filter state is stored in browser storage. |
| 8 | Is there a checkout validator? | Yes, CheckoutValidator checks required fields and formats. |
| 9 | Does the project support modal interactions? | Yes, product detail, checkout, and success modals are present. |
| 10 | Is there a toast system? | Yes, ToastService and ToastRenderer handle notifications. |
| 11 | Does the project include tests? | No automated tests are configured yet. |
| 12 | Does the project include linting? | No lint configuration was found in the repository. |
| 13 | Does the project include a package manager setup? | No package.json is present in the current repository. |
| 14 | Is there a backend API today? | No live backend is used by the current codebase. |
| 15 | Can I use this as a portfolio project? | Yes. The repository shows modular architecture, state management, and documented flows. |
TODO Add a dedicated
CHANGELOG.mdif the project starts using semantic releases or tagged versions.
TODO The repository does not currently expose a tagged release version in source control or project files.
TODO No
LICENSEfile was found in the repository root. Add one before treating the project as formally licensed.
Thang4869— GitHub repository owner and project author visible from the repository metadata.
- GitHub repository: https://github.com/Thang4869/TriAD-12
- Live demo: https://thang4869.github.io/TriAD-12/
If you want to contribute to this repository:
- Fork the repository.
- Create a short-lived feature branch.
- Make a focused change.
- Verify the result in the browser.
- Open a pull request with a clear description.
TODO Add contribution guidelines if the project adopts external contributors.
- HTML5, CSS3, JavaScript, GitHub Pages, and GitHub Shields.io badges.
- Google Fonts for typography.
- Phosphor Icons for iconography.
- Tailwind CSS CDN for utility styling in the current page shell.
- Inspiration from modern product-focused GitHub repositories that emphasize clarity and architectural documentation.
- Appreciation for static-site patterns that keep portfolio projects easy to deploy and review.
- Star the repository if you find the architecture and documentation useful.
- Open an issue if you find a mismatch between the README and the source.
- Share the live demo if you want to show the project in a portfolio review.
![Star History Placeholder]
Placeholder Replace this with a real star-history chart if the repository gets enough public traction.
TriAD is a modular static storefront for premium kitchenware, documented to showcase product architecture, state management, and checkout flow.
This README is intentionally conservative about claims: if something is not verified in the source tree, it stays labeled as TODO or Placeholder.





