Commit Graph

16 Commits

Author SHA1 Message Date
Dries Peeters 3e7b7ab787 feat: add per-user GitHub, Google Calendar, and Slack connectors
Three new opt-in integration connectors that plug into the existing
`app/integrations/base.py:BaseConnector` pattern and the integrations
settings UI. Each connector subclasses `BaseConnector`, persists its
state inside the existing `Integration.config` JSONB (no new tables),
encrypts every secret at rest via `app/utils/secret_crypto`, and
degrades gracefully when the integration row is missing or
`is_active=False` -- every method returns
`{"ok": false, "error": "Integration not configured"}` without
raising, so the timer, exports, and dashboards keep working when a
connector is disabled or broken.

All third-party HTTP calls go through `requests` with a 10-second
timeout and a `try/except requests.RequestException`. Tokens are
never written to logs in their raw form -- only short
`xoxb-...` / `ghp_...` truncations.

GitHub connector (`app/integrations/github_connector.py`, provider
key `github_connector`):
  - Webhook receiver at `POST /api/integrations/github/webhook`
    verifies `X-Hub-Signature-256` with HMAC-SHA256 against the
    per-integration webhook secret before reading the payload.
  - Handles `issues.opened` (creates a task with
    `external_ref="github_issue_{n}"`, mapped priority and `todo`
    status), `issues.assigned` (optionally starts a timer for the
    linked TimeTracker user when `users.github_username` matches),
    `issues.closed` (marks the existing task `done`), and `ping`.
  - Manual sync (`POST /api/integrations/github/sync`, admin only)
    pulls open issues from
    `GET /repos/{owner}/{repo}/issues?state=open&per_page=50` and
    upserts tasks by `external_ref`. Optional `label_filter`.

Google Calendar connector (`app/integrations/google_calendar_connector.py`,
provider key `google_calendar_connector`):
  - OAuth2 flow at `/integrations/google/{connect,callback,disconnect}`
    using raw `requests` against
    `https://oauth2.googleapis.com/token`. Tokens (`access_token`,
    `refresh_token`, `token_expiry`) are stored encrypted in
    `Integration.config`. `client_id`/`client_secret` come from
    Flask config (`GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`) and are
    never hardcoded.
  - `_refresh_token_if_needed()` refreshes within 5 minutes of expiry
    on every API call.
  - `sync()` supports `import` / `export` / `both`:
    * import: pulls dated events from the configured `calendar_id`
      over the last `sync_days_back` days (clamped 1-30), skips
      all-day events and anything tagged `[TT]` or already linked via
      `gcal:{event_id}` in the notes of an existing `TimeEntry`.
    * export: posts completed entries created since `last_sync_at`
      back to Google as `[TT] {project} -- {task or notes}` events
      with `timeZone: "UTC"`.
  - `revoke()` calls `https://oauth2.googleapis.com/revoke` and
    wipes the stored tokens.
  - APScheduler job `google_calendar_sync` runs every 30 minutes;
    each user is wrapped in `try/except` so one broken token cannot
    block the rest.

Slack connector (`app/integrations/slack_connector.py`, provider key
`slack_connector`):
  - Webhook receiver at `POST /api/integrations/slack/events`
    verifies `X-Slack-Signature` (HMAC-SHA256 of
    `v0:{timestamp}:{body}`) and rejects requests older than 5
    minutes. Replies to Slack's URL verification handshake
    immediately.
  - Slash command `/tt` supports `start [project]` (id or
    case-insensitive partial name match against the user's allowed
    projects), `stop`, `status`, `today` (via
    `notification_service.get_today_summary_for_user`), and an
    in-place help text fallback. Every reply is ephemeral JSON so it
    fits inside Slack's 3-second budget without touching
    `response_url`.
  - `notify_timer_started` / `notify_timer_stopped` post a
    stopwatch/checkmark message to the configured channel. Wired
    into both the page route (`app/routes/timer.py`) and the JSON
    API (`app/routes/api.py`) as a fire-and-forget hook: the import
    + call are wrapped in `try/except` and only log at `DEBUG` on
    failure, so Slack outages can't slow down the timer flow.
  - `post_daily_summary` posts a daily roll-up; APScheduler job
    `slack_daily_summary` runs every 30 minutes and matches each
    user's configured `HH:MM` against the window.

Plumbing and storage:
  - New blueprint `app/routes/integrations_webhooks.py` registers
    the webhook receivers (`csrf.exempt`, signature-verified) plus a
    uniform `config`/`status`/`test` API surface
    (`/api/integrations/{github,google,slack}/{config,status,test}`)
    used by the settings UI. Optional-registered in
    `app/blueprint_registry.py`.
  - Alembic revision `155_add_integration_columns`:
    * `users.github_username` (String(100), nullable) - GitHub login
      join key for the assignment auto-start-timer flow.
    * `tasks.external_ref` (String(200), nullable, indexed) -
      canonical external id for connector-created tasks; the new
      index lets webhook receivers de-duplicate cheaply.
    Both columns are added defensively (inspector-checked) so the
    migration is safe to re-run.
  - New cards in `app/templates/integrations/_connector_cards.html`
    (included by `templates/integrations/list.html`) drive the
    Personal connectors UI -- Tailwind CSS only, vanilla JS, per-card
    status fetch, save, test, and sync actions.

Documentation:
  - `docs/integrations/README.md` indexes all built-in connectors.
  - `docs/integrations/GITHUB_CONNECTOR.md`,
    `docs/integrations/GOOGLE_CALENDAR.md`, and
    `docs/integrations/SLACK.md` cover setup, OAuth/webhook wiring,
    config fields, endpoints, and operational notes for each
    connector.
  - `docs/api/REST_API.md` lists the new endpoints under a new
    "Personal integration connectors" subsection.
  - `CHANGELOG.md` notes the feature under the [Unreleased] section.

`LLMService`, `TimeTrackingService`, `ForecastService`, and the
`Integration` model schema are intentionally untouched -- only
`users` and `tasks` gain columns via migration.
2026-05-15 10:45:30 +02:00
Dries Peeters 6de7035b4a feat: add personal productivity dashboard with stats API
Introduce a dedicated My productivity page at /dashboard/productivity
with streaks, focus metrics, project breakdown, a 12-week heatmap, and
Chart.js charts backed by ProductivityService (user-timezone-aware).
Expose GET /api/productivity/stats with a 5-minute cache when no active
timer is running. Document the feature and related session JSON routes.
2026-05-15 08:57:14 +02:00
Dries Peeters fb734fa91c chore(docs): align API and permissions docs with implemented behavior
Fix stale build-guide links, document the implemented quotes API scopes/endpoints, and clarify quote access plus permission-denial behavior so docs match route and test-backed behavior.
2026-04-29 10:42:49 +02:00
Dries Peeters 6c8e86cd01 fix(timer): respect Settings.single_active_timer at runtime
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.
2026-04-27 19:16:25 +02:00
Dries Peeters 07dbbd54a3 docs(api): document GET /api/reports/week-comparison
Describe the session JSON endpoint used by the main dashboard week
comparison chart: partial Monday-to-today window, parallel prior week,
dense by_day series, and null change_percent when last week has no hours.

Note the path with other internal dashboard routes in API_VERSIONING.md.
2026-04-27 17:53:54 +02:00
Dries Peeters eb2f5c6afa fix(apps): harden desktop and mobile server connectivity
Desktop (Electron):
- Add two-step first-run wizard: test TimeTracker via GET /api/v1/info, then log in with API token
- Replace bogus token check with validateSession (users/me, fallback to timer/status for narrow scopes)
- Normalize base URLs; classify TLS/DNS/timeout errors; periodic 401 forces re-login
- Settings save/test use public + authenticated checks; prebuild/prestart and npm test

Server:
- Exempt /api/v1/info, /api/v1/health, and POST /api/v1/auth/login from HTML setup redirect
- Include setup_required on GET /api/v1/info for unfinished installs

Mobile (Flutter):
- Validate saved token against new server URL before persisting settings change
- Remove unused lib/core/config.dart; point BUILD_CONFIGURATION at app_config.dart

Docs: DESKTOP_SETTINGS, desktop README, mobile-desktop-apps README, REST_API /info
2026-04-16 19:59:20 +02:00
Dries Peeters 51035f6779 fix(bootstrap): log optional blueprint failures and document search contracts
Register optional blueprints and the optional audit_logs module with full tracebacks (logger.exception and stable extra fields). Re-raise registration errors when FLASK_ENV is development or DEBUG is enabled so local misconfiguration fails fast; production and testing keep skipping optional modules after logging.

Update REST API, API versioning, architecture, project structure, contributor guide, and CONTRIBUTING for global search responses (partial and per-domain errors), shared run_global_search in app/services/global_search_service.py, and blueprint registry observability.
2026-04-16 15:37:06 +02:00
Dries Peeters 999f5c6319 feat(api): clarify /api vs /api/v1 and reduce duplication
Document the dual HTTP surface everywhere integrators look: OpenAPI intro and servers, ARCHITECTURE, REST_API, API_VERSIONING (deprecated vs internal routes, shared modules), and CONTRIBUTING (v1-first rule).

Session JSON routes in app/routes/api.py that overlap REST v1 now return X-API-Deprecated and a Link header with rel successor-version, implemented via app/utils/api_deprecation.py.

Extract shared global search into app/services/global_search_service.py for both GET /api/search and GET /api/v1/search while preserving legacy short-query 200 empty responses and v1 400 validation.

Refactor legacy POST /api/timer/start, /api/timer/stop, and the start path of /api/timer/resume to use TimeTrackingService; keep existing socketio emits for the web UI.

Add tests/test_api_deprecation_headers.py and adjust search partial-failure tests to patch Project.query on the service module.
2026-04-16 15:36:01 +02:00
Dries Peeters 7aeef629db docs(api): document value dashboard; fix project tasks API test
Document session-auth GET /api/stats/value-dashboard in REST_API.md
(response shape, last_7_days, estimated value fields, 10-minute Redis
cache). Link dashboard session JSON routes from docs/API.md and note
that /api/v1 scopes do not apply to those legacy paths.

Update the comprehensive API test so GET /api/projects/<id>/tasks is
expected to return every task status, including done and cancelled,
which matches the time-entry UI.

Changelog: record the documentation update and the test correction.
2026-04-16 15:09:03 +02:00
Dries Peeters 96955aee62 feat(admin): GitHub-based version update notification for admins
Add VersionService to fetch and cache the latest GitHub release, compare it to the installed semver (APP_VERSION when valid, else setup.py), and expose admin-only GET /api/version/check and POST /api/version/dismiss on the legacy /api blueprint (session or Bearer token).

Persist per-user dismissal in users.dismissed_release_version (Alembic 148) and show a non-blocking update card in base.html for administrators. Add packaging for semver parsing and tests for comparison, service, and routes.

Document configuration in docs/admin/deployment/VERSION_MANAGEMENT.md and endpoints in docs/api/REST_API.md and docs/API.md.
2026-04-15 09:39:32 +02:00
Dries Peeters 507266fbbf docs: API v1 import, bulk, idempotency, rate limits; Linear guide; release tooling
- Document CSV import, bulk actions, Idempotency-Key, and token rate limits in REST_API and scopes.
- Clarify session vs token CSV import in import/export README; mobile offline idempotency note.
- Add docs/integrations/LINEAR.md; refresh CODE_BASED_ANALYSIS_REPORT (v5.3.0, 14 connectors).
- env.example: API_TOKEN_RATE_LIMIT_*; setup.py version; CD release workflow tweak; Zapier webhook sample.
2026-04-05 08:39:22 +02:00
Dries Peeters 7cad0c6fdd docs: align documentation with current implementation
- Remove stale 'coming soon' claims; mark incomplete implementations as historical where relevant
- Update GETTING_STARTED, REST_API, KEYBOARD_SHORTCUTS_SUMMARY, BULK_TASK_OPERATIONS
- Update client portal, inventory, and activity feed docs; API token scopes
2026-03-16 15:16:05 +01:00
Dries Peeters 9547937be2 docs: update README and guides, add audit and strategy docs
- Simplify README version section and point to CHANGELOG
- Update UI overview with Reports and installation reference
- Refresh CONTRIBUTING, DEVELOPMENT, API.md links/consistency
- Add ARCHITECTURE_AUDIT, DOCS_AUDIT, PRODUCT_UX_AUDIT, FRONTEND, PERFORMANCE
- Add API_CONSISTENCY_AUDIT, RESPONSE_FORMAT, CONTRIBUTOR_GUIDE, TESTING_STRATEGY
- Update GETTING_STARTED, REST_API, PROJECT_STRUCTURE, DEPLOYMENT_GUIDE
2026-03-15 09:36:37 +01:00
Dries Peeters 0e7656134e Backend: add API auth login and fix time entry duration calculation
- Add POST /api/v1/auth/login (rate-limited) returning API token for mobile
- Fix time entry duration when DB returns timezone-aware datetimes (_naive_dt)
- Add _parse_date_range helper; expose timezone in API info
- Extend time entries API tests

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-01 16:50:42 +01:00
Dries Peeters e2d7e21447 feat(api): implement and enhance search API endpoints
- Fix syntax error in existing /api/search endpoint (missing parenthesis in tasks query)
- Enhance /api/search endpoint with types filter, improved error handling, and response metadata
- Add new /api/v1/search endpoint with token-based authentication
  - Requires read:projects scope
  - Respects user permissions (non-admin users see only their own time entries)
  - Supports filtering by entity type (project, task, client, entry)
  - Includes OpenAPI documentation
- Add comprehensive test suite for both endpoints
  - Tests for legacy /api/search (session-based auth)
  - Tests for /api/v1/search (token-based auth)
  - Covers authentication, authorization, filtering, and search functionality
- Update API documentation in docs/api/REST_API.md
  - Add search endpoint documentation with examples
  - Include parameter descriptions and response formats
- Add search endpoint to /api/v1/info endpoint listing

This addresses the HIGH PRIORITY requirement to implement the search API
endpoint that was referenced but may not have been fully functional.

Resolves: Search API endpoint (/api/search) referenced but may not exist
2025-12-29 12:40:38 +01:00
Dries Peeters 29f7186ee8 docs: Reorganize documentation structure for better navigation
Complete reorganization of project documentation to improve discoverability,
navigation, and maintainability. All documentation has been restructured into
a clear, role-based hierarchy.

## Major Changes

### New Directory Structure
- Created `docs/api/` for API documentation
- Created `docs/admin/` with subdirectories:
  - `admin/configuration/` - Configuration guides
  - `admin/deployment/` - Deployment guides
  - `admin/security/` - Security documentation
  - `admin/monitoring/` - Monitoring and analytics
- Created `docs/development/` for developer documentation
- Created `docs/guides/` for user-facing guides
- Created `docs/reports/` for analysis reports and summaries
- Created `docs/changelog/` for detailed changelog entries (ready for future use)

### File Organization

#### Moved from Root Directory (40+ files)
- Implementation notes → `docs/implementation-notes/`
- Test reports → `docs/testing/`
- Analysis reports → `docs/reports/`
- User guides → `docs/guides/`

#### Reorganized within docs/
- API documentation → `docs/api/`
- Administrator documentation → `docs/admin/` (with subdirectories)
- Developer documentation → `docs/development/`
- Security documentation → `docs/admin/security/`
- Telemetry documentation → `docs/admin/monitoring/`

### Documentation Updates

#### docs/README.md
- Complete rewrite with improved navigation
- Added visual documentation map
- Organized by role (Users, Administrators, Developers)
- Better categorization and quick links
- Updated all internal links to new structure

#### README.md (root)
- Updated all documentation links to reflect new structure
- Fixed 8 broken links

#### app/templates/main/help.html
- Enhanced "Where can I get additional help?" section
- Added links to new documentation structure
- Added documentation index link
- Added admin documentation link for administrators
- Improved footer with organized documentation links
- Added "Complete Documentation" section with role-based links

### New Index Files
- Created README.md files for all new directories:
  - `docs/api/README.md`
  - `docs/guides/README.md`
  - `docs/reports/README.md`
  - `docs/development/README.md`
  - `docs/admin/README.md`

### Cleanup
- Removed empty `docs/security/` directory (moved to `admin/security/`)
- Removed empty `docs/telemetry/` directory (moved to `admin/monitoring/`)
- Root directory now only contains: README.md, CHANGELOG.md, LICENSE

## Results

**Before:**
- 45+ markdown files cluttering root directory
- Documentation scattered across root and docs/
- Difficult to find relevant documentation
- No clear organization structure

**After:**
- 3 files in root directory (README, CHANGELOG, LICENSE)
- Clear directory structure organized by purpose and audience
- Easy navigation with role-based organization
- All documentation properly categorized
- Improved discoverability

## Benefits

1. Better Organization - Documentation grouped by purpose and audience
2. Easier Navigation - Role-based sections (Users, Admins, Developers)
3. Improved Discoverability - Clear structure with README files in each directory
4. Cleaner Root - Only essential files at project root
5. Maintainability - Easier to add and organize new documentation

## Files Changed

- 40+ files moved from root to appropriate docs/ subdirectories
- 15+ files reorganized within docs/
- 3 major documentation files updated (docs/README.md, README.md, help.html)
- 5 new README index files created
- 2 empty directories removed

All internal links have been updated to reflect the new structure.
2025-12-14 07:56:07 +01:00