Tessera is packaged and deployed exclusively using the SuiteCloud Development Framework (SDF). Every NetSuite object Tessera creates is defined as SDF XML and version-controlled in the product repository. There are no manual configuration steps during installation.
TesseraBI/ ← repo root
├── src/ ← TypeScript source (AMD target)
│ ├── mdl/ ← Metric Definition Layer modules
│ ├── crl/ ← Computed Result Layer modules
│ ├── dal/ ← Data Access Layer modules
│ ├── query/ ← Resolver and executor
│ ├── rendering/ ← Suitelet and portlet scripts
│ ├── security/ ← License and role validation
│ └── netsuite.d.ts ← Ambient NS module declarations
├── test/ ← Test source (CommonJS target)
│ └── tessera_*_test.ts ← Unit test files
├── suiteapp/ ← SDF project root
│ └── src/
│ ├── FileCabinet/
│ │ └── SuiteScripts/
│ │ └── Tessera/ ← Compiled + obfuscated JS bundles
│ ├── Objects/ ← SDF XML object definitions
│ │ ├── customrecord_*.xml ← Custom record type definitions
│ │ ├── customscript_*.xml ← Script record definitions
│ │ └── customrole_*.xml ← Role definitions
│ └── InstallationPreferences/
│ ├── hiding.xml ← Object access control at install
│ └── locking.xml ← Object modification control
├── scripts/
│ └── run_tests.sh ← Sequential test harness
├── tsconfig.json ← TypeScript config (AMD — SDF deployment)
├── tsconfig.test.json ← TypeScript config (CommonJS — test runner)
├── suiteapp.config.xml ← SuiteApp metadata
└── package.json
Tessera uses a two-stage build:
Stage 1 — TypeScript compilation
Two tsconfigs serve two purposes:
| Config | Target | Purpose |
|---|---|---|
tsconfig.json |
AMD | SDF deployment — NetSuite’s module loader expects AMD |
tsconfig.test.json |
CommonJS | Node.js test runner — Jest requires CommonJS |
"ignoreDeprecations": "6.0" is required in tsconfig.json to support AMD module format in TypeScript 6+.
Stage 2 — Obfuscation
Source modules in the MDL, DAL, and query layer are processed through a terser-based obfuscation pipeline before SDF deployment. This is part of Managed SuiteApp IP protection. PUBLISHERPREF: PROTECTED is set in suiteapp.config.xml.
Deployment
npm run build # TypeScript → AMD JS
# [obfuscation pipeline runs]
npm run deploy # suitecloud project:deploy from suiteapp/
The deploy target is always the sandbox account first. Production deployment is a separate manual step after sandbox validation.
All Tessera SDF objects use stable, prefixed internal IDs that will not collide with customer customizations or other SuiteApps.
| Prefix | Layer | Example |
|---|---|---|
custrecord_tess_ |
MDL (Metric Definition Layer) | custrecord_tess_metric_definition |
custrecord_tqc_ |
Query Component records | custrecord_tqc_filter_scope |
custrecord_crl_ |
Computed Result Layer | custrecord_crl_metric_result |
The custrecord_crl_ prefix is preserved as-is — it reflects the layer name, not the product brand, and changing it post-deployment would require data migration.
| Prefix | Example |
|---|---|
customscript_tessera_ |
customscript_tessera_portlet_kpi |
customdeploy_tessera_ |
customdeploy_tessera_portlet_kpi |
| Prefix | Example |
|---|---|
customrole_tessera_ |
customrole_tessera_controller |
| Prefix | Example |
|---|---|
custlist_tessera_ |
custlist_tessera_formula_pattern_type |
custrecord_tess_[record]_[field] |
custrecord_tess_md_approval_status |
| Script type | Count | Purpose |
|---|---|---|
| Suitelet | 3 | Metric Wizard host, drill-down renderer, Registry catalog |
| Portlet | 1 | KPI tile and chart display on NS dashboard |
| Map/Reduce | 1 | CRL scheduled computation fleet |
| User Event | 4 | CRL invalidation triggers, MDL invariant enforcement, baseline record immutability |
| Scheduled | 1 | CRL fleet dispatcher |
<allRoles>T</allRoles>
The portlet script deploys to all NetSuite roles. Access control is enforced in script logic via the Portlet Config record (R10) — not at the deployment level. See Security Model.
All User Event scripts include context.type guards to prevent execution during bulk CSV imports, web service operations, and mass updates:
if (context.type === context.UserEventType.XEDIT) return;
if (runtime.executionContext === runtime.ContextType.CSV_IMPORT) return;
if (runtime.executionContext === runtime.ContextType.WEBSERVICES) return;
This prevents governance flooding and interference with other SuiteApps running in the same account.
Tessera is distributed as a Managed SuiteApp. The Managed vs. Unmanaged selection in SuiteApp Control Center is irreversible and was made before the SuiteApp definition was created.
suiteapp.config.xml (relevant excerpt):
<publisherpreferences>PROTECTED</publisherpreferences>
InstallationPreferences/hiding.xml: Controls which SDF objects are visible to the installing account. Custom record type definitions and script source are hidden from customer inspection.
InstallationPreferences/locking.xml: Prevents customer modification of Tessera-owned objects post-install.
SDF installation is deterministic and idempotent. Running the same bundle version twice produces the same result. The install sequence:
Steps 7–8 run as a post-install bundle script. Mismatches are surfaced in the Tessera Admin console, not as installation errors — installation always completes.
Product upgrades are delivered as new SDF bundle versions. Customer data — metric definitions (R1–R5), computed results (R6), portlet configurations (R10), approval domain records (R7) — is stored in custom records and is unaffected by product upgrades.
Baseline library records (is_baseline: true) are updated by the upgrade bundle. Customer forks of baseline records are not overwritten. The upgrade process compares the new baseline against existing customer forks and flags drift in the Tessera Admin console.
All third-party libraries are bundled and served from NetSuite File Cabinet. No CDN dependencies exist at runtime.
| Library | License | Delivery |
|---|---|---|
| Apache ECharts 5.x | Apache 2.0 | Bundled JS in File Cabinet |
| AG Grid Community Edition | MIT | Bundled JS in File Cabinet |
| math.js 12.x | Apache 2.0 | Bundled JS in File Cabinet |
THIRD_PARTY_LICENSES.md in the repository root lists all dependencies and transitive dependencies with license confirmation. No GPL, AGPL, or LGPL code is included.