Process: Add a Client

Process: Add a Client

Owner: Client Intake Manager (Camille) Type: Manual (semi-automated) Frequency: Per new client (commercial or internal/personal)

Purpose

Provision a new client across the three systems the factory uses, in one consistent pass:

  1. Factory record — the client profile in the repo (production-lines/clients/{slug}/)
  2. Atlassian / JSM — the client as an Organization in the Jackson Creek Tech service desk, so they can raise and track requests
  3. JCT portal — the client's delivery zone at {slug}.jacksoncreektech.ca (Cloudflare Pages + Access)

Not every client needs all three at once. Part 1 is always done. Parts 2 and 3 are done when the client will actually raise tickets / receive published deliverables. Internal/personal "clients" (e.g. dogfooding) usually do Part 1 only, and defer 2–3.

Overview

[Decision: commercial or internal?] → Part 1 Factory record (always)
                                     → Part 2 Atlassian/JSM (if client raises tickets)
                                     → Part 3 JCT portal (if client receives published deliverables)

Client registry

Client IDs are sequential CLIENT-NNN, assigned in Part 1.

ID Slug Name Type
CLIENT-001 stm Société de transport de Montréal Commercial
CLIENT-002 bruno-bock Bruno Bock (personal) Internal

Add a row here each time a client is created. The highest existing ID + 1 is the next CLIENT-NNN.


Part 1 — Factory record (always)

1.1 Choose the slug

  • kebab-case, short, becomes the folder name and the future portal subdomain ({slug}.jacksoncreektech.ca).
  • Examples: stm, transgesco, bruno-bock (subdomain may be shortened, e.g. bb — record the chosen subdomain in the profile if it differs from the slug).

1.2 Assign the next CLIENT-NNN

Scan the registry table above; take the highest CLIENT-NNN and increment. Zero-pad to 3 digits.

1.3 Create the profile

production-lines/clients/{slug}/profile.md

Copy the structure of an existing profile (production-lines/clients/stm/profile.md for commercial, production-lines/clients/bruno-bock/profile.md for internal). Fill:

  • Client ID, slug, last-updated date
  • Organization (full name, segment, size, location, language)
  • Business context (one paragraph)
  • Projects / Work Orders tables (start empty or with the triggering WO)
  • A Planned table for deferred items (portal, JSM org) so nothing is lost

1.4 Add the registry row

Add the new client to the registry table in this file.

Output: production-lines/clients/{slug}/profile.md exists, registry updated.


Part 2 — Atlassian / JSM organization (if the client raises tickets)

The client raises and tracks requests as an Organization in the Jackson Creek Tech service desk.

Fact Value
Site jackson-creek-tech.atlassian.net
Service desk project JCT
Service desk id 3
Internal factory project (backlog/epics) UAAnot used for clients; leave alone here

Scope note: clients live in JCT (service desk). The factory's own backlog lives in UAA. Do not put a client into UAA.

2.1 Get the cloudId

Use mcp__claude_ai_Atlassian__getAccessibleAtlassianResources (first run) to resolve the cloudId for jackson-creek-tech.atlassian.net.

2.2 Create the organization

JSM organizations are created via the service desk REST API (orgs were provisioned by API; groups/types/automations/workflow remain UI-only — see project_jsm-setup-status).

# Auth: Basic with Atlassian account email + API token (id.atlassian.com → API tokens)
# Create the organization
curl -s -u "$ATLASSIAN_EMAIL:$ATLASSIAN_API_TOKEN" \
  -X POST "https://jackson-creek-tech.atlassian.net/rest/servicedeskapi/organization" \
  -H "Content-Type: application/json" \
  -d '{"name": "{Client full name}"}'
# → returns the new organization id

2.3 Associate the organization to the JCT service desk

curl -s -u "$ATLASSIAN_EMAIL:$ATLASSIAN_API_TOKEN" \
  -X POST "https://jackson-creek-tech.atlassian.net/rest/servicedeskapi/servicedesk/3/organization" \
  -H "Content-Type: application/json" \
  -d '{"organizationId": {orgId}}'

2.4 Add the client's contacts as customers

curl -s -u "$ATLASSIAN_EMAIL:$ATLASSIAN_API_TOKEN" \
  -X POST "https://jackson-creek-tech.atlassian.net/rest/servicedeskapi/organization/{orgId}/user" \
  -H "Content-Type: application/json" \
  -d '{"usernames": ["[email protected]", "[email protected]"]}'

If a contact is not yet a customer, JSM creates them. They receive an invite to the portal.

2.5 UI fallback

If the API is unavailable: jackson-creek-tech.atlassian.netService project (JCT)CustomersOrganizationsAdd organization → add the contacts. Same result.

2.6 Record it

In the client profile, replace the deferred "JSM org" row with the live org id and the list of authorized contacts. Requests later raised by the client get a jira_key (JCT-NNN); link that into the matching repo WO/REQ frontmatter so /request-sync can track status.

Output: JSM organization exists, associated to JCT, contacts added, profile updated.


Part 3 — JCT portal (if the client receives published deliverables)

The portal scaffold + Cloudflare steps are already documented in detail. Do not duplicate — follow:

C:\Projects\jct-portail-template\ADD-CLIENT.md

Summary of that checklist (≤ 45 min):

  1. gh repo create bockbr/jct-portail-{slug} --template bockbr/jct-portail-template --private
  2. Customize palette (assets/style.css :root) + hub (index.html)
  3. Commit + push
  4. Cloudflare Pages → Connect to Git → build preset None, output / (dashboard only)
  5. Custom domain {slug}.jacksoncreektech.ca (dashboard only)
  6. Cloudflare Access → Self-hosted app, OTP, allow [email protected] + client contacts (dashboard only)
  7. Incognito access test (blocking DoD)

Steps 4–6 are Cloudflare dashboard only — they cannot be scripted from here. Steps 1–3 can be run via gh/git.

After go-live, record the portal URL + Cloudflare Pages/Access links in the client profile (replace the deferred "portal" row).

Output: {slug}.jacksoncreektech.ca live and access-tested.


Quality gate

A client is fully added when (scope-dependent):

  • Part 1production-lines/clients/{slug}/profile.md exists; registry row added
  • Part 2 (if applicable) — JSM organization created, associated to JCT, contacts added, recorded in profile
  • Part 3 (if applicable) — portal live, access tested, links recorded in profile
  • Deferred parts (if any) are logged in the profile's Planned table — nothing lost

Notes & gotchas

  • Internal/personal clients (CLIENT-002 Bruno Bock pattern): Part 1 only; Parts 2–3 deferred and logged. Used to flow personal/dogfooding talents through the same WO-PROD machinery while staying separated from real clients.
  • Slug vs subdomain: usually identical; if shortened (e.g. bruno-bockbb), record both in the profile so the portal step uses the right subdomain.
  • OTP not arriving (Part 3): 90% antispam — whitelist [email protected].
  • Don't cross the streams: clients = JCT service desk; factory internal backlog = UAA. Keep them separate.