Skip to Content
HelpDocuments & TemplatesMigrating V1 to V2

V1 to V2 Migration Guide

This guide covers the differences between V1 (Mail Merge) and V2 (Tag Templates) in ScopeStack, and how to convert your existing templates.

Syntax Change

V1 templates use Mail Merge syntax with double angle brackets:

<<project_name>> <<tasks:each(task)>> <<task.name>> <<tasks:endEach>>

V2 templates use tag syntax with curly braces:

{project.project_name} {#services} {name} {/services}

Top-Level Structure

V1 merge data has approximately 90 flat keys at the root level. V2 organizes these into 8 structured sections:

V2 SectionContains
projectProject details, client, contacts, sales exec, account info
locationsService hierarchy (locations, phases, services)
currencyCurrency settings
language_fieldsLanguage and sentence blocks
project_pricingFinancial rollups and breakdowns
project_paymentsPayment schedule
survey_responsesSurvey data
metaData format identifier (data_format: "v2")

Entity Renames

These names changed between V1 and V2:

V1 TermV2 TermWhere it appears
tasksservicesArray and loop names
featuressubservicesArray and loop names
resourceresource_nameField inside service and pricing loops
task_typeservice_categoryCategory name on services

Service Hierarchy

V1: Services are nested as locations > lines_of_business > tasks

V2: Services are nested as locations > phases > services

Both versions support the template path locations > phases > services because the render engine synthesizes phase nesting automatically. If your V1 template already uses locations > phases > tasks, changing tasks to services may be all you need.

Value Format Changes

V2 returns raw numbers instead of pre-formatted strings:

FieldV1 ValueV2 Value
total_revenue"$1,128.15"1128.15
service_revenue"$981.00"981.0
total_cost"$388.13"388.13
total_hours"4.5" (string)4.5 (number)

In V2, use the toFixed filter to format numbers:

Revenue: {total_revenue | toFixed:2}

If a field returns a string that needs numeric formatting, multiply by 1 first:

{project_pricing.total_contract_value * 1 | toFixed:2}

Deduplication Changes

V1: Each task has a unique? boolean flag. The phases_with_tasks section provides a unique_phase_tasks array for per-phase dedup.

V2: Each service has a unique boolean flag. Do not use unique? in V2 templates — the ? character crashes the template parser. Use unique (without the question mark) instead.

V2 also adds unique_count, which gives you the total number of services with the same name:

{#services} {#unique} ({unique_count}) {name} {/unique} {/services}

V2 eliminates phases_with_tasks and unique_phase_tasks. Deduplication is handled by the unique flag on individual services instead.

Important: Deduplication is global, not per-location or per-phase. A service name appearing in multiple locations only gets unique: true on the first occurrence across the entire project.

Language Fields

V1 has approximately 30 inline language fields on each service (sow_language, deliverables, out, assumptions, formatted_deliverables, etc.).

V2 consolidates all of these into a nested language_fields array on each service. To access a specific language field in V2:

{#language_fields} {#name=="Deliverables"} {~~formatted_sentences} {/name=="Deliverables"} {/language_fields}

Rich Text Fields

V2 uses the ~~ prefix for fields that contain HTML or markdown:

{~~project.formatted_executive_summary} {~~formatted_service_description}

Without ~~, HTML tags appear as raw text in the output.

Migration Checklist

  1. Rename all tasks references to services
  2. Rename all features references to subservices
  3. Rename resource to resource_name in pricing/service loops
  4. Replace unique? with unique in dedup filters
  5. Replace pre-formatted currency values with toFixed:2 filter calls
  6. Replace inline language fields with language_fields loop and name equality checks
  7. Add ~~ prefix to all formatted/rich text fields
  8. Test with the merge data visualization page (set version to V2) to verify field paths
Last updated on