Files
aars/SPEC.md
T

11 KiB
Raw Blame History

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:

id, email, password_hash, name, role, created_at, updated_at, is_active

Attendance:

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:

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:

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

# 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