diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..b7fa6fe --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,22 @@ +## 📝 Description + + +## 🔗 Related Issue + +Closes # + +## 🎯 Type of Change +- [ ] 🐛 Bug fix +- [ ] ✨ New feature +- [ ] 🔨 Refactoring +- [ ] 📦 library update +- [ ] 📝 Documentation +- [ ] 🎨 UI/UX + +## ✅ Checklist +- [ ] Code đã được test locally +- [ ] Không có lỗi lint +- [ ] Đã cập nhật documentation (nếu cần) + +## 📸 Screenshots (nếu có) + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9baefbb --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,81 @@ +name: CI + +on: + push: + branches: [main, dev] + pull_request: + branches: [main, dev] + +jobs: + lint-and-typecheck: + name: Lint & Type Check + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run ESLint + run: npm run lint + + - name: Type check + run: npm run type-check + + test: + name: Test + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run tests + run: npm test + + build: + name: Build + runs-on: ubuntu-latest + needs: [lint-and-typecheck, test] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build application + run: npm run build + env: + NODE_ENV: production + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: build-output + path: .next + retention-days: 7 diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..2dd5681 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +fund=false +audit=false \ No newline at end of file diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..b087cc9 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +22.13.0 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a619a9e --- /dev/null +++ b/README.md @@ -0,0 +1,296 @@ +
+ +# 🚀 NextApp + +### Nền tảng web hiện đại được xây dựng với Next.js 16 & React 19 + +[![Next.js](https://img.shields.io/badge/Next.js-16.1-black?style=for-the-badge&logo=next.js)](https://nextjs.org/) +[![React](https://img.shields.io/badge/React-19.2-61dafb?style=for-the-badge&logo=react)](https://react.dev/) +[![TypeScript](https://img.shields.io/badge/TypeScript-5.0-3178c6?style=for-the-badge&logo=typescript)](https://www.typescriptlang.org/) +[![Tailwind CSS](https://img.shields.io/badge/Tailwind-4.0-38bdf8?style=for-the-badge&logo=tailwind-css)](https://tailwindcss.com/) +[![CI](https://img.shields.io/github/actions/workflow/status/YOUR_USERNAME/YOUR_REPO/ci.yml?branch=main&style=for-the-badge&label=CI)](https://github.com/YOUR_USERNAME/YOUR_REPO/actions) + +[Demo](https://your-demo.vercel.app) • [Tài liệu](./PROJECT_STRUCTURE.md) • [Docker](./DOCKER.md) + +
+ +--- + +## ✨ Tính năng + +- ⚡ **Next.js 16** - App Router, Server Components, Server Actions +- ⚛️ **React 19** - Hooks mới nhất, Form Actions, Optimistic Updates +- 🎨 **Tailwind CSS 4** - Utility-first CSS framework +- 📘 **TypeScript** - Type safety với strict mode +- 🐳 **Docker** - Production-ready containerization +- 🎯 **ESLint** - Code quality và consistency +- 🚀 **Vercel** - Deploy tự động với zero config + +## 🛠️ Tech Stack + +### Core +- **Framework:** Next.js 16.1.6 +- **UI Library:** React 19.2.3 +- **Language:** TypeScript 5.x +- **Styling:** Tailwind CSS 4.x + +### Utilities +- **Class Merging:** clsx + tailwind-merge +- **Font Optimization:** next/font (Geist Sans & Mono) +- **Image Optimization:** next/image + +### Development +- **Linting:** ESLint 9.x + eslint-config-next +- **Type Checking:** TypeScript strict mode +- **Package Manager:** npm + +### Deployment +- **Containerization:** Docker + Docker Compose +- **Platform:** Vercel / AWS / GCP / DigitalOcean + +## 📁 Cấu trúc dự án + +``` +src/ +├── app/ # App Router - Routes & Layouts +│ ├── layout.tsx # Root layout với metadata +│ ├── page.tsx # Homepage +│ ├── loading.tsx # Loading UI (Suspense) +│ ├── error.tsx # Error boundary +│ ├── not-found.tsx # 404 page +│ └── globals.css # Global styles +│ +├── components/ # React Components +│ ├── ui/ # Base UI components (Button, Input...) +│ └── features/ # Feature-specific components +│ +├── lib/ # Utilities & Configurations +│ ├── utils.ts # Helper functions (cn, formatDate...) +│ ├── fonts.ts # Font configurations +│ └── env.ts # Environment validation +│ +├── types/ # TypeScript Types & Interfaces +├── hooks/ # Custom React Hooks +├── actions/ # Server Actions +└── constants/ # App-wide constants +``` + +> 📖 Xem chi tiết: [PROJECT_STRUCTURE.md](./PROJECT_STRUCTURE.md) + +## 🚀 Bắt đầu + +### Yêu cầu + +- Node.js 22.13.0+ (hoặc 22.x LTS) +- npm 10.0.0+ + +> 💡 Project sử dụng `.nvmrc` để lock Node.js version. Nếu dùng nvm, chạy `nvm use` để tự động switch. + +### Cài đặt + +```bash +# Clone repository +git clone +cd next + +# Cài đặt dependencies (đảm bảo dùng Node.js 22.13.0+) +npm install + +# Copy environment variables +cp .env.local.example .env.local + +# Chạy development server +npm run dev +``` + +Mở [http://localhost:3000](http://localhost:3000) để xem kết quả. + +### Version Management + +Project sử dụng các file sau để đảm bảo consistency giữa các môi trường: + +- `.nvmrc` - Lock Node.js version (22.13.0) +- `.npmrc` - Cấu hình npm (engine-strict, save-exact) +- `package.json` engines - Enforce Node >=22.13.0 <23.0.0 + +```bash +# Sử dụng nvm (recommended) +nvm use + +# Hoặc kiểm tra version thủ công +node --version # Phải >= 22.13.0 và < 23.0.0 +``` + +### Scripts + +```bash +npm run dev # Chạy development server +npm run build # Build production +npm run start # Chạy production server +npm run lint # Chạy ESLint +npm run type-check # Type checking +npm test # Chạy tests +``` + +## 🔄 CI/CD + +Project sử dụng GitHub Actions để tự động test và build: + +### CI Pipeline +1. **Lint & Type Check** - ESLint + TypeScript validation +2. **Test** - Run test suite +3. **Build** - Production build verification + +Pipeline chạy tự động khi: +- Push lên `main` hoặc `develop` +- Tạo Pull Request vào `main` hoặc `develop` + +### Local CI Check +```bash +# Chạy tất cả checks như CI +npm run lint && npm run type-check && npm test && npm run build +``` + +## 📝 Quy tắc code + +### TypeScript +- ✅ Strict mode - Không dùng `any` +- ✅ Explicit return types cho functions +- ✅ Interface cho objects, Type cho unions + +### React +- ✅ Server Components by default +- ✅ `'use client'` chỉ khi cần thiết +- ✅ Components < 150 lines +- ✅ Semantic HTML & Accessibility + +### Styling +- ✅ Tailwind CSS utility classes +- ✅ `cn()` utility cho conditional classes +- ✅ Mobile-first responsive design + +### Code Quality +- ✅ Self-documenting code +- ✅ Early returns để giảm nesting +- ✅ Extract magic numbers thành constants + +## 🏗️ Kiến trúc + +### Server Components First +Mặc định sử dụng React Server Components để tối ưu performance. Chỉ thêm `'use client'` khi cần: +- Browser APIs (window, localStorage) +- Event handlers +- React hooks (useState, useEffect...) + +### Server Actions +Sử dụng Server Actions cho mutations thay vì API routes: +```typescript +// actions/user.ts +'use server'; + +export async function createUser(data: FormData) { + // Server-side logic +} +``` + +### Type Safety +Result pattern cho error handling: +```typescript +type Result = + | { success: true; data: T } + | { success: false; error: Error }; +``` + +## 🎨 UI Components + +### Button Component +```tsx +import { Button } from '@/components/ui'; + + +``` + +### Variants +- `primary` - Blue gradient +- `secondary` - Gray +- `outline` - Border only + +## 🌍 Environment Variables + +```bash +# .env.local +NEXT_PUBLIC_APP_URL=http://localhost:3000 +``` + +> ⚠️ Không commit file `.env.local` vào git + +## 📦 Deployment + +### Vercel (Recommended) +```bash +# Install Vercel CLI +npm i -g vercel + +# Deploy +vercel +``` + +### Docker +```bash +# Build production image +docker build -t nextapp . + +# Run container +docker run -p 3000:3000 nextapp +``` + +### Manual +```bash +# Build +npm run build + +# Start +npm start +``` + +## 🤝 Contributing + +1. Fork repository +2. Tạo branch mới (`git checkout -b feature/amazing-feature`) +3. Commit changes (`git commit -m 'feat: add amazing feature'`) +4. Push to branch (`git push origin feature/amazing-feature`) +5. Mở Pull Request + +### Commit Convention +``` +feat: thêm tính năng mới +fix: sửa bug +docs: cập nhật documentation +style: format code +refactor: refactor code +test: thêm tests +chore: cập nhật dependencies +``` + +## 📄 License + +MIT License - xem [LICENSE](./LICENSE) để biết thêm chi tiết. + +## 🙏 Acknowledgments + +- [Next.js](https://nextjs.org/) - The React Framework +- [Vercel](https://vercel.com/) - Deployment platform +- [Tailwind CSS](https://tailwindcss.com/) - CSS framework +- [Unsplash](https://unsplash.com/) - Free images + +--- + +
+ +**[⬆ Về đầu trang](#-nextapp)** + +Made with ❤️ by Your Team + +
diff --git a/package.json b/package.json index 0153ff9..dd41438 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,17 @@ "name": "next", "version": "0.1.0", "private": true, + "engines": { + "node": ">=22.13.0 <23.0.0", + "npm": ">=10.0.0" + }, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", - "lint": "eslint" + "lint": "eslint", + "type-check": "tsc --noEmit", + "test": "echo \"No tests yet\" && exit 0" }, "dependencies": { "clsx": "^2.1.1", diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx new file mode 100644 index 0000000..262b6ed --- /dev/null +++ b/src/components/ui/button.tsx @@ -0,0 +1,38 @@ +import { type ButtonHTMLAttributes, forwardRef } from 'react'; +import { cn } from '@/lib/utils'; + +interface ButtonProps extends ButtonHTMLAttributes { + variant?: 'primary' | 'secondary' | 'outline'; + size?: 'sm' | 'md' | 'lg'; +} + +const Button = forwardRef( + ({ className, variant = 'primary', size = 'md', ...props }, ref) => { + return ( +