Salesforce · Custom Development

Customise around the package. A firm that cannot take an upgrade has bought a fork.

Litify ships releases. Every piece of custom work you add either survives them or quietly makes the next one harder, and the difference is architectural rather than a matter of care. We build the things the package does not do — custom objects, screens, logic and UI — in a way that leaves the vendor's upgrade path intact. Extend around it, never into it.

Extension Architecture
THE MANAGED PACKAGE Litify Objects & Fields Intake · Matter · Plan · Invoice Litify Logic & UI Shipped by the vendor Package Upgrade Path Vendor Release Notes Namespace Boundary YOUR EXTENSION LAYER Custom Objects Related to, never replacing, the package Apex & Logic Around the package, bulk-safe, tested LWC & UI Screens the package does not provide NOTHING THE VENDOR SHIPS IS TOUCHED 2πr WHAT STAYS TRUE Upgrades Stay Routine A release is a check, not a project Your Work Survives Nothing to rebuild after an upgrade One Codebase Documented, tested, owned by you
0
Vendor components modified, on any engagement
200
Records every piece of Apex is tested against
12+
Years of Salesforce delivery
40+
Consultants, architects & developers

Trusted by 500+ organizations — including law firms and legal technology companies building their case, billing and reporting operations on Salesforce with Twopir Consulting.

Social Justice Collaborative
Bernstein Liebhard LLP
LegalZoom
Sterling Law Offices, S.C.

Development Capability

  • Salesforce Partner
  • Apex
  • Lightning Web Components
  • Custom Objects
  • Screen Flows
  • Async & Batch
  • Test Coverage
  • Upgrade-Safe Design
How Customization Goes Wrong

Six ways custom work turns into technical debt

None of these are visible on the day they ship. They surface at the next vendor release, the next sandbox refresh, or the next time someone has to change the code — and by then the person who wrote it has gone.

Logic written to replace the package, not extend it

A custom matter object built because the standard one was inconvenient. Now every Litify feature, every integration and every vendor improvement bypasses your firm entirely, and you maintain a parallel product.

Hard dependencies on package internals

Apex referencing package fields by assumed API name, or logic that depends on how the vendor currently implements something. It works until the release where they change it, and the failure is opaque.

Code that was never bulk-tested

An Apex trigger that works on a single record and fails on a data load. It passes every manual test, then takes out a migration or a mass billing run — the two moments when failure is least affordable.

Custom UI rebuilt from scratch

A Lightning Web Component that reimplements what a record page and a Screen Flow would have done. More code, more maintenance, no more capability, and one more thing to retest on every release.

No tests worth the name

Coverage achieved by asserting nothing. It satisfies the deployment gate and tells you nothing about whether the code works, which you discover the first time somebody changes it.

One person understood it, and they left

Undocumented custom work is a liability whoever wrote it. The firm ends up afraid to touch a component that nobody can explain, and eventually pays to rebuild something that was working.

The Governing Constraint

Litify is a managed package. That decides everything.

A managed package is code and configuration installed into your org and owned by the vendor, sitting in its own namespace. You cannot edit what is inside it, and you should not want to: the namespace boundary is exactly what lets Litify ship a release into thousands of orgs without breaking them. Customising Litify therefore always means building alongside the package, in your own namespace, using the platform's extension points.

Those extension points are generous. You can add custom objects that relate to Litify's. You can add custom fields to package objects where the vendor allows it. You can write Apex that operates on package data, build Lightning Web Components that appear on package record pages, add Flows, validation rules, page layouts and permission sets. Almost anything a firm actually needs is reachable without touching a vendor component.

The discipline is knowing where the line is and staying behind it, even when crossing it would be quicker this week. Custom work that depends on package internals — an assumed API name, an implementation detail, a field the vendor might repurpose — is the debt that surfaces at the worst moment. We write defensively for that reason, and we verify the real object and field names in your org rather than trusting public sources, which disagree with each other.

Custom Objects

New objects related to Litify's, for data the package has no home for.

Lightning Web Components

Screens and interactions the package does not provide, on its record pages or your own.

Apex

Logic that has to run at volume or express rules Flow cannot, bulk-safe and tested.

Screen Flows

Guided multi-step processes, built declaratively wherever an LWC would be overkill.

Custom UI

Consoles, calculators and views designed around a task rather than around a record.

Experience Cloud

Client and referral-partner portals built on Litify data with the sharing model respected.

Test Coverage

Tests that assert real behaviour under bulk, not coverage achieved by asserting nothing.

Upgrade Safety

A release check in a sandbox before every Litify version reaches production.

Before You Build

Three questions we ask before writing any code

Most customization requests have a cheaper answer than the one they arrived with. We work through these in order, and we are genuinely happy to conclude that no code is needed.

Question 01 · Necessity

Can configuration already do this?

The answer is yes more often than firms expect. A well-built matter plan, a Screen Flow and a good page layout reach a long way, and every piece of code avoided is one less thing to maintain and retest.

  • What the package already does, checked properly
  • What a Screen Flow would cover
  • What a page layout or dynamic form solves
  • Whether a validation rule is the real answer
  • Whether an AppExchange app already exists
  • The honest cost of building versus configuring

Outcome Frequently: no code. We would rather tell you that in a scoping call than bill for a component you did not need.

Question 02 · Placement

Where does it sit relative to the package?

Alongside, always — but the detail matters. A custom object related to Matter behaves very differently from one that duplicates it, and the choice is hard to reverse later.

  • Custom object versus custom fields on the package
  • Relationship design and sharing implications
  • Whether reporting will still work across both
  • Effect on existing integrations
  • What a package upgrade could touch
  • Migration path if the vendor ships it later

Outcome A placement decision with its reasoning recorded — including what happens if Litify ships this capability natively in a future release.

Question 03 · Longevity

Who maintains this in two years?

Custom work is a permanent commitment. If your team cannot maintain it and you do not want a permanent retainer, that changes what we should build and how.

  • Your team's Salesforce capability, honestly assessed
  • Documentation and handover expectations
  • Test coverage sufficient for safe change
  • How configuration-driven it should be
  • Release testing responsibility
  • What happens when requirements change

Outcome A build shaped around who owns it. Sometimes that means more configuration and less code, deliberately, even though it takes longer to build.

Which tool to use for which Litify customization job, and why the obvious alternative is worse
What you wantWhat it should be built withType
A field the package does not haveA custom field on the package object where the vendor permits it, otherwise on a related custom object.Configuration
A guided multi-step process for staffA Screen Flow. Declarative, maintainable by an admin, and no code to retest on every release.Configuration
Data the package has no home forA custom object related to Matter or Intake — never a replacement for either of them.Custom object
A purpose-built console or calculatorA Lightning Web Component, with Apex behind it only where it must query or write at volume.LWC
Logic across thousands of recordsApex, batched and bulk-safe, with tests that assert real behaviour rather than chasing coverage.Apex
A client or referral-partner portalExperience Cloud over Litify data, with the org sharing model enforced rather than reimplemented.Experience Cloud
What We Build

Six kinds of custom work, and when each is justified

Every one of these is something the package does not do. If a request can be met by configuration, it does not belong on this list and we will say so.

Custom Objects & Data Model

For data Litify has no home for — a referral fee structure, a lien tracker, a practice-specific record. Related to the package objects, never replacing them.

  • Object and relationship design
  • Sharing and visibility inherited properly
  • Reporting across custom and package data
  • Effect on existing integrations assessed
  • Migration path if Litify ships it natively
  • Naming that will still make sense later

Lightning Web Components

Where the interaction is genuinely richer than a record page or Screen Flow can express — an intake console, a settlement calculator, a triage board.

  • Component design against a real task
  • Apex behind it only where volume demands
  • Placed on package record pages where useful
  • Accessible and keyboard-navigable
  • Jest tests alongside Apex tests
  • Styled to the org, not to a framework default

Apex Development

Logic that must run at volume or express rules configuration cannot. Written to the platform's standards because the standards exist for good reasons.

  • Bulkified to 200 records as a baseline
  • No SOQL or DML inside loops, enforced in review
  • Queueable and Batch for async work
  • Selective queries against indexed fields
  • Tests that assert behaviour, not coverage
  • Defensive against package field changes

Screen Flows & Guided Processes

Declarative first. A Screen Flow your admin can change beats a component only we can change, and it survives releases with less testing.

  • Multi-step intake and triage screens
  • Conditional paths by case type
  • Reusable sub-flows for common steps
  • Error handling and fault paths
  • Built for admin maintainability
  • Documented for the person who inherits it

Portals & External Experiences

Client and referral-partner access to matter data, built on Experience Cloud so the org's sharing model is enforced rather than reimplemented in application code.

  • Experience Cloud site over Litify data
  • Sharing model enforced, never bypassed
  • Document upload into the matter
  • Status visibility without internal detail
  • Authentication and identity design
  • Mobile-usable, because clients are on phones

Technical Debt Remediation

Inherited custom work that nobody can safely change. We make it explicable before we make it better.

  • Inventory with ownership and last-modified
  • What is load-bearing versus what is dead
  • Test coverage added before refactoring
  • Package dependencies identified and removed
  • Safe retirement of unused components
  • Documentation so it stops being a liability
Upgrade Safety Rules

Six rules that keep vendor releases routine

These are the difference between a Litify upgrade being a sandbox check and a Litify upgrade being a project. Each one exists because its absence has cost somebody a weekend.

Never Modify What The Vendor Ships

The namespace boundary exists for a reason and we stay behind it, without exception. Anything that would require editing a package component is redesigned rather than forced.

Protects The entire upgrade path. One modified vendor component is the difference between an upgrade and a migration.

Verify API Names In The Org

Public sources disagree on Litify's namespace and custom API names, and the authoritative reference sits behind a customer login. We query the org and work from what it reports.

Protects Against code that compiles against an assumed field name and fails in an org where it is different.

Depend On Data, Not Implementation

Custom logic reads package data through supported interfaces. It does not rely on how the vendor currently implements something internally, because that is theirs to change.

Protects Against the release where an internal detail changes and your logic fails in a way nobody can trace.

Configuration In Metadata

Thresholds, mappings and rules live in custom metadata records rather than hard-coded. Behaviour changes without a deployment, and without a developer.

Protects Against a change queue for values the business should be able to edit itself on a Tuesday.

Tests That Assert Behaviour

Real assertions under bulk conditions, not coverage achieved by exercising code and checking nothing. The test suite is what makes the next change safe.

Protects Everyone who touches the code after us — including your own team, which is the point.

Release-Check Every Version

Litify releases go into a sandbox first and custom components are exercised against them before production. A routine check, scheduled, rather than a discovery after the fact.

Protects Against finding out that a release broke something from a user on a Monday morning.
How We Deliver

Five phases, and the first one often ends the project

We start by trying not to build. It is the cheapest phase and it regularly saves firms more than the rest of the engagement costs.

Phase 01

Challenge The Requirement

What the package already does, what a Screen Flow would cover, whether an AppExchange app exists. A genuine attempt to avoid writing code, because code is a permanent commitment.

Phase 02

Verify The Org

Real object and field names, package version, existing custom components and their dependencies. Public sources on Litify API names are unreliable; your org is authoritative.

Phase 03

Design For Upgrade

Placement relative to the package, sharing and reporting implications, what a future vendor release could touch, and the migration path if Litify ships the capability natively.

Phase 04

Build & Test

Built to platform standards, bulk-tested to 200 records, with tests that assert behaviour. Code review on every change, against the rules above.

Phase 05

Document & Hand Over

Documentation your team can act on, a release-check procedure, and enough test coverage that the next person can change it safely without us.

Why we try to talk you out of it first Custom code is a permanent commitment: it has to be maintained, retested on every vendor release, and understood by whoever inherits it. Configuration carries almost none of that weight. We routinely find that a request arriving as "we need a custom component" is met by a Screen Flow, a dynamic form and a validation rule — and we would rather establish that in a scoping call than bill for something you will still be maintaining in 2029.

When Code Is The Answer

Four situations configuration genuinely cannot reach

These are the cases where we stop trying to avoid code. Everything else deserves one more attempt at a declarative answer first.

Volume Beyond Flow

Logic that has to run across thousands of records. Flow hits limits here and fails in ways users see; this is what Batch and Queueable Apex exist for.

A Screen That Is Not A Record Page

An intake console, a settlement calculator, a triage board. When the interaction is organised around a task rather than a record, a component earns its place.

Data With No Home

Lien tracking, referral fee structures, practice-specific records. A custom object related to Matter, never a replacement for it.

External Users

Clients and referral partners needing access to matter data. Experience Cloud over Litify, with the sharing model enforced rather than reimplemented.

Client Outcomes

Legal platforms we have actually built

Two engagements from our legal practice. Both involved custom Salesforce development around packaged applications — built so the packages underneath could still be upgraded.

★★★★★
Twopir provided Salesforce customisation and integration services to help us build a robust, compliant, and scalable legal operations platform — connecting case management, document processing, and financial systems into one unified workflow. The result was transformative for how we run case-to-cash operations.
Operations Lead Fast-growing personal injury law firm Personal Injury
Case Study

Personal Injury Firm — Multi-State

Streamlining case-to-cash operations with Salesforce, AWS and QuickBooks.

40%+ Faster case-to-settlement processing
45% Reduction in reconciliation effort
35% Improvement in data accuracy
Read Full Case Study
★★★★★
Twopir's specialized Salesforce customization enabled efficient integration of third-party systems and streamlined administration and billing, leading to seamless financial operations and enhanced productivity. Automated mass billing and matter management minimized errors across our entire legal workflow.
Practice Manager Mid-size US family law firm · 150 employees Family Law
Case Study

Family Law Firm — 150 Employees, US

A 50% efficiency gain from Accounting Seed and Salesforce integration.

50% Increase in operational efficiency
45% Productivity gains from automation
35% Faster lead qualification & conversion
Read Integration Story
Why Twopir

Custom work you are not afraid to change

The measure of good custom development is whether the next person can safely modify it. Most inherited Salesforce code fails that test, and the firm pays for it twice.

We try not to build first

Configuration reaches further than most firms expect, and every piece of code avoided is one less thing to maintain and retest on every vendor release. We are happy to end a scoping call by recommending a Screen Flow.

We extend around the package, never into it

Custom objects, Apex, Flow and Lightning Web Components built so the vendor's next release upgrades cleanly. A firm that cannot take a Litify upgrade has bought a fork, not a platform.

We verify your org instead of assuming it

Litify's object and field reference sits behind a customer login, and public sources disagree on details as basic as the namespace prefix. We confirm the real objects, fields and package version in your org in week one — and we say so rather than quoting from a blog post.

Tests that assert behaviour, not coverage

Coverage achieved by asserting nothing satisfies the deployment gate and tells you nothing. Our tests assert real behaviour under bulk conditions, because the test suite is what makes the next change safe.

We document for the person who inherits it

Custom work only one person understands is a liability whoever wrote it. Documentation and handover are part of the build, not an optional extra we quote separately.

Common Questions

Answers before the first call

It can be customised extensively — you simply do it alongside the package rather than inside it. A managed package sits in the vendor's own namespace and its components cannot be edited, which is precisely what allows Litify to ship releases into thousands of orgs without breaking them. But you can add custom objects related to Litify's, add custom fields to package objects where the vendor permits, write Apex that operates on package data, build Lightning Web Components that appear on package record pages, and add Flows, validation rules, layouts and permission sets. Almost anything a firm actually needs is reachable without touching a vendor component.

Not if it is built correctly, and this is the single most important thing to get right. Custom work that lives in your own namespace and depends only on supported interfaces upgrades cleanly. Custom work that depends on package internals — an assumed API name, an implementation detail, a field the vendor might repurpose — is the debt that surfaces at the worst possible moment. We write defensively, verify the real object and field names in your org rather than trusting public sources, keep configuration in custom metadata, and run a release check against each Litify version in a sandbox before it reaches production.

Four situations genuinely justify code. Logic that must run across thousands of records, where Flow hits governor limits and fails visibly. A screen organised around a task rather than a record — an intake console, a settlement calculator. Data the package has no home for, which needs a custom object related to Matter rather than a replacement for it. And external users needing access, which means Experience Cloud. Everything else deserves another attempt at a declarative answer first, and we will make that attempt before quoting for a build.

Yes, and the sequence matters. We inventory what exists with ownership and last-modified dates, establish what is load-bearing versus what is dead, and add test coverage before refactoring anything — because changing untested inherited code is how a working system becomes a broken one. We identify and remove hard dependencies on package internals, retire unused components safely, and document what remains. The goal is that your team stops being afraid to touch it, which is usually the real problem.

Yes, on Experience Cloud over Litify data. The critical design principle is that the sharing model is enforced rather than reimplemented: a portal that queries data with elevated permissions and filters in application code is one bug away from showing a client someone else's matter. Built properly, external users see exactly what the org's sharing rules permit. Typical scope covers matter status visibility, document upload into the matter, secure messaging and online payments, and it has to work on a phone because that is where clients are.

The platform's own, because they exist for good reasons. Bulkified to 200 records as a baseline and tested at that volume. No SOQL or DML inside loops, enforced at code review. Queueable and Batch for asynchronous work rather than blocking a user transaction. Selective queries against indexed fields. Configuration in custom metadata rather than hard-coded, including no literal record type or Case Type IDs. And tests that assert real behaviour under bulk conditions, not coverage achieved by exercising code and checking nothing.

Workflow and automation covers declarative work inside the org — matter plans, Salesforce Flow, validation rules, assignment and escalation logic. This page covers what happens when those genuinely cannot reach: custom objects, Lightning Web Components, Apex that is not integration code, and portals. There is real overlap at the boundary, which is why both pages say the same thing about it — configure first, code only where configuration cannot reach. If you are not sure which side of the line you are on, that is a scoping conversation and usually a short one.

Next Step

Tell us what you want to build — we will start by trying to avoid building it

A technical scoping conversation covers what you need, whether configuration already reaches it, and if not, how it should be placed relative to the package so upgrades stay routine.

Challenge the requirement · verify the org · design for upgrade · test · hand over