Initial commit: AARS backend + frontend + holiday/leave phase 1+2
This commit is contained in:
@@ -0,0 +1,377 @@
|
||||
# AARS - Attendance & Accident Record System
|
||||
|
||||
## 1. Concept & Vision
|
||||
|
||||
一個為中小企設計嘅出勤同意外記錄系統。介面乾淨、專業、易用,帶有香港本地特色(繁體中文、HKT時區)。兩大一頁式 dashboard,展示即時數據,所有記錄都可以 filter、sort、export。
|
||||
|
||||
目標係取代 Excel 試算表,做一個可以多人協作、數據唔會重複、report 一click 生成嘅系統。
|
||||
|
||||
---
|
||||
|
||||
## 2. Design Language
|
||||
|
||||
**Aesthetic:** 淺色專業商務風,白底配淺灰,帶有 System Blue 強調色。似 classic Notion / Linear 嗰種乾淨感覺,但再 warm 少少。
|
||||
|
||||
**Colors (TailwindCSS custom):**
|
||||
- Primary: `#2563EB` (blue-600)
|
||||
- Primary Dark: `#1D4ED8` (blue-700)
|
||||
- Accent: `#06B6D4` (cyan-500)
|
||||
- Background: `#F8FAFC` (slate-50)
|
||||
- Card: `#FFFFFF`
|
||||
- Border: `#E2E8F0` (slate-200)
|
||||
- Text Primary: `#0F172A` (slate-900)
|
||||
- Text Secondary: `#64748B` (slate-500)
|
||||
- Success: `#10B981` (emerald-500)
|
||||
- Warning: `#F59E0B` (amber-500)
|
||||
- Danger: `#EF4444` (red-500)
|
||||
|
||||
**Typography:**
|
||||
- Font: Inter (Google Fonts) + Noto Sans TC (繁體中文)
|
||||
- Headings: 600-700 weight
|
||||
- Body: 400-500 weight
|
||||
|
||||
**Spatial System:**
|
||||
- Base unit: 4px
|
||||
- Card padding: 24px
|
||||
- Section gap: 32px
|
||||
- Border radius: 8px (cards), 6px (buttons), 4px (inputs)
|
||||
|
||||
**Motion:**
|
||||
- Page transitions: fade 150ms
|
||||
- Hover states: 200ms ease
|
||||
- Loading: pulse animation
|
||||
- No bouncy/playful animations - keep it professional
|
||||
|
||||
---
|
||||
|
||||
## 3. Layout & Structure
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ Header: Logo + Nav (Attendance | Accident) + User │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ Page Content: │
|
||||
│ ┌─ Dashboard ─┐ ┌─ List View ─┐ ┌─ Detail ─┐ │
|
||||
│ │ Stats cards │ │ Table + Fn │ │ Edit form│ │
|
||||
│ │ Charts │ │ Filter/Sort │ │ History │ │
|
||||
│ └────────────┘ └─────────────┘ └─────────┘ │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Pages:**
|
||||
1. **Login** (`/login`) - Email + password,JWT auth
|
||||
2. **Dashboard** (`/`) - Stats cards + recent activity + quick actions
|
||||
3. **Attendance List** (`/attendance`) - Table with all records
|
||||
4. **Attendance Detail** (`/attendance/:id`) - View/Edit single record
|
||||
5. **Accident List** (`/accident`) - Table with all records
|
||||
6. **Accident Detail** (`/accident/:id`) - View/Edit single record
|
||||
7. **Import** (`/import`) - Excel upload + mapping + preview
|
||||
|
||||
**Responsive:** Desktop-first,但 table 可以 horizontal scroll 喺 mobile
|
||||
|
||||
---
|
||||
|
||||
## 4. Features & Interactions
|
||||
|
||||
### 4.1 Authentication
|
||||
- Login with email + password
|
||||
- JWT token stored in localStorage
|
||||
- Token expiry: 24 hours
|
||||
- Auto-redirect to login if expired
|
||||
|
||||
### 4.2 Dashboard
|
||||
**Attendance Section:**
|
||||
- Total records count
|
||||
- Today attendance count
|
||||
- This month attendance count
|
||||
- Records trend chart (last 7 days / 30 days)
|
||||
|
||||
**Accident Section:**
|
||||
- Total records count
|
||||
- This month accidents count
|
||||
- Unresolved accidents count
|
||||
- Recent accidents list (last 5)
|
||||
|
||||
### 4.3 List View
|
||||
- Paginated table (20 per page)
|
||||
- Columns: ID, Date, Employee Name, Department, Status, Actions
|
||||
- **Filter:** By date range, department, status, search text
|
||||
- **Sort:** Click column header to sort ASC/DESC
|
||||
- **Actions:** View, Edit, Delete (soft delete)
|
||||
- **Bulk Actions:** Select multiple → Delete / Export selected
|
||||
- **Export:** PDF (single/all selected) / Excel (all filtered results)
|
||||
|
||||
### 4.4 Detail / Edit View
|
||||
- Form with all fields
|
||||
- Read-only view mode vs Edit mode
|
||||
- **History tab:** Show who created/modified when
|
||||
- **Save:** Validates + saves to SQLite
|
||||
- **Cancel:** Returns to list without saving
|
||||
|
||||
### 4.5 Excel Import
|
||||
- Upload Excel file (.xlsx, .xls)
|
||||
- Auto-detect columns from first row
|
||||
- **Field mapping:** Map Excel columns to system fields
|
||||
- **Duplicate detection:** Check by unique key (Employee ID + Date for attendance, Date + Location for accident)
|
||||
- **Preview:** Show first 10 rows with validation status
|
||||
- **Options:**
|
||||
- "Update existing" → skip duplicates or update
|
||||
- "Create new only" → skip duplicates
|
||||
- **Import button:** Bulk insert/update
|
||||
- **Result:** Show success count, skipped (duplicates), errors
|
||||
|
||||
### 4.6 Field Management
|
||||
- Default fields per section (pre-defined)
|
||||
- **Add custom field:** Name, type (text/number/date/select), required
|
||||
- Custom fields stored in JSON column
|
||||
- Can be used in list view, detail view, export
|
||||
|
||||
### 4.7 Export
|
||||
- **Excel:** All filtered results, includes all fields
|
||||
- **PDF:** Formatted report with header, table, pagination
|
||||
- Export respects current filter/sort state
|
||||
|
||||
---
|
||||
|
||||
## 5. Component Inventory
|
||||
|
||||
### 5.1 Header
|
||||
- Logo (left): "AARS" text logo
|
||||
- Nav tabs (center): "出勤 Attendance" | "意外 Accident"
|
||||
- Active tab: blue underline
|
||||
- User menu (right): Username + dropdown (Profile, Logout)
|
||||
|
||||
### 5.2 Stats Card
|
||||
- Icon (colored circle bg) + metric value (large) + label (small)
|
||||
- Hover: subtle shadow lift
|
||||
|
||||
### 5.3 Data Table
|
||||
- Header row: grey bg, bold text
|
||||
- Sortable columns: sort icon, click to toggle
|
||||
- Row hover: light blue bg
|
||||
- Checkbox column for bulk select
|
||||
- Action buttons: View (blue), Edit (gray), Delete (red)
|
||||
- Empty state: "No records found" + illustration
|
||||
|
||||
### 5.4 Filter Bar
|
||||
- Date range picker (two inputs)
|
||||
- Dropdown for department/status
|
||||
- Text search input
|
||||
- "Clear filters" button
|
||||
- "Export" button
|
||||
|
||||
### 5.5 Form
|
||||
- Label + input pairs, stacked
|
||||
- Required indicator: red asterisk
|
||||
- Input states: default, focus (blue ring), error (red border + message)
|
||||
- Select dropdowns, date pickers
|
||||
- Submit button (blue), Cancel button (gray outline)
|
||||
|
||||
### 5.6 Modal
|
||||
- Centered overlay, white card
|
||||
- Header + body + footer
|
||||
- Close X button top right
|
||||
- Backdrop click to close
|
||||
|
||||
### 5.7 Toast Notifications
|
||||
- Success (green), Error (red), Info (blue)
|
||||
- Auto-dismiss after 3s
|
||||
- Bottom right corner
|
||||
|
||||
### 5.8 Import Wizard
|
||||
- Step 1: Upload Excel
|
||||
- Step 2: Map columns
|
||||
- Step 3: Preview + validate
|
||||
- Step 4: Confirm + import
|
||||
- Progress indicator at top
|
||||
|
||||
---
|
||||
|
||||
## 6. Technical Approach
|
||||
|
||||
### 6.1 Backend (FastAPI)
|
||||
```
|
||||
backend/
|
||||
├── main.py # FastAPI app entry
|
||||
├── database.py # SQLite + SQLAlchemy
|
||||
├── models.py # SQLAlchemy models
|
||||
├── schemas.py # Pydantic schemas
|
||||
├── auth.py # JWT auth
|
||||
├── routers/
|
||||
│ ├── attendance.py
|
||||
│ ├── accident.py
|
||||
│ ├── import.py
|
||||
│ └── export.py
|
||||
└── utils/
|
||||
├── excel.py # openpyxl helpers
|
||||
└── pdf.py # reportlab helpers
|
||||
```
|
||||
|
||||
**API Endpoints:**
|
||||
```
|
||||
POST /api/auth/login
|
||||
GET /api/auth/me
|
||||
|
||||
GET /api/attendance # List with filter/sort/paginate
|
||||
POST /api/attendance # Create
|
||||
GET /api/attendance/:id # Get one
|
||||
PUT /api/attendance/:id # Update
|
||||
DELETE /api/attendance/:id # Soft delete
|
||||
|
||||
GET /api/accident # List with filter/sort/paginate
|
||||
POST /api/accident # Create
|
||||
GET /api/accident/:id # Get one
|
||||
PUT /api/accident/:id # Update
|
||||
DELETE /api/accident/:id # Soft delete
|
||||
|
||||
POST /api/import/attendance # Excel import
|
||||
POST /api/import/accident # Excel import
|
||||
|
||||
GET /api/export/attendance/excel
|
||||
GET /api/export/attendance/pdf
|
||||
GET /api/export/accident/excel
|
||||
GET //api/export/accident/pdf
|
||||
|
||||
GET /api/dashboard/attendance # Stats
|
||||
GET /api/dashboard/accident # Stats
|
||||
|
||||
GET /api/fields/attendance # Custom fields
|
||||
POST /api/fields/attendance
|
||||
GET /api/fields/accident
|
||||
POST /api/fields/accident
|
||||
```
|
||||
|
||||
### 6.2 Database Schema
|
||||
|
||||
**Users:**
|
||||
```sql
|
||||
id, email, password_hash, name, role, created_at, updated_at, is_active
|
||||
```
|
||||
|
||||
**Attendance:**
|
||||
```sql
|
||||
id, employee_id, employee_name, department, date, check_in, check_out,
|
||||
overtime_hours, leave_type, leave_hours, status, remarks,
|
||||
custom_fields (JSON), created_by, created_at, updated_at, deleted_at
|
||||
```
|
||||
|
||||
**Accident:**
|
||||
```sql
|
||||
id, date, time, location, employee_name, employee_id, department,
|
||||
description, severity, medical_report, action_taken, responsible_person,
|
||||
custom_fields (JSON), created_by, created_at, updated_at, deleted_at
|
||||
```
|
||||
|
||||
**AttendanceCustomFields / AccidentCustomFields:**
|
||||
```sql
|
||||
id, field_name, field_type, required, options, order, created_at
|
||||
```
|
||||
|
||||
### 6.3 Frontend (React + Vite)
|
||||
```
|
||||
frontend/
|
||||
├── src/
|
||||
│ ├── App.jsx
|
||||
│ ├── main.jsx
|
||||
│ ├── api.js # Axios API calls
|
||||
│ ├── context/
|
||||
│ │ └── AuthContext.jsx
|
||||
│ ├── pages/
|
||||
│ │ ├── Login.jsx
|
||||
│ │ ├── Dashboard.jsx
|
||||
│ │ ├── attendance/
|
||||
│ │ │ ├── List.jsx
|
||||
│ │ │ └── Detail.jsx
|
||||
│ │ ├── accident/
|
||||
│ │ │ ├── List.jsx
|
||||
│ │ │ └── Detail.jsx
|
||||
│ │ └── import/
|
||||
│ │ └── Import.jsx
|
||||
│ └── components/
|
||||
│ ├── Layout.jsx
|
||||
│ ├── DataTable.jsx
|
||||
│ ├── FilterBar.jsx
|
||||
│ ├── StatsCard.jsx
|
||||
│ ├── Modal.jsx
|
||||
│ └── Toast.jsx
|
||||
├── index.html
|
||||
├── tailwind.config.js
|
||||
└── vite.config.js
|
||||
```
|
||||
|
||||
### 6.4 Docker Setup
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
aars:
|
||||
build: .
|
||||
ports:
|
||||
- "18775:8000"
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
environment:
|
||||
- TIMEZONE=Asia/Hong_Kong
|
||||
- SECRET_KEY=<generated>
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
### 6.5 Key Libraries
|
||||
- **Backend:** fastapi, uvicorn, sqlalchemy, pydantic, python-jose, passlib, openpyxl, reportlab
|
||||
- **Frontend:** react, react-router-dom, axios, tailwindcss, recharts (charts), react-hot-toast
|
||||
|
||||
---
|
||||
|
||||
## 7. Default Fields
|
||||
|
||||
### Attendance Default Fields
|
||||
| Field | Type | Required |
|
||||
|-------|------|----------|
|
||||
| employee_id | text | Yes |
|
||||
| employee_name | text | Yes |
|
||||
| department | select | Yes |
|
||||
| date | date | Yes |
|
||||
| check_in | time | No |
|
||||
| check_out | time | No |
|
||||
| overtime_hours | number | No |
|
||||
| leave_type | select | No |
|
||||
| leave_hours | number | No |
|
||||
| status | select | Yes |
|
||||
| remarks | text | No |
|
||||
|
||||
### Accident Default Fields
|
||||
| Field | Type | Required |
|
||||
|-------|------|----------|
|
||||
| date | date | Yes |
|
||||
| time | time | Yes |
|
||||
| location | text | Yes |
|
||||
| employee_name | text | Yes |
|
||||
| employee_id | text | Yes |
|
||||
| department | select | Yes |
|
||||
| description | text | Yes |
|
||||
| severity | select | Yes |
|
||||
| medical_report | text | No |
|
||||
| action_taken | text | No |
|
||||
| responsible_person | text | No |
|
||||
|
||||
---
|
||||
|
||||
## 8. Security
|
||||
|
||||
- Passwords hashed with bcrypt
|
||||
- JWT with 24h expiry
|
||||
- CORS configured for known origins only
|
||||
- Input sanitization on all endpoints
|
||||
- Soft delete (never hard delete user data)
|
||||
- Rate limiting on login endpoint
|
||||
|
||||
---
|
||||
|
||||
## 9. Out of Scope (v1)
|
||||
|
||||
- User management (create/edit users) - only admin can do this via direct DB
|
||||
- Multi-company support
|
||||
- Recurring attendance (scheduled check-in reminders)
|
||||
- Document/photo upload for accidents
|
||||
- Email notifications
|
||||
- Mobile responsive redesign
|
||||
- API for third-party integrations
|
||||
Reference in New Issue
Block a user