{"id":22911450,"url":"https://github.com/lcaohoanq/shoppe","last_synced_at":"2026-04-08T11:31:26.633Z","repository":{"id":266594666,"uuid":"897691527","full_name":"lcaohoanq/shoppe","owner":"lcaohoanq","description":"I'm clone Shopee","archived":false,"fork":false,"pushed_at":"2025-12-18T19:13:07.000Z","size":40103,"stargazers_count":2,"open_issues_count":17,"forks_count":0,"subscribers_count":1,"default_branch":"develop","last_synced_at":"2026-01-03T14:25:13.218Z","etag":null,"topics":["android","ci-cd","cross-platform","docker","ecommerce","eureka","eureka-server","gateway","java","kotlin","microservices","postgresql","react","redis","spring-boot","tailwindcss","typescript"],"latest_commit_sha":null,"homepage":"https://shoppe-git-develop-lcaohoanqs-projects.vercel.app/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lcaohoanq.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-12-03T04:17:28.000Z","updated_at":"2025-08-11T06:27:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"f5e4e8b9-2122-4ab9-b740-65500d32e1ff","html_url":"https://github.com/lcaohoanq/shoppe","commit_stats":null,"previous_names":["lcaohoanq/shoppe"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lcaohoanq/shoppe","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lcaohoanq%2Fshoppe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lcaohoanq%2Fshoppe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lcaohoanq%2Fshoppe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lcaohoanq%2Fshoppe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lcaohoanq","download_url":"https://codeload.github.com/lcaohoanq/shoppe/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lcaohoanq%2Fshoppe/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31553997,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T10:21:54.569Z","status":"ssl_error","status_checked_at":"2026-04-08T10:21:38.171Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","ci-cd","cross-platform","docker","ecommerce","eureka","eureka-server","gateway","java","kotlin","microservices","postgresql","react","redis","spring-boot","tailwindcss","typescript"],"created_at":"2024-12-14T04:16:48.965Z","updated_at":"2026-04-08T11:31:26.605Z","avatar_url":"https://github.com/lcaohoanq.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Shopee Clone Cross-Platform [Web, Mobile]\r\n\r\n## Preview\r\n\r\n![image](https://github.com/user-attachments/assets/4092d3d0-ca1b-49d0-8b09-dab0c9ab0e1e)\r\n\r\n![image](https://github.com/user-attachments/assets/8843fbc3-1375-46a6-b307-02ab6981d709)\r\n\r\n## Quick Start\r\n\r\n- Via Go\r\n\r\n```zsh\r\ncd scripts\r\n./start start\r\n```\r\n\r\n## Chức năng trong dự án\r\n\r\n- Authentication module: Quản lý bằng JWT\r\n\r\n  - Đăng ký\r\n  - Đăng nhập\r\n  - Đăng xuất\r\n\r\n- Trang danh sách sản phẩm:\r\n\r\n  - Có phân trang\r\n  - Sort (sắp xếp) theo từng thuộc tính sản phẩm\r\n  - filter nâng cao theo từng thuộc tính sản phẩm\r\n  - Tìm kiếm sản phẩm\r\n\r\n- Trang chi tiết sản phẩm:\r\n\r\n  - Hiển thị thông tin chi tiết\r\n  - Ảnh hiển thị theo slider + hover zoom effect\r\n  - Mô tả thì hiển thị rich text dạng WYSIWYG HTML\r\n  - Có chức năng mua hàng\r\n\r\n- Giỏ hàng\r\n\r\n  - Quản lý đơn hàng: Thêm, sửa, xóa sản phẩm\r\n  - Mua hàng\r\n\r\n- Quản lý Profile khách hàng\r\n\r\n  - Update thông tin cá nhân\r\n  - Upload Avatar\r\n  - Đổi mật khẩu\r\n  - Xem tình trạng đơn hàng\r\n\r\n## Công nghệ sử dụng\r\n\r\n- UI / CSS Library: Tailwindcss + HeadlessUI\r\n- State Management: React Query cho async state và React Context cho state thường\r\n- Form Management: React Hook Form\r\n- Router: React Router\r\n- Build tool: Vite\r\n- API: Rest API dựa trên server mình cung cấp sẵn\r\n- Hỗ trợ đa ngôn ngữ với react.i18next\r\n- Hỗ trợ SEO với React Helmet\r\n- Mô hình hóa các component với story book\r\n- Unit Test\r\n- Và còn nhiều thứ nữa khi làm chúng ta sẽ áp dụng...\r\n\r\n## Cài đặt package cho dự án Vite React TS\r\n\r\n### Cài các depedency\r\n\r\n### Bộ ESLint và Prettier trước\r\n\r\n\u003e Chúng ta sẽ cài hơi nhiều package 1 tí vì chúng ta setup từ đầu, còn Create React App setup sẵn 1 số thứ về ESLint rồi.\r\n\r\nDưới đây là những depedency mà chúng ta cần cài\r\n\r\n- ESLint: linter (bộ kiểm tra lỗi) chính\r\n\r\n- Prettier: code formatter chính\r\n\r\n- @typescript-eslint/eslint-plugin: ESLint plugin cung cấp các rule cho Typescript\r\n\r\n- @typescript-eslint/parser: Parser cho phép ESLint kiểm tra lỗi Typescript.\r\n\r\n- eslint-config-prettier: Bộ config ESLint để vô hiệu hóa các rule của ESLint mà xung đột với Prettier.\r\n\r\n- eslint-plugin-import: Để ESLint hiểu về cú pháp `import...` trong source code.\r\n\r\n- eslint-plugin-jsx-a11y: Kiểm tra các vấn đề liên quan đến accessiblity (Tính thân thiện website, ví dụ cho thiết bị máy đọc sách).\r\n\r\n- eslint-plugin-react: Các rule ESLint cho React\r\n\r\n- eslint-plugin-prettier: Dùng thêm 1 số rule Prettier cho ESLint\r\n\r\n- prettier-plugin-tailwindcss: Sắp xếp class tailwindcss\r\n\r\n- eslint-plugin-react-hooks: ESLint cho React hook\r\n\r\nChạy câu lệnh dưới đây\r\n\r\n```bash\r\nyarn add eslint prettier @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-prettier eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-prettier prettier-plugin-tailwindcss eslint-plugin-react-hooks -D\r\n```\r\n\r\nCấu hình ESLint\r\n\r\nTạo file `.eslintrc.cjs` tại thư mục root\r\n\r\n```js\r\n/* eslint-disable @typescript-eslint/no-var-requires */\r\nconst path = require('path')\r\n\r\nmodule.exports = {\r\n  extends: [\r\n    // Chúng ta sẽ dùng các rule mặc định từ các plugin mà chúng ta đã cài.\r\n    'eslint:recommended',\r\n    'plugin:react/recommended',\r\n    'plugin:react-hooks/recommended',\r\n    'plugin:import/recommended',\r\n    'plugin:import/typescript',\r\n    'plugin:jsx-a11y/recommended',\r\n    'plugin:@typescript-eslint/recommended',\r\n    // Disable các rule mà eslint xung đột với prettier.\r\n    // Để cái này ở dưới để nó override các rule phía trên!.\r\n    'eslint-config-prettier',\r\n    'prettier'\r\n  ],\r\n  plugins: ['prettier'],\r\n  settings: {\r\n    react: {\r\n      // Nói eslint-plugin-react tự động biết version của React.\r\n      version: 'detect'\r\n    },\r\n    // Nói ESLint cách xử lý các import\r\n    'import/resolver': {\r\n      node: {\r\n        paths: [path.resolve(__dirname, '')],\r\n        extensions: ['.js', '.jsx', '.ts', '.tsx']\r\n      }\r\n    }\r\n  },\r\n  env: {\r\n    node: true\r\n  },\r\n  rules: {\r\n    // Tắt rule yêu cầu import React trong file jsx\r\n    'react/react-in-jsx-scope': 'off',\r\n    // Cảnh báo khi thẻ \u003ca target='_blank'\u003e mà không có rel=\"noreferrer\"\r\n    'react/jsx-no-target-blank': 'warn',\r\n    // Tăng cường một số rule prettier (copy từ file .prettierrc qua)\r\n    'prettier/prettier': [\r\n      'warn',\r\n      {\r\n        arrowParens: 'always',\r\n        semi: false,\r\n        trailingComma: 'none',\r\n        tabWidth: 2,\r\n        endOfLine: 'auto',\r\n        useTabs: false,\r\n        singleQuote: true,\r\n        printWidth: 120,\r\n        jsxSingleQuote: true\r\n      }\r\n    ]\r\n  }\r\n}\r\n```\r\n\r\nTạo file `.eslintignore`\r\n\r\n```json\r\nnode_modules/\r\ndist/\r\n```\r\n\r\nTạo file `.prettierrc`\r\n\r\n```json\r\n{\r\n  \"arrowParens\": \"always\",\r\n  \"semi\": false,\r\n  \"trailingComma\": \"none\",\r\n  \"tabWidth\": 2,\r\n  \"endOfLine\": \"auto\",\r\n  \"useTabs\": false,\r\n  \"singleQuote\": true,\r\n  \"printWidth\": 120,\r\n  \"jsxSingleQuote\": true\r\n}\r\n```\r\n\r\nTạo file `.prettierignore`\r\n\r\n```json\r\nnode_modules/\r\ndist/\r\n```\r\n\r\nThêm script mới vào `package.json`\r\n\r\n```json\r\n  \"scripts\": {\r\n    ...\r\n    \"lint\": \"eslint --ext ts,tsx src/\",\r\n    \"lint:fix\": \"eslint --fix --ext ts,tsx src/\",\r\n    \"prettier\": \"prettier --check \\\"src/**/(*.tsx|*.ts|*.css|*.scss)\\\"\",\r\n    \"prettier:fix\": \"prettier --write \\\"src/**/(*.tsx|*.ts|*.css|*.scss)\\\"\"\r\n  },\r\n```\r\n\r\n### Cài editorconfig\r\n\r\nTạo file `.editorconfig` ở thư mục root\r\n\r\n```EditorConfig\r\n[*]\r\nindent_size = 2\r\nindent_style = space\r\n```\r\n\r\n### Cấu hình tsconfig.json\r\n\r\nSet `\"target\": \"ES2015\"` và `\"baseUrl\": \".\"` trong `compilerOptions`\r\n\r\n### Cài tailwindcss\r\n\r\nCài các package dưới đây: Tham khảo [https://tailwindcss.com/docs/guides/vite](https://tailwindcss.com/docs/guides/vite)\r\n\r\n```bash\r\nyarn add -D tailwindcss postcss autoprefixer\r\nnpx tailwindcss init -p\r\n```\r\n\r\nCấu hình file config\r\n\r\n```js\r\n/** @type {import('tailwindcss').Config} */\r\nmodule.exports = {\r\n  content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],\r\n  theme: {\r\n    extend: {}\r\n  },\r\n  plugins: []\r\n}\r\n```\r\n\r\nThêm vào file `src/index.css`\r\n\r\n```css\r\n@tailwind base;\r\n@tailwind components;\r\n@tailwind utilities;\r\n```\r\n\r\n### Cấu hình vite config\r\n\r\nCài package `@types/node` để sử dụng node js trong file ts không bị lỗi\r\n\r\n```bash\r\nyarn add -D @types/node\r\n```\r\n\r\nfile `vite.config.ts`\r\n\r\n```ts\r\nimport { defineConfig } from 'vite'\r\nimport react from '@vitejs/plugin-react'\r\nimport path from 'path'\r\n\r\n// https://vitejs.dev/config/\r\nexport default defineConfig({\r\n  plugins: [react()],\r\n  server: {\r\n    port: 3000\r\n  },\r\n  css: {\r\n    devSourcemap: true\r\n  },\r\n  resolve: {\r\n    alias: {\r\n      src: path.resolve(__dirname, './src')\r\n    }\r\n  }\r\n})\r\n```\r\n\r\n### Cài extension và setup VS Code\r\n\r\nCác Extension nên cài\r\n\r\n- ESLint\r\n\r\n- Prettier - Code formatter\r\n\r\n- Tailwindcss\r\n\r\n- EditorConfig for VS Code\r\n\r\nCấu hình VS Code\r\n\r\n- Bật Format On Save\r\n- Chọn Default Formatter là Prettier\r\n\r\n\u003e Có 3 môi trường khi làm việc\r\n\u003e\r\n\u003e 1. Môi trường VS Code, khi chúng ta đưa chuột vào click thì chạy đến đúng file\r\n\u003e 2. Môi trường ES Lint\r\n\u003e 3. Môi trường Terminal\\*\r\n\r\n## Ghi chú code\r\n\r\nCode xóa các ký tự đặc biệt trên bàn phím\r\n\r\n```ts\r\nexport const removeSpecialCharacter = (str: string) =\u003e\r\n  // eslint-disable-next-line no-useless-escape\r\n  str.replace(\r\n    /!|@|%|\\^|\\*|\\(|\\)|\\+|\\=|\\\u003c|\\\u003e|\\?|\\/|,|\\.|\\:|\\;|\\'|\\\"|\\\u0026|\\#|\\[|\\]|~|\\$|_|`|-|{|}|\\||\\\\/g,\r\n    ''\r\n  )\r\n```\r\n\r\nSữa lỗi Tailwindcss Extension không gợi ý class\r\n\r\nCác bạn thêm đoạn code này vào `settings.json` của VS Code\r\n\r\n```json\r\n{\r\n  //...\r\n  \"tailwindCSS.experimental.classRegex\": [\"[a-zA-Z]*class[a-zA-Z]*='([^']+)'\"]\r\n}\r\n```\r\n\r\n# Error Handling Flow\r\n\r\n```\r\nRequest Flow:\r\n\r\n1. JwtTokenFilter (Authentication)\r\n   ├── No token/Invalid token -\u003e AuthenticationEntryPoint (401)\r\n   └── Valid token -\u003e Continue\r\n\r\n2. Security Filter (Authorization)\r\n   ├── Insufficient role -\u003e AccessDeniedHandler (403)\r\n   └── Sufficient role -\u003e Continue to Controller\r\n\r\n```\r\n\r\n- Example scenario\r\n```java\r\n// Scenario 1: Public endpoint (no JWT needed)\r\n@GetMapping(\"/api/v1/public\")\r\npublic ResponseEntity\u003c?\u003e publicEndpoint() {\r\n// No security checks needed\r\nreturn ResponseEntity.ok(\"Public data\");\r\n}\r\n\r\n// Scenario 2: Protected endpoint (JWT required, any role)\r\n@GetMapping(\"/api/v1/protected\")\r\n@PreAuthorize(\"isAuthenticated()\")  // Just needs valid JWT\r\npublic ResponseEntity\u003c?\u003e protectedEndpoint() {\r\n// User must have valid JWT\r\nreturn ResponseEntity.ok(\"Protected data\");\r\n}\r\n\r\n// Scenario 3: Role-specific endpoint (JWT + specific role required)\r\n@GetMapping(\"/api/v1/admin\")\r\n@PreAuthorize(\"hasRole('MANAGER')\")  // Needs JWT + MANAGER role\r\npublic ResponseEntity\u003c?\u003e adminEndpoint() {\r\n// User must have valid JWT and MANAGER role\r\nreturn ResponseEntity.ok(\"Admin data\");\r\n}\r\n```\r\n- Request Flow\r\n-\r\n```txt\r\n\r\nGET /roles/1 (no token)\r\n↓\r\nJwtTokenFilter (no token found)\r\n↓\r\nAuthenticationEntryPoint (returns 401 Unauthorized)\r\n\r\nGET /roles/1 (invalid token)\r\n↓\r\nJwtTokenFilter (invalid token)\r\n↓\r\nAuthenticationEntryPoint (returns 401 Unauthorized)\r\n\r\nGET /roles/1 (valid token, wrong role)\r\n↓\r\nJwtTokenFilter (valid token)\r\n↓\r\n@PreAuthorize check fails\r\n↓\r\nAccessDeniedHandler (returns 403 Forbidden)\r\n\r\n```\r\n\r\n# Service Discovery\r\n- Eureka là một service discovery server, cho phép các microservices đăng ký và tìm kiếm nhau.\r\n- Spring Cloud Netflix Eureka là một thư viện giúp tích hợp Eureka vào ứng dụng Spring Boot.\r\n- Eureka Server là nơi các microservices đăng ký và tìm kiếm nhau.\r\n\r\n# Spring Cloud Gateway\r\n- Spring Cloud Gateway là một API Gateway cho phép định tuyến và xử lý các yêu cầu đến các microservices.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flcaohoanq%2Fshoppe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flcaohoanq%2Fshoppe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flcaohoanq%2Fshoppe/lists"}