Nothing else in this lab works if this module is wrong, and none of it is difficult. That combination is exactly why it is worth doing slowly.

You are going to make three decisions that are expensive to reverse later: where the components live, what a ticket is, and how an update knows which ticket it belongs to. Every module after this one configures something on top of those three answers.

Outcome. A dedicated solution containing a Support Ticket table, a Ticket Update table, and a lookup relationship joining them.

Time. 45–65 minutes, and the longest module in the lab. Each of the three checkpoints below is a safe place to stop and come back.

Starting point. A Power Platform environment with Dataverse, and a role that can create solutions and tables: Environment Maker, System Customizer, or System Administrator. Use a development or training environment, never production. New to the lab? Start at the overview.

Why the solution comes first

Before you build anything, decide where it lives.

A solution is a container for application components and their dependencies: tables, columns, relationships, forms, views, business rules, process flows, the app itself. It is the unit that moves between environments. Build outside one and your work still functions, but it has no transport boundary, and assembling it later means hunting for pieces you no longer remember creating.

The default solution is genuinely useful for discovery and administration. It is a poor day-to-day development boundary, because every unrelated customization in the environment accumulates there too.

  1. Open the Power Apps maker portal and confirm the correct environment is selected. Check this every time you return to the lab; it is the single most common cause of “my changes vanished.”
  2. Select Solutions, then New solution.
  3. Enter:
PropertyValue
Display nameSupport Ticket Learning Lab
NameSupportTicketLearningLab
PublisherAn existing training publisher
Version1.0.0.0
  1. Select Create, then open the new solution.

The publisher is not a formality. It owns the customization prefix that gets stamped onto every schema name you create in this lab, so a column you name Ticket Age in Days becomes something like new_TicketAgeinDays underneath. That prefix becomes part of the contract any integration depends on, which is why production teams choose a publisher deliberately rather than accepting whatever is default.

Checkpoint. The solution is open, its publisher and version are visible, and it is empty. Empty is correct; everything from here is created inside it. Safe to stop here.

The Support Ticket table

A table gives a business concept a governed schema: stable identity, security, relationships, views, reusable metadata. Use typed columns to constrain meaning, and free text only where narrative flexibility is the actual requirement.

  1. From inside the solution, select New, then Table, then Table again.
  2. Enter:
PropertyValue
Display nameSupport Ticket
Plural nameSupport Tickets
Primary columnTicket Title
OwnershipUser or team
  1. Enable Activities where the option appears.
  2. Save.

Enabling Activities is doing one specific thing to your future: it adds the platform’s activity machinery to this table, which is why a Timeline component becomes available when you build the form in module 2. That component is not the one you want there, and module 2 explains why at the point where it would mislead you. It is enabled here because a realistic support-ticket table would have it, and because meeting the trap is more instructive than avoiding it.

The primary column identifies the row in lookups and throughout model-driven experiences. It is the ticket’s short title here, not its ticket number, because a human-readable name makes every lookup and navigation breadcrumb legible.

Now the columns. Open the table’s Columns area and create each of these:

Display nameData typeNotes
Ticket NumberAutonumberFormat TKT-{SEQNUM:5}, producing TKT-00001
DescriptionMultiple lines of textOptional
Ticket StatusChoice (local)Values: New, In Progress, Resolved. Default New
PriorityChoice (local)Values: Low, Normal, High, Critical. Default Normal
Resolution NotesMultiple lines of textLeave optional
Resolved OnDate and timeOptional

Two of those choices deserve their reasoning stated.

Resolution Notes stays optional at the schema level on purpose. The requirement is that it becomes mandatory when a ticket resolves, not always. Making it permanently required here would block every valid New and In Progress ticket. Module 3 makes it conditional, which is the correct place for a conditional rule.

Ticket Status is your own choice column, not the platform’s. Every Dataverse table already ships with system state columns, usually surfaced as Status and Status Reason and stored as statecode and statuscode. They govern whether a row is active or inactive, and they carry platform behaviour you do not want to redesign in a first lab. Your Ticket Status is a separate business column that happens to describe a similar idea. Keeping them separate is deliberate; conflating them is a genuine source of confusion in real projects.

Checkpoint. The table lists Ticket Title, Ticket Number, Description, Ticket Status, Priority, Resolution Notes, Resolved On, and the system-generated Created On. Ticket Status and Priority show their choice values. Resolution Notes is not required. Safe to stop here.

The Ticket Update table and the lookup

One ticket accumulates many updates. Each update belongs to exactly one ticket. That sentence determines the entire design.

Create the child table:

  1. Solution, New, Table, Table.
  2. Enter:
PropertyValue
Display nameTicket Update
Plural nameTicket Updates
Primary columnUpdate Title
OwnershipUser or team
  1. Save, then add one column: Update Details, Multiple lines of text, Business required.

Now the relationship. This is the step everything else depends on:

  1. In the Ticket Update table, select Columns, then New column.
  2. Enter:
PropertyValue
Display nameSupport Ticket
Data typeLookup
Related tableSupport Ticket
RequiredBusiness required
  1. Save.

Read where that lookup lives, because the placement is the design. The lookup sits on Ticket Update, the child. That is what allows many update rows to point at one ticket:

Support Ticket  1 ─────────< N  Ticket Updates

Put the lookup on the parent instead and a ticket could reference exactly one update, which reverses the cardinality you actually need. Making it Business required is what stops an update from existing without a parent, which would be a row nobody can find and no ticket-centric report can see.

Checkpoint. Ticket Update exists with a required Update Details and a business-required Support Ticket lookup. Dataverse now exposes a one-to-many relationship from Support Ticket to Ticket Update, and the next module uses it twice: once to show updates on a form, and once to count them.

Troubleshooting

SymptomCause and fix
New solution is unavailableConfirm the environment has Dataverse and your role includes customization privileges.
The expected publisher is missingUse an approved existing publisher, or ask an environment administrator to create one.
Autonumber options do not appearSet the data type to Autonumber first; the format field appears afterwards.
A choice value does not show upSave the choice definition and the column, then refresh the designer.
The related table is not listed for the lookupSave and publish the Support Ticket table, then reopen the lookup designer.
New columns do not appear on any formExpected. Columns and form placement are separate operations; forms come in module 2.
Knowledge Check
  1. What problem does a solution solve that simply creating tables does not?
  2. Why are Ticket Status and Priority choice columns rather than text?
  3. Why is Ticket Number not the primary column?
  4. On which table does the Support Ticket lookup physically live, and what would break if it lived on the other one?
  5. What is the difference between making Resolution Notes permanently required and conditionally required?
Architecture Review

Why a separate child table rather than one long multiline field on the ticket: separate rows carry their own timestamps, ownership, security, and reporting grain. You can count them, filter them, and later add an update type or a customer-visible flag. Text in a single field can do none of that.

Production note. Real models also decide cascade behaviour on the relationship, delete restrictions, auditing, alternate keys, field-level security, retention, and whether choices should be global for reuse across applications. Decide those before integrations start depending on schema names, because schema names are the contract.

Stretch. Add an Assigned Support Team lookup and a global Support Tier choice. Explain why each is a relationship or a shared choice rather than free text.

Review scenario. A developer proposes storing Priority as text because integrations might send any value. What do you say, and where does the normalization belong instead?

Stopping point

Safe to stop here. You have a transport boundary, two tables, and the relationship that joins them. Module 2 turns all of it into something a person can actually use.