- Shipped
- August 9, 2026 at 7:55 PM UTC
- Author
- Kamo
- Commit
- e36b9fc
The REST layer serialised the JPA entities directly. A Contact has no mapping to its emails, phones, addresses, organisations, URLs, IMs or relationships — those are separate tables — so none of it was ever in a response, and Jackson silently dropped all of it on the way in. The create dialog collected seven sections and persisted none. Books and groups came back with their lazy associations rendered as null, which is why the sidebar could not attribute a group to a book. Underneath that, creating a contact could not succeed at all: CONTACT.OWNER_ID is NOT NULL and nothing set it, from the UI, from a vCard import, or from a CardDAV PUT. Import stored only the raw card and left FORMATTED_NAME null, which the column rejects; export read that same raw card back, so anything created in the UI exported empty. - **************** the wire shapes, with the counts the sidebar needs and the totals a pager needs - ContactDetailStore: batch-loads and replaces the seven satellite tables and group membership; deleting a contact no longer orphans them - ContactQueryStore: counts, an ordered/filtered/paged org-wide listing, and a search that also matches name parts, phone numbers and organisations - ContactVCardMapper: import and export go through one field mapping, so a contact survives a round trip. BDAY is written as a PartialDate — resolving it to an instant shifted the day for readers in another timezone - updateBook applies only the fields sent: renaming a book used to wipe its description and colour, and throw on the NOT NULL isVisible - deleteBook cascades; the org default is refused rather than breaking the check constraint every org-level book depends on - bulk delete/move/group endpoints — the list's checkboxes had nothing to call Book creation always sets an owner and ignores a client-supplied isOrgDefault: an ownerless book is only legal as the org default, and a second default would leave findOrgDefault choosing arbitrarily.