03-Development / 03.11.Utilities-Style-Guide

03.11.Utilities Style Guide

03.11. Utilities Style Guide

System Overview

The Car Pulse Tracker UTL (bnc-cpt-utl) is the orchestration module that ties together all components of the Car Pulse Tracker system. It provides Docker container management, Make-based build orchestration, shell actions for deployment and operations, and CI/CD integration.

Full System Architecture

 DEVELOPER WORKSTATIONS                        GITHUB
 ═══════════════════════                       ═══════
 ┌───────────────────────────────┐             ┌────────────────────────────────────┐
 │  Local Laptop                 │   git push  │  GitHub (csitea org)               │
 │                               │────────────>│                                    │
 │  Docker Containers:           │             │  Repositories:                     │
 │  ┌──────────┐ ┌──────────┐   │             │  ├── bnc-cpt-api   (FastAPI)       │
 │  │ cpt-api  │ │ cpt-wui  │   │             │  ├── bnc-cpt-wui   (Vue 3)        │
 │  │ :8100    │ │ :3333    │   │             │  ├── bnc-cpt-utl   (Orchestration) │
 │  └──────────┘ └──────────┘   │             │  ├── bnc-cpt-inf   (Terraform)     │
 │  ┌──────────┐ ┌──────────┐   │             │  ├── bnc-cpt-cnf   (Config YAML)  │
 │  │ the-bot  │ │tesla-mock│   │             │  └── tpl-gen       (Templates)     │
 │  │(Puppeteer)│ │ :9100    │   │             │                                    │
 │  └──────────┘ └──────────┘   │             │  Linear Issues: team-bnc-cpt-int   │
 │  ┌──────────┐ ┌──────────┐   │             └───────────────────┬────────────────┘
 │  │tf-runner │ │ tpl-gen  │   │                                 │
 │  │(Terraform)│ │(Jinja2)  │   │                          push to master
 │  └──────────┘ └──────────┘   │                                 │
 │                               │                                 ▼
 │  ~/.gcp/.bnc/key-*.json       │             ┌────────────────────────────────────┐
 │  ~/.slack/bot_token           │             │  GitHub Actions Workers             │
 │  ~/.linear/api_key            │             │                                    │
 └───────────────────────────────┘             │  WUI Pipeline (ci.yaml):           │
                                               │  ┌─────────┐ ┌────────┐ ┌───────┐ │
                                               │  │ build & │→│ deploy │→│post-  │ │
                                               │  │  test   │ │to GCS  │ │deploy │ │
                                               │  └─────────┘ └────────┘ │ test  │ │
                                               │                         └───────┘ │
                                               │  API Pipeline (cd.yaml):          │
                                               │  ┌─────────┐ ┌────────┐ ┌───────┐ │
                                               │  │ build & │→│Cloud   │→│post-  │ │
                                               │  │push img │ │Run dep.│ │deploy │ │
                                               │  └─────────┘ └────────┘ │ test  │ │
                                               │                         └───────┘ │
                                               └───────────────┬──────────────────┘
                                                               │
                        ┌──────────────────────────────────────┘
                        ▼
 GOOGLE CLOUD PLATFORM
 ═════════════════════════════════════════════════════════════════════════════════
 ┌─────────────────────────────────────────────────────────────────────────────┐
 │                                                                             │
 │  Projects: bnc-cpt-inf │ bnc-cpt-dev │ bnc-cpt-tst │ bnc-cpt-prd          │
 │                                                                             │
 │  ┌─────────────────────┐  ┌──────────────────────┐  ┌───────────────────┐  │
 │  │  Artifact Registry  │  │   Cloud Run (API)    │  │  GCS Bucket (WUI) │  │
 │  │                     │  │                      │  │                   │  │
 │  │  bnc-cpt-api/       │  │  {env}.api.          │  │  {env}.           │  │
 │  │    cpt-api:latest   │──│  carpulsetracker.com │  │  carpulsetracker  │  │
 │  │    cpt-api:{sha}    │  │  :8100               │  │  .com             │  │
 │  └─────────────────────┘  └──────────┬───────────┘  └────────┬──────────┘  │
 │                                      │                       │             │
 │  ┌─────────────────────┐  ┌──────────┴───────────┐  ┌───────┴──────────┐  │
 │  │  Secret Manager     │  │  Cloud DNS            │  │  Cloud CDN       │  │
 │  │                     │  │                       │  │  + HTTPS LB      │  │
 │  │  bnc-cpt-stripe-*   │  │  carpulsetracker.com  │  │  + SSL Cert      │  │
 │  │  bnc-cpt-paypal-*   │  │  CNAME → ghs.google   │  │                  │  │
 │  │  bnc-cpt-jwt-*      │  │         hosted.com    │  │                  │  │
 │  │  bnc-cpt-admin-*    │  └──────────────────────┘  └──────────────────┘  │
 │  │  bnc-cpt-tesla-*    │                                                   │
 │  │  bnc-cpt-stripte-   │                                                   │
 │  │   test-account-*    │                                                   │
 │  └─────────────────────┘                                                   │
 └─────────────────────────────────────────────────────────────────────────────┘

 EXTERNAL SERVICES
 ═════════════════════════════════════════════════════════════════════════════════

 Payment Providers                              Vehicle Data Platform
 ─────────────────                              ──────────────────────
 ┌──────────────────┐  ┌──────────────────┐     ╔══════════════════════════════╗
 │ ≋ Stripe         │  │ ≋ PayPal         │     ║  ◈ Tesla Fleet API           ║
 │                  │  │                  │     ║                              ║
 │ checkout.stripe  │  │ paypal.com/      │     ║  auth.tesla.com/oauth2      ║
 │ .com/pay/cs_*    │  │ approve/PAY-*    │     ║  fleet-api.prd.eu.vn.cloud  ║
 │                  │  │                  │     ║   .tesla.com                ║
 │ API: pi_*, cs_*  │  │ API: 5O*, 3L*    │     ║                              ║
 │ Webhook: whsec_* │  │ Sandbox+Live     │     ║  OAuth2 → Vehicle Data      ║
 └──────────────────┘  └──────────────────┘     ║  → Battery Health           ║
                                                ║  → Charging Stats           ║
 ┌──────────────────┐  ┌──────────────────┐     ║  → Service History          ║
 │ ≋ MobilePay      │  │ ≋ Google Pay     │     ╚══════════════════════════════╝
 │   (placeholder)  │  │   (placeholder)  │
 │ API: mp_*        │  │                  │
 └──────────────────┘  └──────────────────┘
                                                 Collaboration
 ┌──────────────────┐                            ──────────────
 │ ≋ Apple Pay      │                            ┌──────────────────┐
 │   (placeholder)  │                            │  ✦ Slack          │
 └──────────────────┘                            │                  │
                                                 │  #bnc-cpt        │
                                                 │  Bot: xoxb-...   │
                                                 └──────────────────┘

                                                 ┌──────────────────┐
                                                 │  ✦ Linear        │
                                                 │                  │
                                                 │  Team: BNC       │
                                                 │  Issues: BNC-*   │
                                                 └──────────────────┘

Data Flow Summary

 User Browser                    Cloud Run (API)              External
 ────────────                    ───────────────              ────────
 ┌────────────┐                  ┌──────────────┐
 │  Vue 3 SPA │──── /api/v1/ ───>│  FastAPI      │
 │  (CDN)     │<─── JSON ───────│  :8100        │
 └─────┬──────┘                  └──┬──────┬────┘
       │                            │      │
       │  Stripe redirect           │      │         ╔═══════════════╗
       │─────────────────────────>Stripe    │         ║ Tesla Fleet   ║
       │<─── return_url ──────────Checkout  │────────>║ API           ║
       │                            │      │<────────║ (OAuth2+Data) ║
       │  PayPal redirect           │      │         ╚═══════════════╝
       │─────────────────────────>PayPal    │
       │<─── return_url ──────────Approve   │
       │                            │      │
       │  PDF download              │      │
       │<─── receipt.pdf ───────────┘      │
       │<─── report.pdf  ──────────────────┘

UTL does not run in production. It is a development and CI/CD tool that orchestrates the other modules.

Docker Container Ecosystem

UTL manages 5 Docker containers:

Container Image Purpose Port
con-bnc-cpt-cpt-api img-cpt-api FastAPI backend (dev) 8100
con-bnc-cpt-wui img-cpt-wui Vue frontend (dev) 3333
con-bnc-cpt-tf-runner img-cpt-tf-runner Terraform execution -
con-bnc-cpt-tpl-gen img-cpt-tpl-gen Template generation -
con-bnc-cpt-conf-validator img-cpt-conf-validator Config validation -

Docker Compose Files

File Containers Purpose
docker-compose-api.yaml cpt-api API development
docker-compose-wui.yaml cpt-wui WUI development
docker-compose-infra.yaml tf-runner, tpl-gen, conf-validator Infrastructure

Environment Variables

Docker containers configured via src/docker/.env (local) or .env.cin (CI):

Variable Local CI
MOUNT_WORK_DIR /opt/bnc/bnc-cpt /home/runner/work/.../opt/bnc/bnc-cpt
HOME_API_PROJ_PATH /home/appusr/opt/bnc/bnc-cpt/bnc-cpt-api same
HOME_WUI_PROJ_PATH /home/appusr/opt/bnc/bnc-cpt/bnc-cpt-wui same
API_PORT_HOST 8100 8100
WUI_PORT_HOST 3333 3333

Shell Action Framework

How It Works

./run -a do_action_name
    │
    ├── Parses -a flag
    ├── Scans src/bash/run/*.func.sh
    ├── Matches: do_action_name → action-name.func.sh
    ├── Sources the file
    └── Executes the function

Naming: kebab-case.func.shdo_snake_case function.

Key Shell Actions

Deployment

Action File Purpose
do_gcp_deploy_wui gcp-deploy-wui.func.sh Build Vue + deploy to GCS + CDN invalidate
do_gcp_deploy_api_full gcp-deploy-api-full.func.sh Build + push + deploy API to Cloud Run
do_gcp_build_and_push_api_image gcp-build-and-push-api-image.func.sh Build + push API Docker image
do_gcp_deploy_cloud_run gcp-deploy-cloud-run.func.sh Deploy image to Cloud Run
do_deploy_app_to_environment deploy-app-to-environment.func.sh Full environment deploy

Version Management

Action File Purpose
do_version_bump version-bump.func.sh Bump semver git tag (patch/minor/major)

Configuration

Action File Purpose
do_generate_env_json (in tpl-gen) YAML → JSON conversion
do_generate_config_for_step (in tpl-gen) JSON → tfvars generation

Sync / Utility

Action File Purpose
do_sync_wui_to_remote_host sync-wui-to-remote-host.func.sh rsync WUI to VM
do_sync_api_to_remote_host sync-api-to-remote-host.func.sh rsync API to VM
do_push_all_app_repos push-all-app-repos.func.sh Git push all repos
do_pull_all_app_repos pull-all-app-repos.func.sh Git pull all repos

Make Target System

Target Categories

Category Prefix Example
Container setup do-setup-* make do-setup-api
Terraform do-provision, do-tf-* make do-provision ENV=dev STEP=029
Testing test-api-* make test-api-cov
Config generation do-generate-* make do-generate-config-for-step
Deployment do-gcp-* make do-gcp-sync-secrets ENV=dev

Terraform Make Targets

All terraform operations run inside con-bnc-cpt-tf-runner:

Target Required Vars Purpose
do-provision ENV, STEP terraform apply
do-deprovision ENV, STEP terraform destroy
do-tf-plan ENV, STEP Plan only
do-tf-state-list ENV, STEP List state objects
do-tf-import ENV, STEP, TARGET, ID Import existing resource
do-tf-apply-target ENV, STEP, TARGET Apply single resource
do-tf-destroy-target ENV, STEP, TARGET Destroy single resource
do-tf-replace-target ENV, STEP, TARGET Destroy + recreate resource
do-tf-state-remove ENV, STEP, TARGET Remove from state
do-tf-state-show ENV, STEP, TARGET Show resource state
do-gcp-sync-secrets ENV Sync secrets from Google Sheet

Configuration Pipeline

YAML (source of truth)     JSON (intermediate)      tfvars (output)
bnc-cpt-cnf/               bnc-cpt-cnf/             bnc-cpt-cnf/
  dev.env.yaml      →        dev.env.json     →       dev/tf/029.vars.tfvars
                                                       dev/tf/029.backend-config.tfvars

  tpl-gen (Jinja2)          tpl-gen (Jinja2)
  renders templates         renders templates

Template files: bnc-cpt-cnf/src/tpl/%org%-%app%/%env%/tf/{step}.*.tfvars.tpl

CI/CD Integration

UTL is used by both API and WUI CI/CD pipelines:

WUI Pipeline (bnc-cpt-wui)

  1. CI clones all repos including UTL
  2. Copies .env.cin.env (Docker config for CI)
  3. Overrides MOUNT_WORK_DIR for runner path
  4. make do-setup-wui-no-cache builds container
  5. do_build_wui_vue runs type-check + build
  6. do_gcp_deploy_wui deploys to GCS

API Pipeline (bnc-cpt-api)

  1. CI clones all repos including UTL
  2. Reads config from bnc-cpt-cnf/{env}.env.json
  3. Builds Docker image using bnc-cpt-utl/src/docker/cpt-api/Dockerfile.x86_64
  4. Pushes to Artifact Registry
  5. Deploys to Cloud Run with env vars from config

Version Management System

Architecture

do_version_bump
    │
    ├── Read latest git tag (git describe --tags)
    ├── Parse: v{major}.{minor}.{patch}
    ├── Increment (patch → minor → major at 9)
    └── Create annotated git tag

                  ┌─────────────────────────┐
                  │                         │
            WUI Build                 API Deploy
                  │                         │
    VITE_APP_VERSION=v0.2.3      APP_VERSION=v0.2.2
                  │                         │
    <meta name="version"         Cloud Run env var
     content="v0.2.3" />         → /health, /, /api

Version Flow

WUI: git tag → gcp-deploy-wui.func.sh reads tag → passes VITE_APP_VERSION to Docker build → Vite injects <meta> tag → visible in HTML source

API: git tag → cd.yaml reads tag → passes APP_VERSION to Cloud Run → Pydantic settings loads it → visible at API endpoints

Environment Matrix

Environment Purpose Auto-deploy Manual deploy
inf Infrastructure testing On master push workflow_dispatch
dev Development On master push workflow_dispatch
tst Testing/QA - workflow_dispatch only
prd Production - workflow_dispatch only

GCP Service Account Keys

All operations authenticate via service account keys at ~/.gcp/.bnc/:

Key File GCP Project Used By
key-bnc-cpt-inf.json bnc-cpt-inf Terraform, deploy
key-bnc-cpt-dev.json bnc-cpt-dev Terraform, deploy
key-bnc-cpt-tst.json bnc-cpt-tst Terraform, deploy
key-bnc-cpt-prd.json bnc-cpt-prd Terraform, deploy
key-bnc-cpt-all.json Cross-project Google Sheets, shared ops

Slack Integration

UTL provides shell actions for posting messages and threads to Slack channels from the CLI.

Setup

  1. Create a Slack App at https://api.slack.com/apps → "Create an App" → "From scratch"
  2. OAuth & Permissions → Bot Token Scopes → add chat:write and chat:write.public
  3. (Optional) Add im:write for direct messages
  4. Install to Workspace → copy the Bot User OAuth Token (xoxb-...)
  5. Run ./run -a do_slack_setup and paste the token

The token is stored at ~/.slack/bot_token (chmod 600).

Shell Actions

Action File Purpose
do_slack_setup slack-setup.func.sh Save bot token to ~/.slack/bot_token
do_slack_post_msg slack-post-msg.func.sh Post message to a channel
do_slack_post_thread slack-post-thread.func.sh Post title + threaded reply

Usage

# Simple message
CHANNEL=bnc-cpt MSG="Hello" ./run -a do_slack_post_msg

# Post file contents (markdown auto-converted to Slack format)
CHANNEL=bnc-cpt FILE=doc/md/cle-ad-hoc.md ./run -a do_slack_post_msg

# Thread: title + file as reply
CHANNEL=bnc-cpt TITLE="Update" FILE=doc/md/cle-ad-hoc.md ./run -a do_slack_post_thread

# Reply in existing thread
CHANNEL=bnc-cpt THREAD_TS=1770813763.163469 MSG="reply" ./run -a do_slack_post_msg

# Mention a user (use their Slack Member ID)
CHANNEL=bnc-cpt MSG="<@U079LU2D17G> check this" ./run -a do_slack_post_msg

Markdown Conversion

When posting .md files, content is automatically converted to Slack mrkdwn format: - Markdown tables → monospace code blocks - **bold***bold* - # Headers*Headers* - [text](url)<url|text>

Parameters

Variable Used By Description
CHANNEL post_msg, post_thread Channel name without #
MSG post_msg Message text (Slack mrkdwn)
FILE post_msg, post_thread File path (overrides MSG/REPLY)
THREAD_TS post_msg Parent message timestamp for thread reply
TITLE post_thread Main message text
REPLY post_thread Text reply (used if FILE not set)

Execution Control Flow

CI/CD Pipeline Execution

 WUI Pipeline (ci.yaml)
 ══════════════════════════════════════════════════════════════════════════════

 ┌─────────────────────────────────────────────────────────────────────────┐
 │  Job 1: build-and-test  (all pushes)                                   │
 │                                                                         │
 │  clone repos ──> docker build ──> type-check ──> wait for ──> Puppeteer │
 │  (gh api)       (Dockerfile)    (do_build_     Vite dev     npm test   │
 │                                  wui_vue)      server       (lcl)      │
 │                                                                         │
 │  Output: Mochawesome HTML report artifact                               │
 └─────────────────────────────────────┬───────────────────────────────────┘
                                       │ (master only)
                                       ▼
 ┌─────────────────────────────────────────────────────────────────────────┐
 │  Job 2: prepare-deploy                                                  │
 │                                                                         │
 │  push to master ──> environments = ["inf", "dev"]                       │
 │  workflow_dispatch ──> environments = ["<selected>"]                    │
 └─────────────────────────────────────┬───────────────────────────────────┘
                                       │
                          ┌────────────┼────────────┐
                          ▼            ▼            ▼
 ┌────────────────────────────────────────────────────────────────────────┐
 │  Job 3: deploy  (matrix: inf, dev, tst)                                │
 │                                                                         │
 │  clone ──> git tag ──> load cnf ──> docker ──> GCP ──> Vue build      │
 │  repos     version     JSON        build      auth    (VITE_APP_      │
 │                                                        VERSION)        │
 │       ──> gsutil sync ──> CDN invalidate ──> health check              │
 │           to GCS bucket                     https://{fqdn}             │
 └─────────────────────────────────────┬──────────────────────────────────┘
                                       │
                          ┌────────────┼────────────┐
                          ▼            ▼            ▼
 ┌────────────────────────────────────────────────────────────────────────┐
 │  Job 4: post-deploy-test  (matrix: inf, dev, tst — never prd)         │
 │                                                                         │
 │  clone ──> load cnf ──> GCP auth ──> fetch secrets ──> docker build   │
 │  repos     JSON                      (Secret Mgr)      the-bot        │
 │                                      STRIPTE_*                         │
 │                                      PAYPAL_*                          │
 │                                                                         │
 │       ──> wait for WUI ──> docker exec npm test ──> upload report      │
 │           health check     (ENV={env}, creds via -e)  Mochawesome      │
 └────────────────────────────────────────────────────────────────────────┘


 API Pipeline (cd.yaml)
 ══════════════════════════════════════════════════════════════════════════════

 ┌────────────────────────────────────────────────────────────────────────┐
 │  Job 1: prepare                                                        │
 │                                                                         │
 │  push to master ──> environments = ["inf", "dev"]                       │
 │  workflow_dispatch ──> environments = ["<selected>"]                    │
 └─────────────────────────────────────┬──────────────────────────────────┘
                                       │
                          ┌────────────┼────────────┐
                          ▼            ▼            ▼
 ┌────────────────────────────────────────────────────────────────────────┐
 │  Job 2: deploy  (matrix: inf, dev, tst)                                │
 │                                                                         │
 │  clone ──> git tag ──> load cnf ──> GCP auth ──> docker build          │
 │  repos     version     JSON                      (target=production)   │
 │                                                                         │
 │       ──> push to ──> gcloud run ──> domain ──> health check           │
 │           Artifact     deploy        mapping     /health (200)          │
 │           Registry     (secrets      (CNAME)     /docs   (200)          │
 │                        from SM)                                         │
 └─────────────────────────────────────┬──────────────────────────────────┘
                                       │
                          ┌────────────┼────────────┐
                          ▼            ▼            ▼
 ┌────────────────────────────────────────────────────────────────────────┐
 │  Job 3: post-deploy-test  (matrix: inf, dev, tst — never prd)         │
 │                                                                         │
 │  clone ──> load cnf ──> GCP auth ──> fetch secrets ──> curl smoke     │
 │  repos     JSON                      (Secret Mgr)      tests          │
 │                                                                         │
 │  Smoke tests:          ──> pip install ──> pytest test_post_deploy.py  │
 │  GET /health     (200)     httpx           (API_URL={url})             │
 │  GET /docs       (200)                                                  │
 │  POST /create-intent (<500)                                             │
 └────────────────────────────────────────────────────────────────────────┘

Terraform Provisioning Flow

 ┌──────────────┐    ┌──────────────┐    ┌──────────────┐    ┌──────────┐
 │  YAML Config │───>│  tpl-gen     │───>│  tfvars      │───>│ tf-runner│
 │  (bnc-cpt-   │    │  Jinja2      │    │  (bnc-cpt-   │    │          │
 │   cnf)       │    │  rendering   │    │   cnf/{env}/ │    │ terraform│
 │              │    │              │    │   tf/)        │    │ apply    │
 │ dev.env.yaml │    │ dev.env.json │    │ 029.vars.    │    │          │
 │              │    │              │    │  tfvars      │    │          │
 └──────────────┘    └──────────────┘    └──────────────┘    └──────────┘
                                                                  │
                                         ┌────────────────────────┘
                                         ▼
                            ┌────────────────────────┐
                            │  GCP Resources Created │
                            │  ├── Secret Manager    │
                            │  ├── Artifact Registry │
                            │  ├── Cloud Run         │
                            │  ├── Cloud DNS         │
                            │  ├── GCS Buckets       │
                            │  └── IAM Policies      │
                            └────────────────────────┘

Data Flow Diagrams

User Payment Flow

 Browser (Vue SPA)                 Cloud Run (API)             External
 ─────────────────                 ───────────────             ────────

 ① Select Plan
    (Basic €19 / Pro €29 / Bulk €149)
         │
 ② Select Payment Method
    (Stripe / PayPal / GooglePay / ApplePay)
         │
 ③ Agree to Terms
         │
 ④ Click Pay
         │
         ├── POST /api/v1/payment/create-intent ───────>┐
         │   {plan, amount, payment_method}              │
         │                                               ▼
         │                                     ┌──────────────────┐
         │                              Stripe │ stripe.checkout  │
         │                                     │ .Session.create()│
         │                                     └────────┬─────────┘
         │                                              │
         │<── {redirectUrl, paymentIntentId} ───────────┘
         │
 ⑤ Redirect to provider
         │
         │────────────────────> ┌──────────────────┐
         │                     │ checkout.stripe   │
         │  Fill test card:    │ .com/pay/cs_*     │
         │  4242 4242 4242 4242│                   │
         │  Click Pay          │ OR                │
         │                     │                   │
         │                     │ paypal.com/       │
         │                     │ approve/PAY-*     │
         │<── return_url ──────└──────────────────┘
         │
 ⑥ Verify payment
         │
         ├── POST /api/v1/payment/verify ──────────────>┐
         │   {payment_id}                                │
         │                                               ▼
         │                                     ┌──────────────────┐
         │                                     │ stripe.checkout  │
         │                                     │ .Session.retrieve│
         │                                     │ payment_status   │
         │                                     │ == "paid"        │
         │                                     └────────┬─────────┘
         │<── {status: "succeeded", receipt_url} ───────┘
         │
 ⑦ Download receipt
         │
         ├── GET /api/v1/payment/receipt/{id}/pdf ─────>┐
         │                                               │ WeasyPrint
         │<── receipt.pdf (HTML→PDF) ───────────────────┘

Tesla Vehicle Report Flow (fetch-in-callback)

 Browser (Vue SPA)                 Cloud Run (API)             Tesla Fleet API
 ─────────────────                 ───────────────             ═══════════════

 ① Initiate OAuth
         │
         ├── POST /api/v1/tesla/oauth/initiate ────────>┐
         │   {paymentId, plan}                           │ generate state token
         │                                               │ store in _states[state]
         │   NOTE: paymentId and plan are CPT-internal   │ (paymentId + plan are
         │   metadata — NOT sent to Tesla. They link     │  stored as state metadata
         │   the OAuth session back to the payment       │  for future use: audit,
         │   that authorized this report request.        │  linking reports to payments)
         │<── {authUrl, state} ─────────────────────────┘
         │
 ② Redirect to Tesla Login
         │
         │─────────────────────> ╔══════════════════════╗
         │   User authenticates  ║ auth.tesla.com       ║
         │   with Tesla account  ║ /oauth2/v3/authorize ║
         │   and grants consent  ║ ?client_id=...       ║
         │                       ║  &state=...          ║
         │                       ╚══════════╤═══════════╝
         │                                  │
         │                                  │ Tesla redirects to
         │                                  │ TESLA_REDIRECT_URI
         │                                  ▼
 ③ Callback: validate + exchange + fetch + store (all server-side)
         │
         │              GET /api/v1/tesla/oauth/callback
         │              ?code=...&state=...&issuer=...
         │                       │
         │                       ├── validate state (CSRF)
         │                       │   pop from _states, check age < 10min
         │                       │
         │                       ├── exchange code ──────> ╔═════════════════╗
         │                       │   for access_token      ║ auth.tesla.com  ║
         │                       │   (LOCAL variable,      ║ /oauth2/v3/     ║
         │                       │    never stored)        ║ token           ║
         │                       │<── access_token ─────── ╚═════════════════╝
         │                       │
         │                       ├── fetch vehicles ─────> ╔═════════════════╗
         │                       │   with user's token     ║ fleet-api/      ║
         │                       │<── vehicle list ─────── ║ api/1/vehicles  ║
         │                       │                         ╚═════════════════╝
         │                       │
         │                       ├── build report ───────> ╔═════════════════╗
         │                       │   (5 parallel calls)    ║ fleet-api/      ║
         │                       │    • vehicle_data       ║  vehicle_data   ║
         │                       │    • charging_history   ║  charging/hist  ║
         │                       │    • recent_alerts      ║  recent_alerts  ║
         │                       │    • service_data       ║  service_data   ║
         │                       │    • warranty_details   ║  warranty/det   ║
         │                       │<── all data ──────────  ╚═════════════════╝
         │                       │
         │                       ├── store report in _reports[session_id]
         │                       │   (token goes out of scope — discarded)
         │                       │
         │                       └── redirect ─────────────────────────────┐
         │                                                                 │
         │<── 302 Redirect: {frontend}?oauth=success&session_id=XXX ──────┘
         │
 ④ WUI reads URL params
         │
         │   App.vue onMounted:
         │   • reads oauth=success, session_id from URL
         │   • store.setSessionId(session_id)
         │   • store.setStep('verify')
         │   • cleans URL with history.replaceState
         │
 ⑤ Fetch pre-built report
         │
         ├── GET /api/v1/tesla/report/{session_id} ────>┐
         │                                               │ pop from _reports
         │                                               │ (one-time retrieval)
         │<── {vehicle, vehicleData, chargingHistory,    │
         │     recentAlerts, serviceData,                │
         │     warrantyDetails} ─────────────────────────┘
         │
 ⑥ Display report dashboard
         │
         │   store.setVehicleReport(report)
         │   store.setStep('report')
         │
         │   (Optional) Download PDF:
         ├── POST /api/v1/tesla/vehicle-report/pdf ────>┐
         │   {vehicleReport}                             │ WeasyPrint
         │<── report.pdf ───────────────────────────────┘

 KEY DESIGN DECISIONS:
 • Token is a LOCAL VARIABLE in fetch_and_store_report() — never stored globally
 • Each user gets a unique session_id — no cross-user interference
 • Reports auto-expire after 15 minutes (_cleanup_expired)
 • One-time retrieval: report is deleted after GET (pop from _reports)
 • App credentials (client_id + secret) != user authorization (per-user token)

Secrets Data Flow

 Source of Truth                    Distribution                  Consumption
 ──────────────                    ────────────                  ───────────

 ┌──────────────────┐
 │ GCP Secret Mgr   │
 │ (per-project)    │
 │                  │
 │ bnc-cpt-{name}   │
 └────────┬─────────┘
          │
          ├──────── Cloud Run ──────────────> API container
          │         (--set-secrets)            env vars at deploy time
          │
          ├──────── CI/CD Worker ───────────> post-deploy-test jobs
          │         (gcloud secrets           docker exec -e (in-memory)
          │          versions access)         masked in CI logs
          │
          └──────── Local Dev ─────────────> Docker containers
                    eval "$(ENV=dev bash      docker-compose env passthrough
                    gcp-fetch-secrets.sh)"    (in-memory, never on disk)

 Naming Convention:
 ┌──────────────────────────────┬───────────────────────────┐
 │ GCP Secret ID                │ Env Var Name              │
 ├──────────────────────────────┼───────────────────────────┤
 │ bnc-cpt-stripe-secret-key   │ STRIPE_SECRET_KEY         │
 │ bnc-cpt-jwt-secret-key      │ JWT_SECRET_KEY            │
 │ bnc-cpt-admin-password-hash │ ADMIN_PASSWORD_HASH       │
 │ bnc-cpt-stripte-test-*      │ STRIPTE_TEST_ACCOUNT_*    │
 └──────────────────────────────┴───────────────────────────┘
 Rule: strip "bnc-cpt-" prefix → replace "-" with "_" → UPPERCASE

Authentication to Services in local dev setup

All service credentials are stored under the $HOME directory of the OS user who invoked the shell (e.g. /home/ysg for Yordan, /Users/petri for Petri). The convention is $HOME/.<service-name>/ for simple tokens and $HOME/.gcp/.<org>/ or $HOME/.ssh/.<org>/ for multi-file credentials.

Linear

Item Path
API key $HOME/.linear/api_key

Single-line personal API key. Used by do_linear_comment_issue, do_linear_close_issue, and other Linear shell actions.

Slack

Item Path
Bot token $HOME/.slack/bot_token

Bot User OAuth Token (xoxb-...). Created via ./run -a do_slack_setup. Used by do_slack_post_msg and do_slack_post_thread.

GitHub

Item Path
Personal access token $HOME/.github/token

Used by gh CLI and shell actions that interact with GitHub API.

GCP (Google Cloud Platform)

All GCP service account key files are under $HOME/.gcp/.<org>/ (e.g. $HOME/.gcp/.bnc/):

File GCP Project Purpose
$HOME/.gcp/.bnc/key-bnc-cpt-inf.json bnc-cpt-inf Infrastructure project
$HOME/.gcp/.bnc/key-bnc-cpt-dev.json bnc-cpt-dev Development environment
$HOME/.gcp/.bnc/key-bnc-cpt-tst.json bnc-cpt-tst Test environment
$HOME/.gcp/.bnc/key-bnc-cpt-prd.json bnc-cpt-prd Production environment
$HOME/.gcp/.bnc/key-bnc-cpt-all.json Cross-project Google Sheets, shared ops

Used by gcloud auth activate-service-account, gsutil, Terraform (via tf-runner), deployment shell actions, and the gsheet_secrets_to_gcp.py script.

SSH and Encryption Keys

All SSH and encryption keys are under $HOME/.ssh/.<org>/ (e.g. $HOME/.ssh/.bnc/):

File Purpose
$HOME/.ssh/.bnc/id_rsa.sys+bnc-cpt-crs@carpulsetracker.com SSH key for git operations
$HOME/.ssh/.bnc/bnc-cpt-crs.pem KeePassXC database key
$HOME/.ssh/.bnc/tesla-private-key.pem Tesla Fleet API private key
$HOME/.ssh/.bnc/tesla-public-key.pem Tesla Fleet API public key (served at /.well-known/appspecific/com.tesla.3p.public-key.pem)

Path Derivation

All credential paths in code use $HOME (not hardcoded usernames) and derive the org from $ORG or $ORG_APP: - GCP keys: $HOME/.gcp/.${ORG}/key-${ORG_APP}-${ENV}.json - SSH keys: $HOME/.ssh/.${ORG}/ - KeePassXC: $HOME/.ssh/.${ORG}/${ORG_APP}-crs.pem

Module Relationship
bnc-cpt-api UTL builds, tests, and deploys the API
bnc-cpt-wui UTL builds and deploys the WUI
bnc-cpt-inf UTL executes Terraform via tf-runner container
bnc-cpt-cnf UTL generates config via tpl-gen container
tpl-gen UTL hosts the template generator container