Special Conditions Library
Special Conditions Library
The special conditions library lets agencies build a reusable set of clause templates that agents can select when generating tenancy agreements. Conditions are snapshotted at the point of attachment, so past agreements are never affected by library edits.
Overview
- Library management — Admins create, edit, categorise, and archive conditions in Company Settings.
- Agreement generation — Agents pick from the library or type freeform clauses during tenancy agreement generation.
- Snapshot integrity — The clause text and title are copied to the tenancy term at selection time; subsequent library edits do not alter existing agreements.
- Promotion — Freeform clauses typed inline can be saved back to the library for future reuse.
Database Schema
special_conditions
Org-scoped library of clause templates.
| Column | Type | Description |
|---|---|---|
id | text (UUID) | Primary key |
orgId | text | Organisation scope |
title | text | Short label for quick selection |
body | text | Full clause text included in the agreement |
isTemplate | boolean | true = reusable template; false = one-off |
category | text (nullable) | Optional grouping (e.g. pets, garden, parking) |
sortOrder | integer | Display order within the list |
isActive | boolean | false = soft-deleted / archived |
createdByUserId | text | Audit trail — who created this entry |
createdAt / updatedAt | timestamp | Timestamps |
tenancy_term_special_conditions
Junction table linking snapshotted conditions to tenancy terms.
| Column | Type | Description |
|---|---|---|
id | text (UUID) | Primary key |
orgId | text | Organisation scope |
tenancyTermId | text | The tenancy term this condition belongs to |
specialConditionId | text (nullable) | Reference to the library entry; null for freeform |
title | text | Snapshotted title at attachment time |
body | text | Snapshotted clause body at attachment time |
sortOrder | integer | Display order within the agreement |
isFromLibrary | boolean | true = selected from library; false = freeform inline |
attachedByUserId | text | Audit trail — who attached this condition |
createdAt | timestamp | Timestamp |
tRPC Router: specialCondition
All endpoints are protected by orgProcedure and automatically scope queries to the caller's organisation.
Library Management
specialCondition.create
Adds a new condition to the library.
const condition = await trpc.specialCondition.create.mutate({
title: "No pets allowed",
body: "The tenant shall not keep any animals or pets on the premises without prior written consent of the landlord.",
isTemplate: true,
category: "pets",
sortOrder: 0,
});
Input
| Field | Type | Required | Description |
|---|---|---|---|
title | string (1–200 chars) | ✅ | Short label |
body | string (1–10 000 chars) | ✅ | Full clause text |
isTemplate | boolean | — (default true) | Reusable template flag |
category | string (max 100 chars) | — | Grouping label |
sortOrder | integer ≥ 0 | — (default 0) | Display order |
specialCondition.list
Returns all active conditions for the org. Supports optional filters.
const conditions = await trpc.specialCondition.list.query({
category: "pets",
isTemplate: true,
isActive: true,
search: "pets",
});
Input (all optional)
| Field | Type | Default | Description |
|---|---|---|---|
category | string | — | Filter by category |
isTemplate | boolean | — | Filter by template flag |
isActive | boolean | true | Include active/inactive records |
search | string (max 200 chars) | — | Title substring search |
Each result includes a usageCount field showing how many tenancy terms currently reference the condition.
specialCondition.getById
Fetches a single condition by ID.
const condition = await trpc.specialCondition.getById.query({ id: "<uuid>" });
Throws NOT_FOUND if the condition does not exist or belongs to a different org.
specialCondition.update
Edits an existing library condition. All fields are optional — only supplied fields are updated. Existing tenancy term snapshots are not affected.
await trpc.specialCondition.update.mutate({
id: "<uuid>",
title: "Updated title",
body: "Updated clause text...",
category: "garden",
sortOrder: 2,
isActive: true,
});
specialCondition.archive
Soft-deletes a condition by setting isActive = false. The record is retained for historical reference.
await trpc.specialCondition.archive.mutate({ id: "<uuid>" });
specialCondition.listCategories
Returns the distinct set of category strings currently in use for the org. Useful for populating filter dropdowns.
const categories = await trpc.specialCondition.listCategories.query();
// e.g. ["garden", "parking", "pets"]
Tenancy Term Attachment
specialCondition.attachToTenancyTerm
Attaches one or more conditions (library picks and/or freeform clauses) to a tenancy term. The title and body of each condition are snapshotted at this point.
await trpc.specialCondition.attachToTenancyTerm.mutate({
tenancyTermId: "<uuid>",
conditions: [
{
specialConditionId: "<library-uuid>", // from library
sortOrder: 0,
},
{
// freeform inline clause
title: "Lawn maintenance",
body: "The tenant must mow the lawn fortnightly.",
sortOrder: 1,
},
],
});
specialCondition.detachFromTenancyTerm
Removes a previously attached condition from a tenancy term.
await trpc.specialCondition.detachFromTenancyTerm.mutate({
id: "<tenancy-term-special-condition-uuid>",
});
specialCondition.listForTenancyTerm
Returns all conditions attached to a specific tenancy term, ordered by sortOrder.
const attached = await trpc.specialCondition.listForTenancyTerm.query({
tenancyTermId: "<uuid>",
});
specialCondition.reorderForTenancyTerm
Updates the sortOrder of conditions on a tenancy term to reflect a new display sequence.
await trpc.specialCondition.reorderForTenancyTerm.mutate({
tenancyTermId: "<uuid>",
orderedIds: ["<id-3>", "<id-1>", "<id-2>"],
});
specialCondition.saveToLibrary
Promotes a freeform clause (attached inline to a tenancy term) into the reusable library.
const libraryEntry = await trpc.specialCondition.saveToLibrary.mutate({
tenancyTermSpecialConditionId: "<uuid>",
category: "parking",
});
Workflow
- Admin setup — Navigate to Company Settings → Special Conditions and create clause templates, assigning titles, bodies, and categories.
- Agreement generation — When generating a tenancy agreement, the agent is presented with the library. They can search by category or keyword, select conditions, and add freeform clauses inline.
- Attachment & snapshot — Selected conditions are written to
tenancy_term_special_conditionswith the clause text frozen at that moment. - Reordering — The agent can drag conditions into the required order before finalising the agreement.
- Promote freeform — If a freeform clause is useful for future agreements, the agent can save it to the library directly from the term view.
Audit Logging
All mutating operations emit an audit log entry:
| Action | Trigger |
|---|---|
special_condition.created | create |
special_condition.updated | update |
special_condition.archived | archive |
special_condition.attached | attachToTenancyTerm |
special_condition.detached | detachFromTenancyTerm |
special_condition.saved_to_library | saveToLibrary |
Security
- All endpoints use
orgProcedure, enforcing row-level org scoping on every query. - No cross-org data leakage is possible — every query filters by
orgIdderived from the authenticated session.