Real Estate Software & CMS for Agents with OpenImmo Import / Export
Appointments and tasks: a calendar that understands Outlook and Nextcloud

Appointments and tasks: a calendar that understands Outlook and Nextcloud

· Features

caldav calendar crm feature import tasks

An estate agent office lives on appointments: a viewing on Tuesday, the notary on Friday, the callback that has been on the list for two weeks. Until now these things had no place in our estate agent software, they lived in Outlook, in Nextcloud, on scraps of paper. Since this week the CRM has a place for them: calendars, appointments and tasks, with everything the two big worlds can do too — recurrences, reminders, categories, participants.

We deliberately started with the data basis, not with the view. No weekly grid, no drag and drop of appointment blocks. Lists instead: a calendar list, a task list, and in the calendar itself the list of its appointments. That sounds modest but it is the order that holds. The views come once the data is right — and whether the data is right you can tell from the import.

One language for Outlook and Nextcloud

Outlook and Nextcloud could not be more different, and yet both speak the same language when it comes to appointments: iCalendar, a text format from the nineties that every calendar in the world can read and write. An appointment in it is a VEVENT, a task a VTODO, a recurrence a rule like FREQ=WEEKLY;BYDAY=MO,WE. We built our data model along that format. Not because it is beautiful — it is not — but because it means every appointment coming from Outlook arrives with us without loss and one day leaves again just as well.

The recurrences were the hardest part. A rule such as every second Monday of the month, until the end of the year, except on 14 October the estate agent software must not only store but unfold: when is the next occurrence? Which appointments fall in this week? For that there is now a calculation core of its own in the data model that reads the rule language, subtracts the exceptions and puts changed single appointments in their place. And because no user wants to type BYMONTHDAY=15, a recurrence editor sits in the appointment dialog: frequency, interval, weekdays, day of month, end — and beneath it a preview of the next ten occurrences that updates on every click. Parts of a rule the editor does not display because they are too exotic are kept untouched; the editor says so.

Import from Outlook and Nextcloud

The import knows two routes. The first is the calendar file: Outlook exports a calendar as .ics, Nextcloud likewise, and the estate agent software reads both — with a preview before anything happens. The preview shows per entry whether it would be new or already present, and whether it carries a recurrence. The import itself runs as a server job in the background, with progress and a log, as with the contact import two weeks ago. A second import of the same file duplicates nothing: every appointment carries its identifier from the source, and a known appointment is updated instead of created anew.

The second route is a CalDAV account — the protocol Nextcloud shares its calendars over. In the CRM administration you create the account, check the connection and see which calendars and task lists the server offers. One click on import calendars fetches them all: every collection gets a mirror calendar of its own with us that knows where it comes from. Time zones are resolved in the process; a Berlin appointment at ten stays an appointment at ten even if the file noted it in UTC.

Reminders and participants we take along but do not evaluate yet. They stand as text on the appointment so that nothing is lost, and wait for the views in which they can do something.

You share a calendar, not an appointment

The most interesting decision was one about permissions. Our permission model can assign every record to a user or a team, and for contacts that is exactly right: one contact is mine, the other the team's. For appointments it would be wrong. Nobody shares individual appointments; you share a calendar. So with us the calendar is the permission holder, and every appointment follows it — the same pattern with which the inquiries followed their lead in the last report. Whoever sees the team calendar sees all appointments in it; an appointment moved into another calendar changes its visibility with the move.

Tasks, by contrast, are individually assignable, like contacts. The callback belongs to a person, not to a calendar. Both, calendars and tasks, sit in the group tree of the estate agent office and can be filed by drag and drop. A single agent notices none of this: they have their calendar, their tasks, done. The data separation is there, it is simply not in the way.

And because appointments in the CRM have to do with people, every contact and every lead has a new tab: appointments & tasks. The viewing sits on the prospect, the callback on the owner — created right there, with the link already set.

The rule that was not allowed into the core

Every user has a default calendar: the one an appointment falls into when nobody picks another. During the live test of the assignment a gap appeared. Whoever assigns a calendar to another user takes it away from the previous one — and if it was their default calendar, the colleague loses their default without anyone noticing. The server would have quietly created a new, empty one for them at the next appointment.

The first idea was to catch that in the assignment endpoint. Except this endpoint is generic. It knows contacts, calendars, templates, properties only as a record with someone responsible, and that is exactly what makes it valuable. Writing an exception for calendars into it would have married the core to the first module that needs a special rule. So the core got a seam instead: every module can register an assignment rule, and the endpoint asks them all before saving. The CRM registers one — a default calendar stays with its user; a team change is free — and the core still does not know what a calendar is. The next module with such a rule, a property with a running contract for instance, uses the same seam.

The balance in numbers

  • 4 new data types: calendar, appointment, task, CalDAV account — plus a calculation core for recurrence rules
  • 2 import routes: calendar file with preview and CalDAV account with mirror calendars
  • 1 recurrence editor with preview, in the appointment and task dialogs
  • 1 seam in the core for the assignment rules of the modules
  • over 4,700 automated tests, all green, zero findings in the code analysis

What users see of it: a planner document with calendars and tasks, a calendar dialog with its appointments, the tab on the contact — and an import that brings the past along from Outlook and Nextcloud. What comes next already stands in the lists: the calendar view that turns the same data into a weekly grid, and the user document that shows an agent's calendars, tasks and contacts in one place.

A recurrence with an exception: the editor shows the next occurrences, the gap stays empty

A recurrence with an exception: the editor shows the next occurrences, the gap stays empty

One language for both: calendars from Outlook and Nextcloud come through the same import

One language for both: calendars from Outlook and Nextcloud come through the same import

You share a calendar, not an appointment: every appointment follows its calendar

You share a calendar, not an appointment: every appointment follows its calendar

Back to the overview

Newly Added

Newly listed properties appear here first. This way, you can see the latest additions from any page without having to switch to the overview. One click opens the property's full listing with all details, photos and its location on the map. You'll find the complete list under "All Properties".

House for rent

01723 Wilsdruff

Object no.:
MI-062
Base rent:
1,850 EUR
Rent per m²:
12.01 EUR
Living area:
154 m²
Rooms:
5.0

Detached house for rent in Wilsdruff: 154 m², heat pump, garden, two parking spaces

House for rent

01217 Dresden

Object no.:
MI-061
Base rent:
1,520 EUR
Rent per m²:
14.07 EUR
Living area:
108 m²
Rooms:
4.0

End-of-terrace house for rent in Dresden-Mockritz: 108 m², first occupancy, garden

Apartment for sale

01309 Dresden

Object no.:
MI-060
Purchase price:
598,000 EUR
Purchase price per m²:
4,397.06 EUR
Living area:
136 m²
Rooms:
4.0

New-build maisonette for sale in Dresden-Striesen: 136 m², KfW 40, first occupancy

House for sale

01067 Dresden

Object no.:
MI-059
Purchase price:
1,450,000 EUR
Purchase price per m²:
7,250 EUR
Living area:
200 m²
Rooms:
7.0

Listed town villa for sale in Dresden-Innenstadt: 200 m², 620 m² garden

House for rent

01156 Dresden

Object no.:
MI-058
Base rent:
1,480 EUR
Rent per m²:
11.94 EUR
Living area:
124 m²
Rooms:
5.0

Semi-detached house for rent in Dresden-Cossebaude: 124 m², garden, garage

House for rent

01156 Dresden

Object no.:
MI-057
Base rent:
1,050 EUR
Rent per m²:
11.05 EUR
Living area:
95 m²
Rooms:
3.0

Small detached house for rent in Dresden-Cossebaude: 95 m², garden, garage

    Contact Us

    Software Entwicklung Sieg
    Rhönweg 5 
    01159 Dresden

    info@ses-realestate.com

    Useful Links

    Our Partners


    Please note: All properties on this site are fictitious. Addresses, prices, floor areas and energy data do not describe any actual properties, enquiries are not processed and no contract is concluded. What you see is our software's interface in action: search, listing pages, shortlist and map work exactly as they will later with real properties.
    ©2026 SES Software Entwicklung Sieg