Download Latest Version v0.9.1 -- Sentiment split + Projekt-Cockpit + inline-edit UX source code.zip (14.2 MB) Google Add to Preferred Sources
Home / v0.6.0
Name Modified Size InfoDownloads / Week
Parent folder
README.md 2026-10-04 9.5 kB
v0.6.0 -- Arbeitspakete, Pro-Teaser, Side-Panel _ Updater source code.tar.gz 2026-10-04 1.2 MB
v0.6.0 -- Arbeitspakete, Pro-Teaser, Side-Panel _ Updater source code.zip 2026-10-04 1.3 MB
Totals: 3 Items   2.5 MB 0

Added

  • Side-panel now also renders HTML banners as sandboxed <iframe>s (in addition to image/SVG), so creatives can be fluid (adapt to the slot) and carry their own clickable links. A feed item may have an image or an iframe URL; iframe URLs are validated against the same first-party allow-list, and the CSP gains frame-src/child-src for the banner host(s) (derived from banners.allowed_hosts, so HTML banners load without further config).
  • Arbeitspaket (Workpackage) layer between projects and tasks (fixes [#65]). Hierarchy becomes Kunde → Projekt → Arbeitspaket → Aufgabe, matching Pro so CSV exports/imports stay portable between editions.
  • New work_packages table (SQLite + MySQL) + nullable work_package_id FKs on tasks and time_entries (denormalized for the same reason as project_id/client_id).
  • Idempotent migration (schema/migrations/2026-10-04-01-work- packages.php): CREATE TABLE IF NOT EXISTS, column-exists guards around ALTER TABLE for upgrading installs, and a transactional backfill that seeds a default "Allgemein" work package per project and remaps every existing task + time entry to it. Zero-touch for live installations.
  • New admin nav entry Arbeitspakete between Projekte and Aufgaben; CRUD view at ?r=workpackages under structure.manage.
  • Task form grows an "Arbeitspaket" select; the entries form option-groups tasks by Kunde / Projekt / Arbeitspaket so the hierarchy is visible when picking.
  • CSV export adds work_package_code and work_package_name columns. CSV import still accepts files without these columns — tasks land in the project's default "Allgemein" WP (backwards compat for existing exports and third-party CSVs).
  • Pro-feature teaser pages. Four new nav entries — Rechnungen, Angebote, Budget, Rollen Pro — open dimmed read-only mockups of the features that only exist in Timeminator Pro. Each page carries a sticky upsell banner on the right edge linking to pro_url. No data is written, nothing is sent; the mockups are seeded from the user's real clients / projects where available so the preview looks plausible. All inline positioning (budget progress bars) is emitted into nonce-authorized <style> blocks so the strict CSP stays strict.
  • LoginThrottle::retryAfterSeconds($username, $ip) — precise upper bound in seconds until whichever locked bucket clears first; used to fill the Retry-After header.
  • Dockerfile + docker-compose.yml for zero-infrastructure local evaluation and self-hosting. Image is php:8.3-apache with PDO (MySQL and SQLite), zip for the in-app updater and mod_rewrite enabled — the same shape as a typical PHP shared host. Two Compose profiles: sqlite (single service) and mysql (app + MariaDB). data/ is persisted on a named volume. The project remains Composer-free at install time: composer.json and vendor/ are excluded from the build context via .dockerignore. README gains a "Run it in Docker" section (fixes [#19]).
  • Update banner. Admins see a small "new version available" panel under the top bar when the release manifest reports a newer version. Three actions: Ignorieren (dismiss for this session — comes back next login), Ueberspringen (skip this specific version until a newer one appears; persisted globally), Update (jump to Admin → System to apply). All buttons are forms with CSRF tokens; no inline JS. The banner respects Updater::isDisabled() and stays hidden for non-admins.
  • Opportunistic update check. The layout partial triggers Updater::opportunisticCheck() once every 24 h per install (throttled by the cache timestamp). Silent on failure — a page never breaks because the release manifest is unreachable.
  • .php data migrations. Updater::runMigrations() now picks up both .sql and .php files from schema/migrations/<driver>/. PHP migrations are required in an isolated closure and receive access to DB and Settings — for backfills that cannot be expressed as one SQL statement. Applied migrations are tracked by basename in Settings['applied_migrations'] as before, so an existing install is unaffected.
  • docs/schema-migrations.md. Documents the migration naming convention (YYYY-MM-DD-NN-slug.<ext>), the additive-by-default policy, the .php migration flow and the pre-1.0 compatibility contract.
  • referrer_or_default() helper. Same-origin-only redirect helper for the new dismiss/skip flow — keeps the admin on whatever page they were on instead of jumping to the dashboard.
  • Community banner carousel with server-side feed loading, offline fallback and opt-outable telemetry (fixes [#22]). A slim, collapsible banner column on the right of the main layout rotates through FelixSchallerCOM services, tools and news:
  • Creatives are loaded server-side from a configurable subdomain (banners.endpoint, default https://banners.felixschaller.com/feed.json) through a first-party route (index.php?r=banners), so the strict default CSP (connect-src 'self') needs no exception. The fetch is async and never blocks page rendering, and results are cached for banners.cache_ttl.
  • On any network failure the app falls back to the bundled default set in assets/banners/default.json, so the slot is never empty or broken on an isolated server.
  • Every creative is sanitized: links are accepted only as https felixschaller.com URLs and open with rel="noopener noreferrer"; images only as same-origin assets or https felixschaller.com URLs.
  • A small anonymized usage signal rides along with each feed refresh (app version, a random installation id stored in data/settings.json, a salted hash of it, and a truncated request IP). No time-tracking data is ever sent. Each field is switchable under banners.telemetry in config.php.
  • Admin → System → Community-Banner & Telemetrie adds runtime toggles: show/hide the column (banner_visible, default on), a master telemetry opt-out (banner_telemetry), and an endpoint override.
  • Set banners['enabled'] => false in config.php to remove the whole feature and its telemetry (the Pro edition ships it off).
  • Documented in docs/BANNERS.md.
  • Creatives are portrait "skyscraper" (300x600) SVGs with the real brand logos embedded. Bundled set covers the FelixSchallerCOM brand portfolio: AI Transformation ("AI Maturity Made Right"), Fractional & Interim Deep-Tech, the XIXUM AI-maturity assessment (xixum.ai), AF-AX ("the wing that never stalls", af-ax.com, logo + eVTOL-photo variant), and Timeminator Pro.
  • The feed link/image allow-list is configurable via banners.allowed_hosts (default felixschaller.com, xixum.ai, af-ax.com; subdomains included); foreign links/images are stripped. Images may be a same-origin asset, an https first-party URL, or an inline data:image/* URI, so remote creatives render under the strict default CSP without changes.
  • Default feed endpoint is https://assets.felixschaller.com/feed.json.

Changed

  • Banner slot renamed to a side-panel (ad-blocker-neutral: no "banner" anywhere in element classes, ids, or the fetch URL). Element ids / classes are now #sidepanel / .sp-*, the first-party fetch route is ?r=sidepanel, and the live feed subdomain migrated from banner.felixschaller.com to assets.felixschaller.com so content- blocking filter lists stop disappearing the whole column. Config keys (banners.*) and the admin UI label ("Anzeige") are unchanged.
  • PromoFeed system retired. The provisional src/PromoFeed.php + views/partials/promo_sidebar.php + assets/promo-fallback.json wiring (branch-only) is superseded by the Banners + #sidepanel carousel which supports both image creatives and sandboxed HTML iframe banners.
  • LoginThrottle now escalates the lockout window for repeat offenders in a 24 h horizon: 15 min → 1 h → 4 h → 24 h. The first lockout stays at the baseline 15 min; every subsequent lockout inside the horizon climbs one rung. Message copy reflects the actual wait ("… in 1 Stunde erneut versuchen") (fixes [#38]).
  • ctrl_login now returns HTTP 429 Too Many Requests with a Retry-After: <seconds> header when LoginThrottle refuses a login. The German error string in the page body stays unchanged, so the human path is identical; the change is for monitoring probes, health checks and retry scripts (fixes [#37]).
  • asset() now appends a cache-busting ?v=<filemtime> query string to every assets/* URL (CSS/JS/images) so browsers pick up a changed file immediately after a deploy — including a one-off hotfix via scp, not just a version bump. Falls back to app_version() when the file is not found on disk (#78).
  • .gitignore now excludes runtime artifacts under data/ (settings.json, *.json, *.log) so per-install state and logs stay out of the repo.
  • docs/ISSUES.md and the README privacy section describe the banner carousel and its telemetry.

Config

  • New banners block in config.sample.php (enabled, endpoint, cache_ttl, telemetry.*, hash_salt). Pre-1.0: this is an additive, optional block; existing installs keep working with the Community defaults.
Source: README.md, updated 2026-10-04