This commit is contained in:
2026-02-06 17:13:17 +00:00
parent 2bdba1581d
commit 5a8ec67a68
5 changed files with 6236 additions and 0 deletions

120
README.md Normal file
View File

@@ -0,0 +1,120 @@
# Inventory Frontend Service
Minimal React frontend for inventory management. Focus: **DevOps/CI-CD demo**, not UI complexity.
## Features (Minimal by Design)
- Display items in simple table
- Add new item form (name, quantity, price)
- Basic error handling
- That's it! No edit, delete, pagination, or filters
## Tech Stack
- React 19 + Vite
- Axios for API calls
- Basic CSS (no framework)
- Nginx for production serving
## Local Development
### Prerequisites
- Node.js 20+
- Backend service running at http://localhost:3000
### Quick Start
```bash
# 1. Install dependencies
npm install
# 2. Create .env file
cp .env.example .env
# 3. Start development server
npm run dev
# Frontend runs on http://localhost:5173
```
### Testing
```bash
# Run tests
npm test
# Run linter
npm run lint
# Build for production
npm run build
```
## Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| VITE_API_URL | http://localhost:3000 | Backend API URL |
## Docker Build
```bash
# Build image
docker build -t frontend-service:latest .
# Run container
docker run -d -p 80:80 frontend-service:latest
```
## CI/CD Pipeline
Gitea Actions workflow:
1. Checkout → Install → Lint → Test → Build
2. SonarQube scan + quality gate
3. Build multi-stage Docker image (React build + nginx)
4. Push to Gitea registry with tags: `{branch}-{sha}`, `{branch}`, `latest`
5. Update k8s-manifests repo
## Component Structure
Single component (`App.jsx`) with:
- Items list table
- Add item form
- Loading/error states
- API integration via axios
**~80 lines total** - intentionally minimal!
## Project Structure
```
frontend-service/
├── src/
│ ├── App.jsx # Single component (~80 lines)
│ ├── api.js # Axios API calls (~15 lines)
│ ├── App.css # Basic styling
│ └── main.jsx # Entry point
├── tests/
│ └── App.test.jsx # Basic component tests
├── .gitea/workflows/
│ └── ci.yaml # CI/CD pipeline
├── Dockerfile # Multi-stage build
├── nginx.conf # Production web server config
├── package.json
└── README.md
```
**Total: ~8 files** - focus on DevOps, not application!
## Production Deployment
Built as static files served by nginx:
- React app compiled to `/usr/share/nginx/html`
- Non-root nginx user (nginx-app:1001)
- Security headers enabled
- Gzip compression
- Asset caching with cache-busting
- SPA routing support
## API Integration
Frontend calls backend endpoints:
- `GET /api/items` - Fetch all items
- `POST /api/items` - Create new item
Backend URL configured via `VITE_API_URL` environment variable.

6061
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

34
package.json Normal file
View File

@@ -0,0 +1,34 @@
{
"name": "frontend-service",
"private": true,
"version": "1.0.0",
"type": "module",
"description": "Minimal inventory management frontend for DevOps demo",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview",
"test": "vitest"
},
"dependencies": {
"react": "^19.2.0",
"react-dom": "^19.2.0",
"axios": "^1.6.2"
},
"devDependencies": {
"@eslint/js": "^9.39.1",
"@types/react": "^19.2.5",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.1",
"eslint": "^9.39.1",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.4.24",
"globals": "^16.5.0",
"vite": "^7.2.4",
"vitest": "^1.0.4",
"@testing-library/react": "^14.1.2",
"@testing-library/jest-dom": "^6.1.5",
"jsdom": "^23.0.1"
}
}

14
sonar-project.properties Normal file
View File

@@ -0,0 +1,14 @@
sonar.projectKey=inventory-frontend
sonar.projectName=Inventory Frontend Service
sonar.projectVersion=1.0
# Source and test paths
sonar.sources=src
sonar.tests=tests
sonar.javascript.lcov.reportPaths=coverage/lcov.info
# Exclusions
sonar.exclusions=node_modules/**,dist/**,coverage/**,tests/**,**/*.test.jsx
# Quality gate
sonar.qualitygate.wait=true

7
vite.config.js Normal file
View File

@@ -0,0 +1,7 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
})