Files
aars/SPEC.md
T

378 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 + passwordJWT 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