npm package: @hashicorp/web-tracking-plans
Description: HashiCorp's Web Tracking Plans
Author: Brandon Romano
Latest version: 0.1.1

# Web Tracking Plans

This repository contains the [JSON Schema](https://json-schema.org/) specifications for our web properties' [Tracking Plans](https://segment.com/docs/protocols/tracking-plan/). We define all of our Tracking Plans centrally here, in code.

This repository is responsible for:

1. **Deploying updates to our [Segment Protocols](https://segment.com/product/protocols/) service.**

2. **Packaging the [@hashicorp/web-tracking-plans npm package](https://www.npmjs.com/package/@hashicorp/web-tracking-plans)**.

## Requirements

This project requires having [Node.js](https://nodejs.org/en/) installed on your machine.

## Installation

```bash
npm install @hashicorp/web-tracking-plans --save
```

## Usage

The package exposes two named exports:

| Name                    | Type                                                     | Description                                                                                                           |
| ----------------------- | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| trackingPlans           | `Array<string>`                                          | An array of plan names. This value is useful for consumers needing to know all available Tracking Plans               |
| generateAnalyticsClient | `(path: string, destinationDir?: string): Promise<void>` | A function that generates a strongly typed analytics client via [Typewriter](https://github.com/segmentio/typewriter) |

```ts
import {
  trackingPlans,
  generateAnalyticsClient
} from "@hashicorp/web-tracking-plans";

generateAnalyticsClient("notavalidplan"); // TS Error: Argument of type '"notavalidplan"' is not assignable to parameter of type 'Plan'.
generateAnalyticsClient("dotcom"); // generates an index.js and index.d.ts file for the "dotcom" plan
```

## Contributing

First, install the project's dependencies:

```bash
npm install
```

Next, set up an `.env` file in the project root:

```sh
cp .env.sample .env
```

**Add Segment Access Token**

In order to deploy schema updates to [Segment Protocols](https://segment.com/product/protocols/) you will need to generate a [Segment Access Token](https://reference.segmentapis.com/#cd642f96-0fca-42a1-a727-e16fd33c7e8f) and manually add it to your `.env` file.

### Project Structure

All of the analytics schemas are housed within the `/plans` directory as shown below:

```
/plans
├── dotcom
│   ├── _protocols.yaml
│   ├── _typewriter.yaml
│   └── events
│       └── ...
├── io
│   ├── _protocols.yaml
│   ├── _typewriter.yaml
│   └── events
│       └── ...
└── ...
```

With the exception of the special `global` folder, each child of the `/plans` directory is treated as a unique ["Tracking Plan"](https://segment.com/docs/protocols/tracking-plan/). The plans store schemas written in YAML.

#### \_protocols.yaml

This file serves as the [JSON Schema](https://json-schema.org/) that is synced and deployed to [Segment Protocols](https://segment.com/product/protocols/)

#### \_typewriter.yaml

This file serves as the [JSON Schema](https://json-schema.org/) that is consumed by Segment's [Typewriter library](https://github.com/segmentio/typewriter) which is used to generate a typed analytics client.

### Local Development / Testing

#### Adding a new Plan

1. Simply add a new folder under the `/plans` directory (i.e. `newPlan`) with that appropriate `.yaml` file values for your needs.

```diff
/plans
 ├── ...
+├── newPlan
+│   ├── _protocols.yaml
+│   ├── _typewriter.yaml
+│   └── events
+│       └── ...
 └── ...
```

2. Add a plan ID environment variable

**.env.sample**, **.env**

```diff
  SEGMENT_IO_PLAN_ID="abcdef"
+ SEGMENT_NEWPLAN_PLAN_ID="abcdefg"
```

3. Update library code

- a) Append a new enum value

**lib/index.ts**

```diff
export enum Plan {
  Dotcom = "dotcom",
  Io = "io",
  Learn = "learn"
+ NewPlan = "newPlan"
}
```

**Note:** You must initialize the enum value with a string that matches the folder name. Continuing our example from before, consider the following:

```ts
export enum Plan {
  ..
  NewPlan1 = "new", // ❌ the enum value "new" doesn't match the folder name
  NewPlan2 = "newPlan" // ✅ the enum value "newPlan" matches the folder name
}
```

- b) Expand environment variable checks

**lib/cli.ts**

```diff
  if (
    !process.env.SEGMENT_DOTCOM_PLAN_ID ||
    !process.env.SEGMENT_IO_PLAN_ID ||
-   !process.env.SEGMENT_LEARN_PLAN_ID
+   !process.env.SEGMENT_LEARN_PLAN_ID ||
+   !process.env.SEGMENT_NEWPLAN_PLAN_ID
  ) {
```

- c) Extend switch statement to point to new environment variable (see above) to determine `planId`

**lib/cli.ts**

```diff
  const planId: string = (plan => {
    switch (plan) {
      case Plan.Dotcom:
        return process.env.SEGMENT_DOTCOM_PLAN_ID;
      case Plan.IO:
        return process.env.SEGMENT_IO_PLAN_ID;
      case Plan.Learn:
        return process.env.SEGMENT_LEARN_PLAN_ID;
+     case Plan.NewPlan:
+       return process.env.SEGMENT_NEWPLAN_PLAN_ID;
    }
  })(plan);
```

## Scripts

This project exposes a few scripts to leverage during development:

| Script                     | Description                                                                                                                                                                                                                                                                   |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `npm run update:protocols` | This script invokes a CLI that guides you through deploying a particular Tracking Plan to the Segment Protocols service.                                                                                                                                                      |
| `npm start`                | This script will run the TypeScript compiler (`tsc`) in _watch mode_, listening to changes inside the `lib` directory. You'd run this if you are actively changing library code (`.ts`) and are either checking or running the compiled output (`/dist` directory) as you go. |
| `npm run build`            | This script will run the TypeScript compiler (`tsc`) and build the project once, outputing the results in the `/dist` directory.                                                                                                                                              |
| `npm run release`          | This script will build the project and guide you through the process of releasing a new version of the project (provided there are changes).                                                                                                                                  |

## "The Process" (Stakeholder Coordination)

Updating, deploying, and utilizing the code managed in this repository requires a level of coordination between a number of different stakeholders. The diagram below illustrates how this coordination will occur:

![Web Tracking Deploy Process](https://user-images.githubusercontent.com/794809/61177908-4f9b9680-a5ae-11e9-8682-19cadb32b1dc.png)