KALENDER
KALENDER
The KALENDER plugin shows the appointments from your tenant data centrally
as a Unified Calendar (/kalender) in a shared 4-week grid and provides
the appointments via ICS feeds (ICS Export, /kalender/export) for
external calendar applications (Outlook, Apple Calendar, Google Calendar,
and so on).
The calendar is layer-based: Each layer comes from aCalendarSourceProvider of the respective plugin and combines its
appointments in one view:
- Contracts (plugin
VERTRAG) — rental periods as multi-day events - Time tracking (plugin
BUCHUNG) — time entries as single-day events
Further plugins can add their own layers via the sameCalendarSourceProvider interface (details:How-To/PLUGIN-DEVELOPMENT.md, section "Supplying a calendar (Unified
Calendar)").
> The calendar needs no database table of its own – it reads directly from
> the source plugins. You therefore need at least one active plugin with a
> calendar source (for example VERTRAG or BUCHUNG).
- Open the calendar view
- Show/hide layers
- Configure the ICS settings (visibility, fields)
- Create and manage ICS feeds (Calendar → ICS Export)
- Share the ICS link with staff so Outlook/Apple/Google can pull the appointments
1) Calendar view
1. Open Calendar in the menu (/kalender).
2. All active layers appear in the 42-day grid: contracts as multi-day events,
time tracking as single-day events.
3. Use the layer bar to show/hide layers – the setting is stored per user
(pref `kalender.layer., e.g. kalender.layer.VERTRAG` /kalender.layer.BUCHUNG). The default is on.
> Time tracking: Without the buchung.entry.view_all permission, a user
> only sees their own entries in the grid; with view_all, entries from
> all users are shown (foreign entries are prefixed with the user name in the
> subtitle).
2) ICS settings
1. Admin → Calendar → ICS (/settings/admin/kalender/ics).
2. Configure (content settings, affecting the contracts layer only):
- which fields appear in the appointment title/description (include checkboxes: purpose, tenant name, tenant address, date range, pickup location, return location, inventory list, technicians, link)
- the LOCATION mode: pickup location / return location / tenant address / no location
- the base URL (used to build the link to the contract; empty = automatic)
Other layers (e.g. time tracking) are exported as generic events
(title, date, link) – there are no filters by contract status and
no time window. The settings apply globally to all feeds of the
contracts layer (Calendar → ICS Export).
3. Save (POST /settings/admin/kalender/ics).
> Note: These content settings affect all feeds. The preview is now
> available per feed on the ICS export page (see section 3).
3) Create and manage ICS feeds (Calendar → ICS Export)
The export page /kalender/export manages the tenant-wide feeds
(view: permission kalender.kalender.view, edit: permissionkalender.ics.edit):
- Multiple named feeds per tenant – each feed has its own
token-based URL and its own layer selection (all layers by default).
- Dynamic generation: The feed content is **generated fresh on every
request** – there is no feed file to keep up to date and no more
AUTOMATE task.
- Active badge: green "Active" if the feed was accessed within the
last 7 days, otherwise grey "Inactive" (tooltip: last access or
"never").
- Token rotation per feed (permission
kalender.ics.edit): the old
feed URL becomes invalid immediately (404).
- Legacy migration: Existing K6 feed tokens (Issue #351) are
migrated automatically to the feed "Standard-Feed" – existing
subscriptions keep working.
4) Subscribe in an external calendar
The feed is token-based – every feed URL is an individual, unguessable secret
(Issue #351):
`https://
/ical-feed/<32-hex-token>
/calendar.ics`
1. Copy the feed URL under Calendar → ICS Export ("Copy" button on the feed).
2. Add it in the external calendar as a "calendar subscription" or "Add internet calendar".
3. Outlook / Apple / Google will refresh the appointments periodically – the feed content is generated fresh on every request.
> Each feed is tenant-wide for its selected layers: all appointments of
> those layers, without month or user filtering – the user's layer toggles
> only affect the grid.
>
> With Apple and Google calendars the refresh sometimes takes several hours – that is normal.
>
> Re-import after token rotation: "Rotate token" immediately invalidates
> the old feed URL (404). Affected subscribers must re-import the new feed
> URL – this is the intended protection: only those who know the URL can
> see the appointments.
5) Correcting appointments
Appointments come from the source plugins. If an appointment is wrong in the
calendar, fix it at the source (for example on the contract, plugin
VERTRAG, or on the time entry, plugin BUCHUNG), not on the calendar.
"Nothing shows up in the external calendar"
- Is the ICS URL correct?
- Does the feed URL return something (try opening it in the browser)? Wrong token → 404.
- Force a refresh in the external calendar.
"An old appointment that no longer exists keeps showing up"
- Are the contracts soft-deleted? The feed content is regenerated on every
request – the appointment disappears after the next refresh in the
external calendar.
- Force a manual refresh in the external calendar.
"The appointment title is meaningless"
- ICS settings → adjust the title field format.
"I don't see all time tracking entries in the calendar"
- Without the
buchung.entry.view_allpermission, only own entries are
visible – this is by design. Users who may see all entries need the
permission (granted via ROLLEN).
"A layer is missing from the calendar / from the ICS"
- Missing from the grid? Was the layer hidden via the layer bar? Check the
user's pref `kalender.layer.
` (default is on). The layer toggles
only affect the grid.
- Missing from the feed? Check the feed's layer selection (Calendar → ICS
Export, edit the feed).
- Is the source plugin enabled for the tenant? Only active plugins provide
layers.
User area:
GET /kalender– Unified calendar view (layers: contracts, time tracking)POST /kalender/toggle-layer– show/hide a layer (prefkalender.layer., active providers only)GET /kalender/export– ICS export page (named feeds, layer selection, preview)POST /kalender/export/create– create a feed (permissionkalender.ics.edit)POST /kalender/export/{uuid}/update– modify a feed (name, layers; permissionkalender.ics.edit)POST /kalender/export/{uuid}/rotate-token– rotate the feed token (old URL → 404; permissionkalender.ics.edit)POST /kalender/export/{uuid}/delete– delete a feed (permissionkalender.ics.edit)GET /kalender/export/{uuid}/preview– feed preview (permissionkalender.kalender.view)GET /ical-feed/{token}/calendar.ics– ICS feed (public, token-based, generated dynamically on every request, Issue #351)GET /ical/{filename:.+}– disabled (404, former public format)
Admin:
GET /settings/admin/kalender/ics– content settings (contracts layer)POST /settings/admin/kalender/ics– save content settings
- Each ICS feed is tenant-wide for its selected layers: all
appointments of those layers, without month or user filtering. The feed
content is generated fresh on every request (no feed file, no AUTOMATE
task).
- The layer toggles in the calendar are per user (pref
kalender.layer.,
default on) and affect only the grid, not the feeds; the
per-feed layer selection is on the export page (/kalender/export).
- New layers come from
CalendarSourceProviderbeans of the respective
plugins – KALENDER itself only filters by tenant and user prefs;
visibility logic (e.g. time tracking) stays in the source plugin.
- KALENDER works with the active plugin sources (e.g. VERTRAG,
BUCHUNG).
- Legacy: existing K6 feed tokens (Issue #351) are migrated automatically
to the feed "Standard-Feed" – existing subscriptions and feed URLs stay
valid as long as the feed is not deleted or its token is rotated.
- Feed management (create, layer selection, token rotation, delete,
preview) is on the ICS export page (/kalender/export). The former
AUTOMATE task KALENDER_ICS (static feed file) is gone: feeds are now
generated dynamically on every request.