Skip to main content
All Docs
FeaturesagentOS Block ManagerUpdated April 12, 2026

Block Settings & Management Fee Configuration

Block Settings & Management Fee Configuration

Each block can now have a dedicated settings page that controls management fee structure, billing schedule, RMC/RTM company details, and service charge apportionment.

Navigate to a block and select Settings to access the page at:

/dashboard/blocks/{blockId}/settings

Authentication is required. Viewing settings requires org membership; saving changes requires admin access.


Tabs Overview

The settings page is split into three tabs.

1. Fees & Billing

Configure how and when your management fee is charged.

Fee Structure

Fee TypeDescriptionStored As
Fixed AnnualA fixed annual amount billed on the chosen scheduleInteger pence (e.g. £2,500.00 → 250000)
Percentage of BudgetA percentage of the total service charge budgetBasis points (e.g. 15% → 1500)

Important — fee isolation: Per platform spec, management fee income must never be deposited into client money accounts. The settings page tracks fee configuration separately from block funds.

Billing Schedule

  • Frequency — Monthly, quarterly, or annual.
  • Financial Year Start — The calendar month the financial year begins (default: April). This drives billing period calculations.

Invoice Settings

FieldDefaultDescription
Auto-generate invoicesOffAutomatically create a fee invoice at the start of each billing period
Days before due14How many days before the due date to send the invoice
Payment terms30 daysDays from invoice date until payment is due

2. RMC / RTM

Store details for the Resident Management Company (RMC) or Right to Manage (RTM) company associated with this block.

FieldDescription
Company NameLegal name of the RMC/RTM company
Company NumberCompanies House registration number
Registered AddressLines 1 & 2, city, postcode
DirectorsJSON array of director objects

Directors Format

Directors are stored as a JSON array. Each director object accepts:

[
  {
    "name": "Jane Smith",
    "role": "Director",
    "email": "jane@example.com"
  }
]

3. Apportionment

Control how the service charge budget is split between units in the block.

Apportionment Method

MethodDescription
EqualEach unit receives an equal share
By Floor AreaShares are proportional to each unit's floor area
CustomYou set each unit's percentage manually

Editing Percentages

The apportionment table lists every unit in the block with columns for unit number, floor, leaseholder name, and an editable percentage share.

  • Percentages are stored internally as basis points (1% = 100 basis points; 100% = 10,000 basis points).
  • A live total indicator shows the current sum and highlights any over- or under-allocation.
  • Saving is blocked until the total equals exactly 100.00%.

Distribute Equally

Click Distribute Equally to automatically split 10,000 basis points across all units. Any rounding remainder is distributed one basis point at a time to the first units in the list.

Saving Apportionment Changes

  1. Adjust each unit's percentage in the table.
  2. Confirm the total reads 100.00%.
  3. Optionally enter a reason for the change (e.g. "Lease extension", "Remeasurement").
  4. Click Save Apportionment.

Each save creates an immutable, versioned record in the audit history.

Change History

Click History to open the apportionment change history panel. Each record shows:

  • Version number and apportionment method in effect at the time
  • Timestamp of the change
  • Reason (if provided)
  • A full snapshot of every unit's basis points at that version

History is read-only and cannot be modified or deleted.


Data Model

block_settings table

One record per block. Created on first save, updated on subsequent saves.

ColumnTypeDescription
management_fee_typeenumfixed_annual or percentage_of_budget
management_fee_fixed_amount_penceintegerAnnual fee in pence (fixed type only)
management_fee_percentage_basis_pointsintegerFee as basis points (percentage type only)
billing_scheduleenummonthly, quarterly, or annual
financial_year_start_monthinteger1–12
auto_generate_invoicesbooleanDefault false
invoice_days_before_dueintegerDefault 14
payment_terms_daysintegerDefault 30
rmc_company_nametextOptional
rmc_company_numbertextOptional
rmc_address_line_1textOptional
rmc_address_line_2textOptional
rmc_citytextOptional
rmc_postcodetextOptional
rmc_directorstextJSON string; array of {name, role, email}
apportionment_methodenumequal, by_floor_area, or custom
notestextFree-text notes

apportionment_change_history table

Immutable append-only table. One record per apportionment save.

ColumnTypeDescription
block_idtextBlock the change belongs to
changed_bytextUser ID who made the change
apportionment_methodtextMethod in effect at time of change
snapshottextJSON array of {unitId, unitNumber, basisPoints} for all units
reasontextOptional reason text
versionintegerAuto-incremented per block

Both tables are protected by Row Level Security (RLS) for multi-tenant isolation.


API Reference (tRPC)

blockSettings.getByBlockId

Fetch the settings record for a block.

const settings = await trpc.blockSettings.getByBlockId.query({ blockId });
// Returns the settings object, or null if not yet configured.

blockSettings.upsert

Create or update block settings. Admin only.

await trpc.blockSettings.upsert.mutate({
  blockId: "blk_abc123",
  managementFeeType: "fixed_annual",
  managementFeeFixedAmountPence: 250000, // £2,500.00
  billingSchedule: "quarterly",
  financialYearStartMonth: 4,
  autoGenerateInvoices: true,
  invoiceDaysBeforeDue: 14,
  paymentTermsDays: 30,
  apportionmentMethod: "custom",
});

All fields except blockId are optional on update — only supplied fields are changed.

blockSettings.getApportionment

Fetch apportionment data for all units in a block.

const data = await trpc.blockSettings.getApportionment.query({ blockId });
// data.units — array of units with apportionmentBasisPoints
// data.total — sum of all basis points
// data.isComplete — true if total === 10000

blockSettings.updateApportionment

Atomically update all unit apportionments. Validates the sum equals exactly 10,000 basis points (100%). Creates a versioned history record. Admin only.

await trpc.blockSettings.updateApportionment.mutate({
  blockId: "blk_abc123",
  entries: [
    { unitId: "unit_1", basisPoints: 5000 }, // 50%
    { unitId: "unit_2", basisPoints: 5000 }, // 50%
  ],
  reason: "Initial configuration",
});
// Returns { version: 1 }

blockSettings.apportionmentHistory

Fetch versioned change history.

const history = await trpc.blockSettings.apportionmentHistory.query({
  blockId: "blk_abc123",
  limit: 10,
});
// Returns array of history records, newest first.

Compliance Notes

  • Fee isolation — Management fee income is configured here but must never be deposited into a client money account. The platform enforces this separation.
  • Apportionment audit trail — Every change to unit apportionments creates an immutable versioned record. History cannot be edited or deleted.
  • Audit logging — All upsert and updateApportionment calls are recorded via logAudit().