Data Contracts
Model application data with document types and indexes.
The ticket marketplace starts with no records and a pile of future questions. Before Bob lists anything, decide what the app must store by writing down what people will ask:
- Which tickets are still on sale for events in my city, ordered by start time?
- Which tickets have been sold for one event?
Those reads are more useful than a list of fields pulled from thin air. They tell you which records the app needs, what facts each record must carry, and how Platform must organize them for retrieval.
Two questions, two families
An event and a ticket describe different things. An event has a title, city, status, and start time. A ticket connects one seat to one event and records who owns it and what it costs. Mixing both into one kind of record would make every ticket repeat the event details, while every event carried seat details it didn't need.
Give the contract two document types instead: event and ticket. A document type is one family of records governed by the same rules. One event document might describe Saturday's show; each ticket document stands for one seat at it.
For each family, its schema states what a valid record looks like. The event schema can require a title, city, status, and start time, with rules for the kind of value each field accepts. The ticket schema can require an event reference, a seat, and a price. If a submitted record is missing a required value or gives a value of the wrong kind, Platform refuses it.
A data contract gathers these document types and their schemas. It doesn't contain the events themselves. It supplies the rules that every event and ticket must satisfy.
Let the first read shape the event
Return to the first question: "Which tickets are still on sale for events in my city, ordered by start time?"
The event documents need city, status, and startTime because the answer depends on those values. Keeping only a venue name and hoping to derive its city later won't give this read what it needs.
The document type also needs an index covering that intended read. An index organizes selected fields of one document type so Platform can retrieve records by those fields. Here, an index over city, status, and start time supports Alice's city listing of open events in time order.
An index isn't an after-the-fact speed setting. Filtered or ordered document reads such as this one depend on fields covered by an index, so an omitted index can leave the app unable to ask a planned question. This is why the read came first: it exposed both the fields and the index the event model needs.
The second question does the same job for ticket. To find the tickets for one event, each ticket stores that event's identifier in an eventId field, and the ticket type declares an index that starts from that relationship. The event reference isn't useful only as a link for the interface; it's data the app needs to search.
A relationship isn't a join
Now Bob proposes splitting venues into a third document type while keeping the city search. Each event would store venueId, the venue record would carry the city, and you might expect Platform to combine both types during one read.
Platform document queries don't expose relational joins between document types. A query targets one contract and one document type, so following venueId doesn't pull the venue's city into an event search.
There are two honest designs. The app can fetch venue and event records separately, then combine them in its own code. Or, if searching events by venue city is a required read, each event can also carry the city value and include it in the event type's index. That duplicates a fact, and the application must keep the copies consistent, but the searched record now contains the field the read depends on.
This is a read-oriented choice, not an instruction to copy every related field. Store a relationship identifier when separate reads are acceptable. Put query-critical relationship data on the searched document when the app must answer from that type directly.
When the last seat goes
Bob adds one more rule: when sold tickets reach the event's capacity, change its status to soldout and notify the waiting list. Can the contract run that reaction whenever a ticket sells?
No. A schema validates the record presented to it; it doesn't count related tickets and then update another document. Platform has protocol-defined behavior for its own system contracts, but ordinary app developers can't attach custom data triggers to their contracts.
The marketplace must own that reaction. Its code can read the relevant tickets, decide whether capacity has been reached, submit the event change, and send notifications. The contract still has a useful job: it can reject malformed events and tickets. It just isn't uploaded business logic.
That boundary also affects what the app can promise. A schema can require a numeric capacity and a recognized status value. By itself, it can't guarantee that the status changes at the exact moment the final ticket sells, because that guarantee depends on application code outside the contract.
Decide while the questions are cheap
Before publication, changing event from a sketch to a better model costs little. After publication, contract updates are constrained. Platform permits some compatible additions, but you shouldn't assume that a missing field or index can later be added in whatever form a new read requires.
Walk through the marketplace's expected screens and ask what each one must retrieve. For every filtered or ordered read, identify the document type being searched, make sure that type carries the facts needed to answer, and plan its index. Then check the boundaries: any combination across types or reaction to a write belongs in application code unless the records themselves have been shaped to avoid it.
Check your understanding
Restoring your progress…
4 correct to pass