There actually example in the seed address page:

Have you seen it? Long story short, the targetData represents an XML that you are throwing on a delivery template to produce actual delivery and it maps to a temporary table schema. Any table column will become an attribute with the same name and any linked table will create a nested element with tag name equal to link name and attribute names, equal to linked table columns.
The delivery template will load these elements and attributes only if they are mention directly in JSSP tag. For example, the following expression will load @providerName column of a linked provider table.
<% var providerName = targetData.provider.providerName %>
But the following expression will only load provider @_cs and @providerName will be undefined:
<%
var provider = targetData.provider
var providerName = provider.providerName
%>
as for <%= recipient.firstName %>, you do not have to do anything, because the recipient is default Adobe table, and recipient record is always loaded if a recipient is targeted in the delivery.
Please check out this doc: Personalization fields