Zum Hauptinhalt springen

Social report sharing

The Android and iOS apps build monthly and yearly report aggregates from their local databases. They never upload task entries to render a share image. The only network body is the versioned ReportRenderPayload containing totals, project distribution, daily intensity levels, and achievement counters.

The authenticated POST /v1/report-render endpoint validates the request with a strict allow-list, renders the official Timesheet wordmark, Poppins typography, orange (#FF8800) and navy (#1A1B41) brand system in memory, and returns a non-cacheable PNG. The endpoint does not write the request or image to storage.

Platform presets

Dimensions are derived by the server from platform and placement; clients cannot submit width or height.

DestinationPlacementOutput
Instagram / Facebookpost1080 × 1350 (4:5)
Instagram / Facebookreel or story1080 × 1920 (9:16)
TikTokpost1080 × 1920 (9:16)
YouTubeshort1080 × 1920 (9:16)
LinkedIn / Threads / genericpost1080 × 1350 (4:5)

Unsupported combinations, such as a LinkedIn reel, are rejected.

Canonical aggregation rules

  • A report period is a half-open interval [local start-of-day, next period start). Leap days are included naturally.
  • Tracked duration is net task duration after breaks. Work crossing a boundary is clipped to the period and split at local calendar midnight before daily aggregation.
  • Duration math uses elapsed instants; calendar bucketing uses the payload time zone, so daylight-saving transitions do not invent or remove elapsed work.
  • An active day has positive net tracked duration. Streaks count consecutive local calendar dates, independent of the configured first weekday.
  • Weekdays use ISO numbering: Monday 1 through Sunday 7.
  • Heatmap intensity is ceil(day net duration / maximum day net duration × 4), clamped to 1...4; empty days are 0.
  • Project percentages use net duration divided by total net duration. The default share uses ordinal labels (Project 1, and so on), groups the remainder as Other, and never uploads database identifiers.
  • Comparisons use the immediately preceding calendar month or year with the same non-period filters. Percentage change is omitted when the previous duration is zero.
  • Achievement thresholds are deterministic: 100 tracked hours, 30 active days, 10 projects, and a 7-day streak.

Privacy boundary

Allowed fields are defined in the v1 JSON Schema. Unknown fields are rejected recursively. In particular, task descriptions, notes, timestamps, rates, salary, expenses, locations, invoice data, and individual entry identifiers have no representation in this contract.

The canonical yearly fixture is the reference input for renderer and mobile contract tests.

Both apps query aggregates locally, request the PNG, place it in a temporary/cache directory, open the native share sheet, and remove or allow the operating system to evict the temporary file.