Entities: the nouns of the system
An entity is a business object the application stores: Account, Policy, Claim, Invoice, Contact. Each entity is defined in metadata (XML files), and from that definition the platform generates three things:
- a database table with a column for each field,
- a Gosu type developers can use in code (
claim.LossDate), - the plumbing to load, save and validate the object.
Entity fields come in a handful of kinds:
| Kind | Meaning | Example |
|---|---|---|
| Column | A plain value: text, number, date, money, boolean | Claim.LossDate |
| Typekey | A value from a typelist (a code) | Claim.State = open |
| Foreign key | A pointer to one other entity | Exposure.Claim |
| Array | A one-to-many list of child entities | Claim.Exposures |
| One-to-one | A single child that lives with the parent | A policy's primary location detail |
"Each claim can have several exposures, and each exposure belongs to one claimant" is a data model sentence: an array from Claim to Exposure and a foreign key from Exposure to a Contact. Getting used to translating requirements this way makes BA–developer conversations much shorter.
Typelists: controlled vocabularies
A typelist is a fixed list of codes, each with a display name. Dropdowns, statuses and categories are almost always typelists. Examples: ClaimState (draft, open, closed), LossCause, CoverageCategory.
- Each entry is a typecode with a code, a display name, a description and a priority (sort order).
- Typecodes can be retired so they stop appearing for new data but old records stay valid.
- Categories and filters link typelists together, for example showing only the loss causes that make sense for the chosen line of business.
When you write a story with a dropdown, list the codes and display names as a table. Developers turn that table straight into a typelist extension, and the codes become the values integrations and reports rely on — so choose them carefully and never reuse a code for a different meaning.
Keys, public IDs and retiring
Every entity row has an internal ID (the database key) and usually a public ID, a string that is stable across systems. Integrations should exchange public IDs, never internal IDs, because internal IDs differ between environments.
Most business entities are retireable: instead of deleting a row, the platform marks it retired so history and references remain intact. Queries ignore retired rows by default.
| Behaviour | What the platform adds |
|---|---|
| Keyable | An ID and a public ID |
| Editable | Created/updated user and timestamp, plus a version for optimistic locking |
| Retireable | Soft delete with a retired flag |
Effective dating in PolicyCenter
A policy changes over its term — a new driver from 1 March, a different car from 15 June. PolicyCenter has to answer "what did the policy look like on 20 April?" It does this with effective-dated entities.
- Effective-dated rows carry an effective date and an expiration date.
- A change creates new versions of the affected rows from its effective date, leaving earlier versions untouched.
- Reading the policy "as of" a date returns the slice of rows valid on that date.
- 1 JanIssuedOne driver, one car.
- 1 MarPolicy changeSecond driver added from this date.
- 15 JunPolicy changeCar replaced from this date.
- 31 DecTerm endsThree slices, one policy period.
BillingCenter and ClaimCenter don't use effective dating in the same way. ClaimCenter instead stores a snapshot of the policy as it was on the loss date. You'll see both ideas again in the PolicyCenter and ClaimCenter modules.
Bundles and transactions
Changes in Guidewire are made inside a bundle: a set of entity changes that are committed to the database together, or not at all. When a user clicks Update on a screen, everything they edited in that screen is in one bundle.
- Rules such as pre-update and validation run as the bundle commits, so they can see all the changes together.
- If validation fails, the whole bundle is rejected and the user sees the errors.
- Integration messages created during the commit are saved in the same transaction, so a message is never sent for a change that didn't happen.
In Gosu, background code that changes data runs inside an explicit bundle, typically with gw.transaction.Transaction.runWithNewBundle(\ bundle -> { ... }). Module 14 covers extending entities and module 15 covers the rules that run on commit.
The core entities per app
PolicyCenter
- Account
- Policy
- PolicyPeriod
- Job (Submission, PolicyChange…)
- PolicyLine, coverables, coverages
BillingCenter
- Account
- PolicyPeriod
- Charge
- InvoiceItem, Invoice
- Payment and money received
ClaimCenter
- Claim
- Exposure
- Incident
- Policy snapshot
- Reserve, payment, recovery transactions