# Axiom Transport Integration Implementation Plan

> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Add `@axiomhq/pino` as a production-only log transport to the NestJS API, with graceful degradation when Axiom credentials are absent.

**Architecture:** A module-level `buildPinoTransport()` helper returns a partial `pinoHttp` options object that is spread into `LoggerModule.forRoot()`. In production with credentials present it outputs to both stdout and Axiom; without credentials it warns and falls back to stdout JSON; in non-production it uses `pino-pretty`.

**Tech Stack:** NestJS 10, nestjs-pino ^4.6.1, pino ^10.3.1, @axiomhq/pino ^1.2

---

## Chunk 1: Install package and wire transport

### Task 1: Install `@axiomhq/pino`

**Files:**
- Modify: `apps/api/package.json` (dependencies section)
- Updated automatically: `pnpm-lock.yaml` (monorepo root)

- [ ] **Step 1: Install the package**

Run from the `apps/api` directory:

```bash
cd apps/api && pnpm add @axiomhq/pino@^1.2
```

Expected: `@axiomhq/pino` appears in `apps/api/package.json` under `dependencies`.

- [ ] **Step 2: Verify the install**

```bash
cd apps/api && pnpm list @axiomhq/pino
```

Expected: one line showing `@axiomhq/pino 1.x.x`.

---

### Task 2: Update `app.module.ts` with `buildPinoTransport()`

**Files:**
- Modify: `apps/api/src/app.module.ts` (lines 25–33)

No automated tests — this is pure configuration. Manual verification is in Task 3.

- [ ] **Step 1: Replace the inline ternary with `buildPinoTransport()`**

Open `apps/api/src/app.module.ts`. The current `LoggerModule.forRoot()` block (lines 25–33) looks like:

```typescript
LoggerModule.forRoot({
  pinoHttp: {
    autoLogging: true,
    quietReqLogger: false,
    transport: process.env.NODE_ENV !== 'production'
      ? { target: 'pino-pretty', options: { colorize: true, singleLine: true } }
      : undefined,
  },
}),
```

Replace with the following. Add the `buildPinoTransport` function **above** the `@Module` decorator (after the last import line), and update `LoggerModule.forRoot()`:

```typescript
function buildPinoTransport() {
  if (process.env.NODE_ENV !== 'production') {
    return {
      transport: { target: 'pino-pretty', options: { colorize: true, singleLine: true } },
    };
  }

  const token = process.env.AXIOM_TOKEN;
  const dataset = process.env.AXIOM_DATASET;

  // Treat undefined AND empty string as absent
  if (!token || !dataset) {
    // console.warn fires before the pino instance is initialised — intentional plain-text warning
    console.warn('[Logger] AXIOM_TOKEN or AXIOM_DATASET not set — Axiom transport disabled, using stdout JSON only');
    return {};
  }

  return {
    transport: {
      targets: [
        { target: 'pino/file', level: 'info', options: { destination: 1 } },    // stdout
        { target: '@axiomhq/pino', level: 'info', options: { token, dataset } }, // Axiom
      ],
    },
  };
}

@Module({
  imports: [
    LoggerModule.forRoot({
      pinoHttp: {
        autoLogging: true,
        quietReqLogger: false,
        ...buildPinoTransport(),
      },
    }),
    // ... rest unchanged
```

- [ ] **Step 2: Verify TypeScript compiles**

```bash
cd apps/api && pnpm check-types
```

Expected: no errors.

---

### Task 3: Add Axiom env vars to `.env.example`

**Files:**
- Modify: `.env.example` (monorepo root)

- [ ] **Step 1: Append Axiom vars to `.env.example`**

Open `.env.example` at the monorepo root. Append after the existing content:

```
# Axiom (production log ingestion)
AXIOM_TOKEN=""
AXIOM_DATASET=""
```

---

### Task 4: Verify and commit

- [ ] **Step 1: Run the full test suite to confirm nothing is broken**

```bash
cd apps/api && pnpm test
```

Expected: all tests pass (136 tests, 0 failures).

- [ ] **Step 2: Start the dev server and verify `pino-pretty` output still works**

```bash
cd apps/api && pnpm dev
```

Expected: colourised, single-line pino-pretty output in the terminal (non-production mode). No errors on startup.

- [ ] **Step 3: Verify graceful degradation — production mode without credentials**

Stop the dev server. Run:

```bash
NODE_ENV=production node -e "
  process.env.AXIOM_TOKEN = '';
  process.env.AXIOM_DATASET = '';
  // Inline the logic to test it in isolation
  const token = process.env.AXIOM_TOKEN;
  const dataset = process.env.AXIOM_DATASET;
  if (!token || !dataset) {
    console.warn('[Logger] AXIOM_TOKEN or AXIOM_DATASET not set — Axiom transport disabled, using stdout JSON only');
    console.log('PASS: graceful degradation fires');
  } else {
    console.log('FAIL: should have degraded');
  }
"
```

Expected: prints `[Logger] AXIOM_TOKEN or AXIOM_DATASET not set...` followed by `PASS: graceful degradation fires`.

- [ ] **Step 4: Commit**

```bash
git add apps/api/package.json apps/api/src/app.module.ts .env.example pnpm-lock.yaml
git commit -m "feat(api): add Axiom pino transport with graceful degradation"
```
