Skip to main content

Contracts

Contract entities represent rental agreements as business records. A contract is not just a PDF; the PDF is a document linked to the contract.

contracts

Purpose

Central business entity representing a rental contract.

Suggested attributes

FieldDescription
idPrimary identifier.
property_idProperty covered by the contract.
contract_typeRESIDENTIAL, COMMERCIAL, TEMPORARY, STUDENT, TOURIST, or OTHER.
contract_dateSignature or registration date.
start_dateContract start date.
end_dateContract end date.
original_end_dateFirst legal end date captured before any auto-renewal catch-up.
renewal_typeRenewal logic or description.
auto_renewal_enabledUser-confirmed auto-renewal flag. Existing contracts remain false after migration.
auto_renewal_period_monthsRenewal period length in months.
auto_renewal_notice_daysDays before end date by which notice must be given.
auto_renewal_notice_deadlineComputed deadline for notice.
auto_renewal_next_dateNext end date after the latest applied or proposed renewal.
auto_renewal_statusNONE, ACTIVE, CANCELLED_BY_NOTICE, DISABLED, or ERROR.
rent_amountMain recurring rent amount.
rent_frequencyMONTHLY, QUARTERLY, YEARLY, or CUSTOM.
deposit_amountSecurity deposit amount.
payment_due_dayDay of month or period when rent is due.
notice_period_monthsNotice period in months.
tax_regimeContract tax regime.
cedolare_secca_flagWhether cedolare secca applies.
bank_account_idDefault logical bank account for collection.
statusDRAFT, ACTIVE, EXPIRED, or TERMINATED.
conditionsStructured or free-form contract conditions.
notesOperational notes.
created_atCreation timestamp.
updated_atLast update timestamp.

Relationships

RelationshipDescription
contracts.property_id to properties.idEach contract belongs to one property.
contracts to contract_unitsA contract may cover one or more units.
contracts to contract_partiesA contract has role-based parties.
contracts to rent_installmentsA contract generates expected rent installments.
contracts.bank_account_id to bank_accounts.idOptional default collection account.
contracts to documentsContract files are documents linked to the contract.
contracts to contract_renewal_eventsAuto-renewal audit trail, reminders, cancellations, and scheduler actions.

Notes and design rationale

The contract stores business facts used by rent scheduling, tax reporting, alerts, and reconciliation. Legal files are stored in documents.

Contract deletion cleanup

Contract deletion is orchestrated by the dedicated data-service module backend/data-service/modules/contracts/contractDeleteOrchestrator.js. The data-service module does not access MySQL directly: it authenticates the user, checks contract ownership through the normal route guard, receives the cleanup options selected by the user, deletes document/vector resources through the owning services, and delegates database preview/cascade work to datahub.

The database-owned part is implemented in backend/datahub/modules/contracts/contractDeleteCascade.js and exposed through internal-only datahub endpoints:

  • POST /internal/contracts/:id/delete-preview
  • POST /internal/contracts/:id/delete-cascade

Those endpoints require an internal JWT with audience datahub and scope datahub:contracts:delete. They are not browser APIs and must not contain business ownership decisions.

POST /contracts/:id/delete-preview returns the counts of connected records and the default cleanup options. POST /contracts/:id/delete applies the selected options. DELETE /contracts/:id is kept for compatibility and applies the default cleanup options.

By default, contract deletion performs a bottom-up cleanup before deleting the contract row:

  • Collects rent installments linked to the contract.
  • Collects contract-scoped expected expenses.
  • Collects bank transactions connected through rent matches, expense matches, or bank transaction splits.
  • Deletes rent payment matches.
  • Deletes expense payment matches for contract-scoped expected expenses.
  • Deletes bank transaction splits that point to the contract, its rent installments, or its expected expenses.
  • Deletes contract-scoped expected expenses instead of letting them become orphaned contract_id=NULL records.
  • Resets impacted bank transactions to unreconciled by clearing reconciliation fields.
  • Deletes linked contract documents through docs-service, which also removes extracted text and vector index content owned by those documents.
  • If document deletion is disabled but vector cleanup is enabled, it calls document-indexer-service to remove the contract document vectors only.
  • Detaches manual expenses, linked mail messages, and analytics read models that are not removed by FK cascade.
  • Deletes explicit contract entity shares.
  • Deletes the contract only after the manual cleanup, letting FK cascades remove contract_bank_accounts, contract_units, contract_parties, contract_renewal_events, rent_installments, and rent_installment_lines.

Property-level expenses are preserved. If an expense should survive contract deletion, it must be modeled without contract_id.

Auto-renewal migration policy

The auto-renewal migration is intentionally conservative:

  • Existing contracts are not mass-enabled.
  • auto_renewal_enabled defaults to false.
  • auto_renewal_status defaults to NONE.
  • No migration backfills renewal assumptions from existing PDFs or extracted text.
  • Any auto-renewal activation must be explicitly reviewed and saved by a user.

For historical data, use the read-only assisted script:

cd backend/data-service
node scripts/proposeContractAutoRenewals.js --datahub-url http://localhost:3000 --format json

The script scans document text already linked to contracts and returns proposed candidates with evidence snippets. It never writes to the database and never enables auto-renewal.

Auto-renewal rollout

Rollout is split into controlled releases so each operational risk can be validated independently:

ReleaseScopeRuntime behavior
1Schema, form, LLM extraction, catch-up calculation.No scheduler-driven renewal. Users can review extracted fields before saving.
2Catch-up rent installment generation.Missing installments are generated idempotently when a user saves a catch-up renewal.
3Scheduler dry-run.Nightly system job calls the internal dry-run endpoint and logs what would happen. No writes.
4Real automatic renewal and notifications.Scheduler applies due renewals, creates audit events, generates missing installments, and sends notice reminders through alertingService.

Operational switches:

SettingPurpose
CONTRACT_AUTO_RENEWALS_MODEdry-run for release 3, run only when release 4 is intentionally enabled.
CONTRACT_AUTO_RENEWALS_ENABLEDEnables or disables the scheduler system job.
CONTRACT_AUTO_RENEWAL_NOTIFICATIONS_ENABLEDEnables notification sending for reminders.
CONTRACT_AUTO_RENEWAL_REMINDER_DAYSComma-separated reminder offsets, default 90,30,7.
CONTRACT_AUTO_RENEWALS_NOTIFICATION_TOFallback recipients when no owner/manager email exists.

contract_renewal_events

Purpose

Audit trail for every auto-renewal decision and side effect.

Suggested attributes

FieldDescription
idPrimary identifier.
contract_idLinked contract.
event_typeSCHEDULED, APPLIED, APPLIED_ON_CREATE, SKIPPED, CANCELLED, ERROR, or NOTICE_REMINDER_SENT.
old_end_dateContract end date before the event.
new_end_dateContract end date after the event.
notice_deadlineNotice deadline involved in the event.
renewal_dateDate on which the event was applied or evaluated.
renewal_period_monthsRenewal period length used by the event.
status_beforeAuto-renewal status before the event.
status_afterAuto-renewal status after the event.
created_bySYSTEM, USER, or LLM.
created_by_user_idUser who triggered the event, when applicable.
reasonHuman-readable reason.
metadata_jsonStructured details such as reminder offset or generated installment counts.

contract_units

Purpose

Links contracts to one or more property units.

Suggested attributes

FieldDescription
idPrimary identifier.
contract_idLinked contract.
property_unit_idLinked property unit.
notesFree-form notes.

Relationships

RelationshipDescription
contract_units.contract_id to contracts.idMany units can belong to one contract.
contract_units.property_unit_id to property_units.idOne unit can appear in many historical contracts.

Notes and design rationale

A contract may cover a whole property, a single room, multiple rooms, parking, storage, or a combination of units.

contract_parties

Purpose

Role-based relationship between parties and contracts.

Suggested attributes

FieldDescription
idPrimary identifier.
contract_idLinked contract.
party_idLinked party.
roleLANDLORD, CO_LANDLORD, TENANT, CO_TENANT, GUARANTOR, AGENCY, or MANAGER.
percentageShare or allocation percentage when relevant.
start_dateRole start date.
end_dateRole end date.
notesFree-form notes.

Relationships

RelationshipDescription
contract_parties.contract_id to contracts.idOne contract can have many parties.
contract_parties.party_id to parties.idOne party can participate in many contracts.

Notes and design rationale

The model supports multiple landlords, co-landlords, tenants, co-tenants, guarantors, agencies, and managers without schema changes.

Graphical local diagrams

contracts

contract_units

contract_parties