Switch product and installation telemetry to OTLP/Grafana across runtime config, CI injection, docs, and tests to unify telemetry transport and simplify privacy-focused opt-in behavior.
- New scopes read:inventory and write:inventory; existing read/write:projects
still grant same inventory access for backward compatibility
- require_api_token() accepts tuple of scopes (any one required); inventory
endpoints accept (read:inventory | read:projects) and (write:inventory | write:projects)
- ApiTokenService: add new scopes to allowed list; document in API_TOKEN_SCOPES.md
- Add tests for inventory report endpoints with scope checks
- Add keyboard_shortcuts_defaults utility for default bindings and overrides
- Update Settings keyboard shortcuts template for customization UI
- Add KEYBOARD_SHORTCUTS_DEVELOPER.md for implementation and extension
- Add telemetry-architecture.md: base vs detailed layers, schema, consent, retention
- ARCHITECTURE: link to telemetry doc and two-layer overview
- analytics.md: two-layer telemetry section and link to architecture
- privacy.md: update base/detailed analytics and retention wording
- all_tracked_events.md: document base_telemetry.first_seen/heartbeat, opt-in events
- In section 5.3 Stock Devaluation: note form message when item does not
support devaluation.
- Add 'How to use (UI)' steps for return and waste with devaluation.
- Add API note for POST /api/v1/inventory/movements devaluation parameters.
- Enables closing GitHub issue #385 with a doc reference.
OAuth: Replace deprecated accounting.transactions scope with accounting.invoices and accounting.payments so new Xero Developer apps (on or after 2026-03-02) complete the authorization flow.
Expense sync: Use /api.xro/2.0/ExpenseClaims instead of non-existent /api.xro/2.0/Expenses; read ExpenseClaimID from response.
API: Add optional json_body to _api_request and send invoice/expense payloads (Invoices and ExpenseClaims wrappers) to Xero.
Docs: Add docs/integrations/XERO.md (setup, scopes, sync, troubleshooting) and CHANGELOG entry.
- Mileage: Add GET /mileage/export/csv and /mileage/export/pdf with same
filters as list (status, project, client, date range, search). Export
buttons in list header; JS builds export URL from current filter form.
- Mileage PDF: New app/utils/mileage_pdf.py (ReportLab, landscape A4,
totals row for distance and amount).
- Per diem: Add Client filter to list (with client-lock/single-client
handling). Add GET /per-diem/export/csv and /per-diem/export/pdf.
- Per diem PDF: New app/utils/per_diem_pdf.py (same style as mileage).
- Export links always use current filters (no need to submit first).
- CHANGELOG and docs/import_export/README updated.
- Backend: WorkforceGovernanceService.delete_period, delete_leave_request,
delete_leave_type, delete_holiday with permission and state checks
- Web: POST delete routes in workforce blueprint; delete buttons in dashboard
for periods (draft/rejected), time-off (draft/submitted/cancelled), leave
types list, and company holidays (admin only)
- API v1: DELETE endpoints for timesheet-periods, time-off/requests,
time-off/leave-types, time-off/holidays (scopes and admin where required)
- Desktop: deleteTimesheetPeriod/deleteTimeOffRequest in API client; Delete
buttons and handlers in workforce view with confirmation and refresh
- Mobile: deleteTimesheetPeriod/deleteTimeOffRequest in API client; Delete
in popup menus for periods and time-off requests
- Docs: WORKFORCE_DELETE.md, PROJECT_STRUCTURE and API_TOKEN_SCOPES updates
- Add docs/BREAK_TIME_FEATURE.md (timers pause/resume, manual break, API, settings)
- CHANGELOG: add entry under [Unreleased]
- FEATURES_COMPLETE: Timer Management and Manual Time Entry mention break time
- docs/README: link to Break Time feature doc
- Document accumulated overtime (YTD) and where it appears (dashboard, analytics, workforce)
- Document take-overtime-as-paid-leave flow, API endpoints, and new helpers
- Add migration 136 and test_overtime_leave.py to Testing section; bump version to 1.2.0
- Enforce scope in timer routes: start_timer (POST), start_timer_for_project (GET),
and start_timer_from_template; deny with flash+redirect when project/client not allowed
- Add user_can_access_project check in api_start_timer (legacy API), API v1 timer/start,
and kiosk start-timer; return 403 with clear error message
- Scope dashboard Start Timer modal: load active_projects and active_clients via
apply_project_scope_to_model/apply_client_scope_to_model so subcontractors only see
assigned options
- Document timer start scope in SUBCONTRACTOR_ROLE.md (web, API, kiosk, 403/redirect)
On viewports <=767px, skip loading Toast UI Editor for the notes field on manual entry and edit timer pages; use a plain textarea instead. Toast UI is heavy and was freezing/crashing mobile Safari and Chrome. Desktop behavior unchanged. Document in CHANGELOG and MOBILE_IMPROVEMENTS.md.
- Add root CONTRIBUTING.md with quick overview and links to full guide,
Code of Conduct, and CHANGELOG
- Fix docs/development/CONTRIBUTING.md: use env.example (not .env.example)
for cp command to match repository
Allow overriding nginx port mappings with environment variables so users behind a reverse proxy (Nginx Proxy Manager, Traefik, etc.) or with 80/443 already in use can deploy without editing docker-compose.yml.
- docker-compose.yml: use \:80 and \:443
- env.example: document HTTP_PORT and HTTPS_PORT with example
- DOCKER_COMPOSE_SETUP.md: add Docker/nginx ports to env reference
Closes#553
Switch embedded invoice PDFs to Factur-X CII payloads and tighten the PDF/A-3 and AS4 handling so exports better match the standards they advertise. Document the experimental native Peppol transport path and cover the new validation and embedding behavior with focused tests.
Implement native PEPPOL transport plumbing (identifier validation, SMP/SML discovery, and AS4 send path) and make ZUGFeRD/PDF export fail fast when embedding or PDF/A-3 normalization fails. Add settings, migrations, validators, tests, and docs so compliance issues are visible and verifiable.
- UBL: add unitCode C62 to InvoicedQuantity (required by EN 16931 / Peppol BR-CL-23)
- ZugFerd: attach XML as Associated File with relationship Alternative
- ZugFerd: inject ZUGFeRD XMP RDF for validators
- Docs: document AF/XMP, PDF/A-3 limitation, and validation (b2brouter, portinvoice)
- Tests: assert UBL contains InvoicedQuantity with unitCode in ZugFerd and Peppol tests
Admin menu:
- PDF Templates is now a top-level submenu under Admin (same level as System Settings) so it opens without opening System Settings first.
- Remove PDF routes from admin_settings_open so only PDF Templates expands on invoice/quote PDF pages.
- Set pdfDropdown parent to adminDropdown in nested dropdown click handler.
PDF layout (invoice & quote):
- Preserve table groups (Items, Expenses) on save by skipping Groups in cleanup and ensuring table names are set and restored from design_json.
- Add test for saving and reloading layout with tables.
Docs:
- Update PDF layout access path to Admin → PDF Templates → Invoice PDF (and Quote PDF) in PDF_LAYOUT_CUSTOMIZATION.md, PDF_EDITOR_ENHANCED_FEATURES.md, PDF_EDITOR_QUICK_START.md, INVOICE_EXTRA_GOODS_PDF_EXPORT.md.
Pass dicts instead of StockItem/Warehouse ORM objects to the purchase
order form template so Jinja's tojson filter can serialize them for
the embedded script. Fixes TypeError when creating or editing a PO.
- new_purchase_order and edit_purchase_order now convert query results
to minimal dicts (id, sku, name, unit for items; id, code, name for
warehouses) before render_template.
- Add docs/implementation-notes/INVENTORY_PO_FORM_JSON.md describing
the requirement and pattern for other forms embedding data in JS.
- Add run_seed() in app/utils/seed_dev_data.py: users, clients, projects,
tasks, time entries, expenses, comments, warehouses, stock items,
warehouse stock, stock movements, currencies, tax rules, invoices,
invoice items, and payments. Only runs when FLASK_ENV=development.
- Register 'flask seed' CLI command with options (users, clients,
projects-per-client, tasks-per-project, days-back).
- Add scripts/seed-dev-data.py and docker/seed-dev-data.sh for local
and Docker runs. Include seed scripts in image via Dockerfile chmod.
- Document in docs/development/SEED_DEV_DATA.md; update
DATABASE_RECOVERY.md, DOCKER_COMPOSE_SETUP.md, and development README.
When creating or editing a task, the description field relied entirely on the
Toast UI Editor from CDN. If that script failed to load (reverse proxy, CSP,
Firefox, or offline), users saw only an empty area and no way to enter a
description.
- Add fallback in create.html and edit.html: when window.toastui.Editor is
unavailable, show the existing textarea (remove 'hidden') and hide the
empty #description_editor div; set textarea min-height for usability.
- CHANGELOG: document fix under [Unreleased] -> Fixed.
- docs/TASK_MANAGEMENT_README: note fallback in Markdown Support section.
- Add Pause and Stop buttons when a timer is running; Pause saves the
segment so users can resume later without losing context.
- When no timer is active, show prominent 'Resume (project name)' to
restart with the same project/task/notes as the last entry.
- Add quick time adjustment (-15 / -5 / +5 / +15 min) for the active
timer via POST /timer/adjust (delta_minutes); limits ±4 hours.
- Update CHANGELOG, in-app Help, GETTING_STARTED, and FEATURES_COMPLETE
to document the new dashboard timer behavior.
Add trigger-demo-deploy job to cd-release workflow that POSTs to
Render deploy hook when TimeTrackerDemoRender org secret is set.
Runs after build-and-push; skips gracefully if secret is not
configured. Include demo deploy status in release summary.
Document in RENDER.md, CI_CD_DOCUMENTATION.md, and
GITHUB_ACTIONS_SETUP.md.
- Add render.yaml Blueprint: PostgreSQL + Python web service, auto-deploy on push
- Add demo mode (DEMO_MODE, DEMO_USERNAME, DEMO_PASSWORD): single fixed user only
- Login page shows demo credentials when demo mode is active
- Disable self-registration, admin user creation, and OIDC user creation in demo mode
- DB init creates demo user with password when DEMO_MODE is true
- Add docs/deploy/RENDER.md with deployment and demo mode instructions
- Group Chat, Timer, and Help in header as round icon buttons
- Vertically aligned, evenly spaced (gap-2), consistent w-10 h-10
- Header timer: one-click start/stop from any page via floating-timer-bar.js
- Fix timer manual entry URL (use /timer/manual, not /timer/manual_entry)
- Add Help button linking to help page
- Update FEATURES_COMPLETE (Header Quick Access, One-Click Timers)
- Update help page Time Tracking section with header timer tip
- Update CHANGELOG
Replace the single-page setup (telemetry + optional Google Calendar) with
a guided wizard that collects all base settings before completion.
Wizard steps:
1. Welcome - intro and Next
2. Region & time - timezone, date/time format, currency (Settings)
3. Company - name, address, email, optional phone/website (Settings)
4. System - allow self-registration, rounding minutes, single active
timer, idle timeout (Settings)
5. Integrations (optional) - Google Calendar OAuth; can skip
6. Privacy & finish - telemetry opt-in; Complete Setup submits form
Backend (app/routes/setup.py):
- GET: pass settings and timezones to template for prefilling
- POST: validate timezone, date_format, currency, rounding_minutes,
idle_timeout_minutes; persist all fields to Settings and
mark_setup_complete(telemetry_enabled)
- Default timezone/currency to UTC/EUR when missing (keeps tests passing)
Frontend:
- initial_setup.html: 6 wizard steps, progress bar (Step X of 6),
Back/Next and submit on last step
- setup-wizard.js: step navigation, progress update, optional
client-side validation for step 2 (timezone, currency required)
Docs updated: TELEMETRY_QUICK_START.md, GETTING_STARTED.md,
TELEMETRY_IMPLEMENTATION_SUMMARY.md.
Decorative images now survive save/load and no longer cause a black PDF preview:
- Sync imageUrl onto groups before generateCode() so template_json has
correct source (invoice and quote layout editors).
- Inject name/imageUrl into design_json with position-based matching so
reordering does not swap or drop URLs.
- Restore name and imageUrl from saved JSON onto canvas on load
(synchronous) so Konva custom attrs are not required.
- Omit decorative image elements with empty source from template_json;
placeholders stay visible in the editor but are not sent to ReportLab.
- ReportLab: explicitly skip decorative images with empty source; validate
base64 data URI payload and decode in try/except to avoid bad PDF output.
Documentation: PDF_LAYOUT_CUSTOMIZATION.md and PDF_EDITOR_ENHANCED_FEATURES.md
updated with decorative image description, state persistence details, and
troubleshooting. CHANGELOG.md updated under [Unreleased] Fixed.
- Add optional embedding of EN 16931 UBL XML in invoice PDFs (ZugFerd/Factur-X)
when 'Embed EN 16931 XML in invoice PDFs' is enabled in Admin > Peppol e-Invoicing.
Exported PDFs then contain ZUGFeRD-invoice.xml for hybrid human- and machine-readable
invoices; same UBL as Peppol, usable via Peppol or email.
- New setting invoices_zugferd_pdf (migration 128), pikepdf dependency, and
app.utils.zugferd helper (best-effort supplier/customer from Settings and client).
- Wire embed in export_invoice_pdf (and fallback path); admin checkbox and persistence.
- Docs: PEPPOL_EINVOICING.md retitled to 'Peppol and ZugFerd', new section for
ZugFerd embedding; README and CHANGELOG updated; migration 128 noted.
- Tests: test_zugferd.py (embed adds attachment with expected XML; invalid PDF
returns original bytes and error).
- Add user_clients table and UserClient model for many-to-many user-client assignment
- Add 'subcontractor' system role; users with this role see only assigned clients and their projects
- User helpers: is_scope_restricted, get_allowed_client_ids(), get_allowed_project_ids()
- Admin user form: assign clients when role is Subcontractor (multi-select, JS toggle)
- Scope filtering: clients, projects, time entries, reports, invoices, timer, API v1
- Direct access to out-of-scope client/project returns 403 (web and API)
- Migration 127_add_user_clients_table; scope_filter utility and ProjectService scope_client_ids
- Docs: SUBCONTRACTOR_ROLE.md, ADVANCED_PERMISSIONS.md, RBAC, CLIENT_PORTAL, README, CHANGELOG
Addresses GitHub Discussion #476 (user with limited clients/projects).
- Fix#504: Save button no longer removes items/expenses table from PDF layout
- Add i18n-aware table name inference when Konva fails to serialize custom attrs
- Ensure table group names are set before generateCode on save
- Extend load-time defensive fix to support localized headers (DE, FR, IT, NL)
- Apply same fixes to Quote PDF layout for quote-items-table
- Fix#503: Invoice items (time entries, extra goods, expenses) now appear in PDF
- Root cause was #504; tables are now persisted correctly on save
- Add collapsible Help sections to invoice and quote PDF layout pages
- Update README with PDF Invoice Layout subsection and doc links
- Add troubleshooting for 'Items/expenses table disappears after save'
- Clarify invoice.all_line_items usage in PDF_LAYOUT_CUSTOMIZATION.md
- Document Items Table element in INVOICE_EXTRA_GOODS_PDF_EXPORT.md
Make https://timetracker.drytrix.com/support.html visible so users can purchase a key to hide donate/support UI (one key per instance, €25 one-time).
- Add SUPPORT_PURCHASE_URL config and support_purchase_url in template context
- Donate page: 'Remove Donation Messages' section and CTA, link in Other Ways to Help
- Admin Settings: Support visibility copy and 'Get key at Support & Purchase' button
- User Settings: line and link for admins to purchase a key
- Support banner: 'Purchase key to hide' link
- Dashboard widget: 'Want to hide this widget? Purchase a key'
- README: Support section bullet and intro line for support/purchase key
- SUPPORT_VISIBILITY.md: 'How to get a code' subsection, issuing codes note
- docs/README.md: Support visibility in Configuration with purchase link
- messages.po: add new translatable strings
- REST API v1: add deals, leads, contacts, time-entry-approvals (CRUD + approve/reject/cancel/bulk-approve). New scopes and /info entries.
- Standardize API errors: use error_response, forbidden_response, not_found_response in api_v1 (projects + new CRM/approval routes).
- Consolidate templates: move root templates/ into app/templates/, remove ChoiceLoader and legacy root files.
- Version: README/FEATURES_COMPLETE/CHANGELOG/mobile docs reference setup.py as single source (4.19.0); add [4.19.0] changelog entry.
- Docs: SERVICE_LAYER_AND_BASE_CRUD.md, RBAC_PERMISSION_MODEL.md; base_crud_service docstring points to service-layer doc.
- Mark projects_refactored_example, timer_refactored, invoices_refactored as REFERENCE ONLY in docstrings.
- Admin PDF preview: build all_line_items on invoice wrapper and resolve
table data from element data source (invoice.all_line_items or
invoice.items) so preview matches exported PDF.
- ReportLab: when template uses invoice.items, append both extra_goods
and expenses to table data so all line types appear in PDF.
- Export PDF: explicitly load items, extra_goods, and expenses before
generation so data is in session.
- Docs: recommend invoice.all_line_items for custom templates; document
backward compatibility and preview behavior.
Refs #503
Co-authored-by: Cursor <cursoragent@cursor.com>
- Respect user date format and week start: Flatpickr on user-date-input
fields, get_resolved_week_start_day for calendar/pickers, Week Starts On
from My Settings. Update CALENDAR_FEATURES_README.
- Fix time entry notes not saving on edit: sync Toast UI editor to hidden
textarea on all forms so the submitted form gets the current note (edit_timer).
- Time entries PDF export: wrap Task, Client, and Project columns like Notes
so long text breaks across lines (Issue #489).
Co-authored-by: Cursor <cursoragent@cursor.com>