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>
- Add Support visibility in Settings: users see a stable System ID and can
enter a code to permanently hide donate buttons, support banner, and
donate widgets.
- Verification supports two modes:
- Ed25519: server stores only public key; codes are signatures generated
offline with the private key (no secret on server).
- HMAC: server stores a secret; code = HMAC(secret, system_id).
- Add User.ui_show_donate and Settings.system_instance_id (migration 121).
- Add donate_hide_code utility (HMAC + Ed25519 verify) and config for
DONATE_HIDE_PUBLIC_KEY(_FILE) and DONATE_HIDE_UNLOCK_SECRET(_FILE).
- Wrap all donate UI in base, dashboard, about, help with conditional.
- Add admin doc SUPPORT_VISIBILITY.md; ignore docs/internal/ and
code-generation script in .gitignore.
- Add translations for new strings.
Co-authored-by: Cursor <cursoragent@cursor.com>
- Document that the default admin has no password; users set it on first
login (8+ characters) with AUTH_METHOD=local
- Add security note: self-register creates app users from entered
credentials only, not from DATABASE_URL; avoid using the DB username
(e.g. timetracker) as an app username
- Add "What is the default admin password?" to Common Questions
- Update GETTING_STARTED, DOCKER_COMPOSE_SETUP, DOCKER_STARTUP_TROUBLESHOOTING,
and env.example
- Config: clarify WTF_CSRF_TRUSTED_ORIGINS comment (include exact client URL)
- Mobile: README troubleshooting for DDNS/cert errors and subpath base URL
- Mobile: login screen helper text for exact URL and "Yes, trust" for certs
- Mobile: 404 diagnostics suggest using full base URL when app is at a subpath
- Docs: add NGINX_PUBLIC_DOMAIN.md (Docker vs host nginx, why /api/v1 404)
- Nginx: add example-public-domain.conf for exposing app at a public domain
- Add issuer fallback from OIDC_ISSUER when userinfo lacks iss (fixes Authelia)
- Fallback to unverified id_token decode for iss when ID token parsing failed
- Wrap authorize_access_token() in dedicated try/except; log token_exchange_failed
and suggest session cookie/proxy checks when state or PKCE validation fails
- Log reason=... before every redirect to login in callback for easier debugging
- Add 'Redirect loop / callback returns to login' troubleshooting to OIDC_SETUP.md
Fixes#486
Co-authored-by: Cursor <cursoragent@cursor.com>
- desktop/README and docs/mobile-desktop-apps: minor updates
- desktop renderer index.html: small adjustments
Co-authored-by: Cursor <cursoragent@cursor.com>
- 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>
- Add '+ Add task' button in Kanban and Gantt headers linking to create
with project (and status for Kanban) pre-filled
- Support 'next' redirect after task create; validate to allowed paths
(/kanban, /gantt, /tasks, /projects) to avoid open redirects
- Honor Initial Status on create: TaskService and form now pass status
through; create form pre-fills status from query and hidden 'next'
- Per-column '+' on Kanban to add task into that column (status pre-set)
- Return user to same Kanban/Gantt view after creating a task
Stock devaluation for return and waste movements was already implemented via valuation layers (stock lots). This change hardens and documents it:
- Add route tests: return with devaluation creates devalued lot; waste with devaluation consumes from devalued lot.
- Add API tests for POST /api/v1/inventory/movements with devalue_enabled (return and waste).
- Add discoverability hint on Record Movement form when type is Return or Waste.
- Document stock devaluation in INVENTORY_MANAGEMENT_PLAN.md (subsection 5.3) and list devaluation in movement_type.
- Update README.md to reflect version 4.14.0
- Update docs/FEATURES_COMPLETE.md to version 4.14.0
- Add CHANGELOG entry for version 4.14.0 with comprehensive changes
- Align all version references with setup.py (4.14.0)
- Fix version consistency: Update all documentation to reflect version 4.13.2
- Add Technology Stack section with complete tech overview
- Enhance Quick Start section with prerequisites and troubleshooting links
- Add System Requirements section with minimum/recommended specs
- Improve documentation organization by use case (users, admins, developers)
- Add comprehensive feature documentation links throughout README
- Enhance Features section with guide links and better categorization
- Update documentation index (docs/README.md) with missing links
- Add Contributing Quick Reference section
- Fix broken links and improve navigation
- Polish all documentation for clarity and consistency
This update makes the documentation more accessible, better organized,
and easier to navigate for all user types (new users, administrators,
developers, and troubleshooters).
Import window and web activity from a local ActivityWatch aw-server
(https://activitywatch.net/) as automatic time entries (source='auto').
- Add ActivityWatchConnector: test_connection, sync_data, get_config_schema
- Per-user integration; config: server_url, default_project_id, lookback_days,
optional bucket_ids (default: aw-watcher-window_* and aw-watcher-web_*)
- No OAuth; setup at /integrations/activitywatch/setup
- Idempotent sync via IntegrationExternalEventLink and external_uid
- Register connector; treat activitywatch as per-user in IntegrationService
- activitywatch_setup route and template; connect redirect and is_global updates
- View/manage: Configure and Edit Configuration links for activitywatch
- docs/integrations/ACTIVITYWATCH.md; tests for connector and idempotency
Scheduled reports (per-salesman, unpaid-only)
- Schedule form: add email distribution (single / SalesmanEmailMapping /
template) and recipient template when "Split by custom field" is on.
- Support {value} and {value_lower} in recipient_email_template
(e.g. {value_lower}@test.de).
- Add use_last_month_dates on ReportEmailSchedule: optional "Use previous
calendar month" for monthly runs; migration 111.
- Override report date range in ScheduledReportService when
cadence=monthly and use_last_month_dates=true.
- Wire use_last_month_dates through schedule form, API, and
create_schedule.
Report Builder
- Add "Unpaid time entries" quick-start (Time Entries + unpaid only +
last 30 days) and applyUnpaidPreset().
- Clarify "Unpaid only" help: "Unpaid = billable, not yet on any invoice."
- Define canvas at top of script so edit-mode IIFE and addDataSourceToCanvas
can use it; fix applyUnpaidPreset/onclick when script failed to parse.
- Click-to-add for Data Sources and Components (in addition to drag-and-drop).
- Set dataTransfer.effectAllowed = 'copy' in dragstart for drop compatibility.
- Fix save-form handler: remove orphan try { with no catch that caused
SyntaxError and prevented applyUnpaidPreset (and rest of script) from loading.
Documentation
- Add docs/reports/UNPAID_BY_SALESMAN_AND_SCHEDULED_REPORTS.md (unpaid
definition, unpaid-by-salesman setup, SalesmanEmailMapping, template use).
- Add Flutter mobile app with authentication, timer, projects, and time entries
- Add Electron desktop app with system tray integration and offline support
- Implement offline storage with sync queue for both platforms
- Add comprehensive build scripts for cross-platform builds
- Include documentation and README files for both apps
- Add test suites for mobile and desktop applications
- Add ReportLab template renderer with JSON-based template system
- Implement template schema validation and helper functions
- Add database migration for template_json columns
- Update visual editor to generate ReportLab JSON alongside HTML/CSS
- Maintain backward compatibility with legacy templates
- Add comprehensive migration documentation
BREAKING CHANGE: Existing PDF templates need to be saved again through
the visual editor to generate the new template_json format. Templates
will continue to work using the legacy fallback generator until saved.
- Add multiple DNS resolution strategies (socket, getaddrinfo, auto)
- Implement IP address caching with TTL for improved performance
- Add retry logic with exponential backoff for metadata fetching
- Support Docker internal service name resolution
- Add connection pooling and optimized HTTP session handling
- Improve error classification and diagnostics
- Add comprehensive OIDC configuration options in config.py
- Update OIDC initialization in app factory with lazy loading support
- Add background metadata refresh scheduling
- Update documentation with troubleshooting guide and setup instructions