mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-05-20 05:10:26 -05:00
6c8e86cd01
Timer starts always blocked a second running entry and never read the\nadmin-controlled Settings flag.\n\n- Add TimeTrackingService.can_start_timer() using Settings.get_settings()\n and wire it into start_timer, web timer routes, kiosk start, and\n legacy POST /api/timer/resume.\n- POST /api/v1/timer/start returns 409 with error_code\n timer_already_running when single-active mode is on and a timer\n is already running.\n- Deduplicate start_timer template handling in the service.\n\nTests: tests/test_single_active_timer_setting.py.\nDocs: REST_API (responses), GETTING_STARTED, REQUIREMENTS, Docker env\nnotes, TESTING_STRATEGY, env.example comment; CHANGELOG entry.
411 lines
14 KiB
Markdown
411 lines
14 KiB
Markdown
# Raspberry Pi Time Tracker — Software Requirements Document (SRD)
|
||
|
||
**Version:** 1.0
|
||
**Date:** 2025-08-15
|
||
**Owner:** (to be assigned)
|
||
|
||
---
|
||
|
||
## 1. Purpose & Scope
|
||
|
||
This SRD defines requirements for a Python application that primarily runs on a Raspberry Pi (RPI) using Docker, with a web-based frontend. The application tracks time across multiple projects with two tracking modes: manual entry and automatic timers that persist even if the browser is closed. The system supports per-user tracking with simple username-only login (no passwords) and provides project overviews, reporting, and per-entry annotations. No external REST API is required.
|
||
|
||
### In Scope
|
||
|
||
* Project management (name, client, brief description, billing information)
|
||
* Per-user time tracking
|
||
* Manual time entry (start/end date & time + project)
|
||
* Automatic timers that continue running server-side after browser close
|
||
* Project-level overviews of time spent
|
||
* Ability to add extra information (notes/metadata) per time entry
|
||
* Web-based UI (sleek, modern, and user-friendly)
|
||
* Execution on Raspberry Pi via Docker
|
||
* Local data storage and backups
|
||
|
||
### Out of Scope (for v1)
|
||
|
||
* Public internet exposure (LAN only)
|
||
* External integrations (e.g., third-party invoicing, calendars)
|
||
* Advanced permissions/roles beyond simple user identification
|
||
* Mobile apps (web frontend should be responsive)
|
||
* External REST API endpoints
|
||
|
||
---
|
||
|
||
## 2. Stakeholders & Users
|
||
|
||
* **End Users:** Team members who log time per project.
|
||
* **Project Managers / Admins:** Configure projects, view summaries, export reports.
|
||
* **IT/Ops:** Deploy and maintain the Dockerized application on RPI.
|
||
|
||
---
|
||
|
||
## 3. Definitions & Glossary
|
||
|
||
* **Automatic Timer:** A server-side, long-lived timer associated with a user and project that continues running even if the browser is closed.
|
||
* **Entry Notes/Metadata:** Additional text fields or tags recorded with each time entry.
|
||
* **Billing Information:** Basic fields such as billing rate, billable flag, PO/Cost center, or invoicing reference stored on the project.
|
||
|
||
---
|
||
|
||
## 4. System Overview
|
||
|
||
A Python backend (Flask recommended) runs inside Docker on a Raspberry Pi. The frontend is a server-rendered web UI with light interactive components and optional WebSocket events for live timers. Data persists locally (SQLite by default) with optional scheduled backups.
|
||
|
||
---
|
||
|
||
## 5. Functional Requirements
|
||
|
||
### 5.1 Authentication & User Identity
|
||
|
||
1. **Username-only Login:**
|
||
|
||
* Users enter a username to start a session; no password.
|
||
* If username does not exist, offer to create it (admin-configurable setting).
|
||
* Persist session via secure cookies.
|
||
2. **Access Model:**
|
||
|
||
* All logged-in users can create and edit their own time entries.
|
||
* Admin users can manage projects, view all reports, and edit any entry.
|
||
* Admin assignment via config or first user bootstrap.
|
||
|
||
### 5.2 Project Management
|
||
|
||
1. **Create/Read/Update/Archive Projects** with fields:
|
||
|
||
* Project Name *(required)*
|
||
* Client *(required)*
|
||
* Brief Description *(optional)*
|
||
* Billing Information *(see 5.2.2)*
|
||
* Status: Active/Archived
|
||
2. **Billing Information Fields (configurable subset):**
|
||
|
||
* Billable (Yes/No)
|
||
* Hourly Rate (currency-aware)
|
||
* Billing Reference (e.g., PO number)
|
||
* Default Time Rounding (e.g., 1/5/15 minutes) *(optional)*
|
||
|
||
### 5.3 Manual Time Entry
|
||
|
||
1. **Create Manual Entry:**
|
||
|
||
* Required: Project, Start DateTime, End DateTime
|
||
* Optional: Notes/Description (free text), Tags
|
||
* Validation: End must be after Start; no overlaps check (configurable) with warning.
|
||
2. **Edit/Delete Entry:** Users can edit or delete their own entries; Admins can edit any.
|
||
3. **Bulk Operations:** Optional bulk edit for tags or project reassignment.
|
||
|
||
### 5.4 Automatic Timer Tracking
|
||
|
||
1. **Start Timer:** User selects project and clicks **Start**.
|
||
2. **Server-Side Persistence:** Timer continues running on the server even if the browser closes, device sleeps, or network drops.
|
||
3. **Stop Timer:** User clicks **Stop** from any browser session or device; server finalizes entry (start->stop).
|
||
4. **Resilience:** If the RPI restarts, active timers are restored using last known start time and a flag indicating “active”.
|
||
5. **Single Active Timer per User:** By default only one running timer per user is allowed; attempting to start another while one is running is rejected until the first is stopped. **System Settings** can disable this to allow multiple concurrent timers. The `SINGLE_ACTIVE_TIMER` environment variable seeds the initial stored value for new deployments; runtime enforcement follows the database setting.
|
||
6. **Idle/AFK (optional v1.1):** After N minutes of inactivity, prompt on next visit to confirm whether to subtract idle time.
|
||
|
||
### 5.5 Time Entry Annotations & Metadata
|
||
|
||
* **Notes Field:** Rich text (plain text in v1, markdown in v1.1) per entry.
|
||
* **Tags:** Freeform comma-separated tags; auto-suggest from existing tags.
|
||
* **Edit History (optional):** Keep non-destructive audit trail for edits.
|
||
|
||
### 5.6 Reporting & Overview
|
||
|
||
1. **Project Overview:**
|
||
|
||
* Total time spent, grouped by user and by time period (day/week/month).
|
||
* Filters: date range, user, tags, billable/non-billable.
|
||
* Summaries: total hours, billable hours, estimated cost (rate × hours).
|
||
2. **User Overview:**
|
||
|
||
* Personal dashboard of own entries and totals.
|
||
3. **Entry List & Detail:**
|
||
|
||
* Paginated list with search, sort by date/project/duration.
|
||
4. **Exports:**
|
||
|
||
* CSV export for entries and summaries.
|
||
|
||
### 5.7 Notifications & Feedback
|
||
|
||
* Inline validations, toasts for success/errors.
|
||
* Live timer display (mm\:ss) with WebSocket/SSE updates.
|
||
|
||
### 5.8 Administration
|
||
|
||
* User list (usernames), role assignment (User/Admin).
|
||
* Project archival/unarchive.
|
||
* Configuration page (see 6.4) with authentication mode, rounding rules, timezone, currency.
|
||
|
||
---
|
||
|
||
## 6. Non-Functional Requirements
|
||
|
||
### 6.1 Platform & Runtime
|
||
|
||
* **Target Hardware:** Raspberry Pi 4 (2GB+) recommended.
|
||
* **OS:** Raspberry Pi OS (64-bit) or compatible Linux.
|
||
* **Containerization:** Docker + docker-compose.
|
||
* **Python:** 3.11+.
|
||
|
||
### 6.2 Performance
|
||
|
||
* Support 10–25 concurrent users on LAN with sub-200 ms page actions.
|
||
* Timer accuracy within ±1 second over 24 hours.
|
||
|
||
### 6.3 Reliability & Resilience
|
||
|
||
* Automatic restart with `restart: unless-stopped` in Compose.
|
||
* Graceful shutdown; in-flight timers persisted.
|
||
* Periodic health checks and liveness endpoints (internal only).
|
||
|
||
### 6.4 Configurability
|
||
|
||
* `.env`/config UI for: timezone (default Europe/Rome), currency, default rounding, allow self-register, single-active-timer, idle timeout, export delimiter.
|
||
|
||
### 6.5 Security
|
||
|
||
* LAN-only by default; bind to private IP.
|
||
* Reverse proxy optional (Caddy/nginx) for TLS on LAN.
|
||
* Username-only login; display clear banner that this is an internal tool.
|
||
* CSRF protection disabled for simplified development; secure cookies; session timeout.
|
||
* Role-based checks server-side.
|
||
|
||
### 6.6 Privacy & Data Retention
|
||
|
||
* Store minimal PII (username only).
|
||
* Retain entries indefinitely unless purged. Admin-configurable retention and backup.
|
||
|
||
### 6.7 Localization & Timezones
|
||
|
||
* System default timezone configurable; all storage in UTC; UI displays local time.
|
||
* Handle DST transitions; prevent overlapping/invalid times via UI validation.
|
||
|
||
### 6.8 Accessibility
|
||
|
||
* WCAG 2.1 AA-aligned basics: keyboard navigation, color-contrast, focus states.
|
||
|
||
---
|
||
|
||
## 7. Architecture & Design
|
||
|
||
### 7.1 High-Level Components
|
||
|
||
* **Web App (Flask):** Server-rendered templates (Jinja2) + HTMX/Alpine.js for interactivity.
|
||
* **Background Scheduler:** APScheduler (or asyncio task) for periodic jobs (backups, health checks).
|
||
* **Real-Time Layer:** WebSocket or Server-Sent Events for live timer updates.
|
||
* **Storage:** SQLite with WAL mode; upgrade path to PostgreSQL.
|
||
* **Reverse Proxy (optional):** Caddy/nginx container for TLS and static asset caching.
|
||
|
||
### 7.2 Data Model (Initial Schema)
|
||
|
||
**users**
|
||
|
||
* id (PK)
|
||
* username (unique, required)
|
||
* role (enum: user, admin)
|
||
* created\_at
|
||
|
||
**projects**
|
||
|
||
* id (PK)
|
||
* name (required)
|
||
* client (required)
|
||
* description (text)
|
||
* billable (bool)
|
||
* hourly\_rate (decimal, nullable)
|
||
* billing\_ref (text, nullable)
|
||
* status (enum: active, archived)
|
||
* created\_at, updated\_at
|
||
|
||
**time\_entries**
|
||
|
||
* id (PK)
|
||
* user\_id (FK → users)
|
||
* project\_id (FK → projects)
|
||
* start\_utc (datetime)
|
||
* end\_utc (datetime, nullable when active)
|
||
* duration\_seconds (int, computed on finalize)
|
||
* notes (text)
|
||
* tags (text)
|
||
* source (enum: manual, auto)
|
||
* edited\_at
|
||
|
||
**settings**
|
||
|
||
* id (singleton)
|
||
* timezone, currency, rounding\_minutes, single\_active\_timer, allow\_self\_register, idle\_timeout\_minutes
|
||
|
||
Indexes on (user\_id, start\_utc), (project\_id, start\_utc), and active entries (end\_utc IS NULL).
|
||
|
||
### 7.3 Timer Persistence Logic
|
||
|
||
* On **Start**: create `time_entries` row with `end_utc=NULL` and `source=auto`.
|
||
* Heartbeat optional; not required for persistence.
|
||
* On **Stop**: set `end_utc`, compute `duration_seconds` applying rounding rules.
|
||
* On **Server Restart**: query all `end_utc IS NULL` and treat as still running since `start_utc`.
|
||
|
||
### 7.4 UI/UX Guidelines
|
||
|
||
* Clean, modern layout with responsive design.
|
||
* Primary views:
|
||
|
||
1. **Dashboard:** Active timer status, quick Start/Stop, recent entries.
|
||
2. **Projects:** List, filter, create/edit, archive.
|
||
3. **Log Time:** Manual entry form.
|
||
4. **Reports:** Project and user overviews with filters and CSV export.
|
||
5. **Admin:** Users, settings.
|
||
* Components: sticky header timer, toasts, modal dialogs, date/time picker, tag chips.
|
||
|
||
---
|
||
|
||
## 8. Deployment & Operations
|
||
|
||
### 8.1 Docker Compose (concept)
|
||
|
||
* `app` (Flask + Gunicorn)
|
||
* `db` (optional Postgres; otherwise SQLite volume in `app`)
|
||
* `proxy` (optional Caddy/nginx)
|
||
* Volumes for `/data` (DB, exports, backups).
|
||
|
||
### 8.2 Environment Variables
|
||
|
||
* `TZ`, `CURRENCY`, `ROUNDING_MINUTES`, `ALLOW_SELF_REGISTER`, `SINGLE_ACTIVE_TIMER`, `IDLE_TIMEOUT_MINUTES`, `ADMIN_USERNAMES`.
|
||
|
||
### 8.3 Backup & Restore
|
||
|
||
* Nightly SQLite copy to `/backups/YYYY-MM-DD/` with retention policy.
|
||
* Manual on-demand export (zip: DB + CSVs of key tables).
|
||
|
||
### 8.4 Monitoring
|
||
|
||
* Health endpoint `/_health` (no auth) for local check.
|
||
* Logs to stdout; optional file rotation.
|
||
|
||
---
|
||
|
||
## 9. Security Considerations
|
||
|
||
* Username-only login is weak; mitigate by LAN isolation, optional reverse proxy auth, and kiosk usage.
|
||
* CSRF protection disabled; use SameSite cookies; disable framing.
|
||
* Rate-limit login attempts by IP to prevent session abuse.
|
||
|
||
---
|
||
|
||
## 10. Compliance & Legal
|
||
|
||
* Internal tool; ensure local employment/time-tracking rules if used formally (outside v1 scope).
|
||
|
||
---
|
||
|
||
## 11. Acceptance Criteria (Sample)
|
||
|
||
1. Users can create projects with client and billing fields.
|
||
2. Users can log manual entries with start & end times and notes.
|
||
3. Users can start a timer, close the browser, reopen, and see the timer still running.
|
||
4. Only one active timer per user (by default).
|
||
5. Project overview shows total hours per user for a chosen date range.
|
||
6. CSV export contains correct rows and computed durations.
|
||
7. System restarts do not lose active timers or historical entries.
|
||
8. Admin can archive a project; archived projects cannot be chosen for new entries.
|
||
9. UI renders well on desktop and mobile and passes basic keyboard navigation.
|
||
|
||
---
|
||
|
||
## 12. Test Cases (Illustrative)
|
||
|
||
* **TC-01:** Create project with required fields → Project listed as Active.
|
||
* **TC-02:** Manual entry with end before start → Validation error displayed.
|
||
* **TC-03:** Start timer, close browser, wait 2 minutes, reopen, stop → Duration ≥ 120s.
|
||
* **TC-04:** Start timer A, then start timer B → Timer A auto-stops (if configured).
|
||
* **TC-05:** Edit entry notes and tags → Changes persist and appear in reports.
|
||
* **TC-06:** Archive project, attempt to log time → Not selectable in new entry form.
|
||
* **TC-07:** CSV export for project/date range → Matches on-screen totals.
|
||
* **TC-08:** RPI reboot → Active timers restored, dashboard reflects running state.
|
||
* **TC-09:** CSRF protection disabled - no CSRF validation required.
|
||
|
||
---
|
||
|
||
## 13. UI Wireframe Descriptions (Textual)
|
||
|
||
* **Login:** Username input, “Continue” button, disclaimer about internal use.
|
||
* **Dashboard:** Header with current user + active timer (project name, elapsed). Large Start/Stop button, quick project selector, recent entries table with inline edit.
|
||
* **Projects:** Card list with name, client, billable badge, actions (Edit, Archive).
|
||
* **Log Time:** Form with project dropdown, start/end pickers, notes, tags.
|
||
* **Reports:** Filters row (date range, user, project, tags), totals cards, table, export button.
|
||
* **Admin:** Users list with role toggles, settings form.
|
||
|
||
---
|
||
|
||
## 14. Future Enhancements (Backlog)
|
||
|
||
* Idle detection and retroactive adjustments.
|
||
* Mobile PWA installability and offline caching for UI.
|
||
* Calendar and Kanban views; week grid editor.
|
||
* Rate cards by client; multi-currency.
|
||
* LDAP/SSO or reverse-proxy auth (e.g., Authelia) for stronger security.
|
||
* REST API (if needed) or WebDAV/ICS export.
|
||
* PDF report templates and invoice drafts.
|
||
|
||
---
|
||
|
||
## 15. Constraints & Assumptions
|
||
|
||
* LAN-only deployment; minimal threat model.
|
||
* No external REST API required.
|
||
* SQLite is sufficient for initial scale; PostgreSQL available if needed.
|
||
|
||
---
|
||
|
||
## 16. Appendix: Example docker-compose.yml (Skeleton)
|
||
|
||
```yaml
|
||
services:
|
||
app:
|
||
image: timetracker:latest
|
||
build: .
|
||
environment:
|
||
- TZ=Europe/Rome
|
||
- ROUNDING_MINUTES=1
|
||
- SINGLE_ACTIVE_TIMER=true
|
||
- ALLOW_SELF_REGISTER=true
|
||
- ADMIN_USERNAMES=admin
|
||
ports:
|
||
- "8080:8080"
|
||
volumes:
|
||
- app_data:/data
|
||
restart: unless-stopped
|
||
|
||
# Optional reverse proxy (TLS on LAN)
|
||
proxy:
|
||
image: caddy:latest
|
||
volumes:
|
||
- ./Caddyfile:/etc/caddy/Caddyfile
|
||
- caddy_data:/data
|
||
- caddy_config:/config
|
||
ports:
|
||
- "80:80"
|
||
- "443:443"
|
||
depends_on:
|
||
- app
|
||
restart: unless-stopped
|
||
|
||
volumes:
|
||
app_data:
|
||
caddy_data:
|
||
caddy_config:
|
||
```
|
||
|
||
---
|
||
|
||
## 17. Appendix: Data Dictionary (Selected Fields)
|
||
|
||
* **projects.hourly\_rate:** Decimal(9,2), nullable; interpreted in `settings.currency`.
|
||
* **time\_entries.tags:** CSV string; UI presents chips; stored raw for simplicity.
|
||
* **time\_entries.duration\_seconds:** Calculated as `round_to(duration, rounding_minutes)` when finalized.
|
||
|
||
---
|
||
|
||
**End of Document**
|