# 02 — Architecture

## Runtime stack

| Layer | Technology |
|-------|------------|
| Language | Go 1.22+ |
| HTTP | `net/http`, `http.ServeMux` |
| UI | Embedded via `//go:embed` in `web/embed.go` (templates + static assets) |
| State | In-memory only — no database |
| Build | `CGO_ENABLED=0`, single static binary |

Default port: **8082**

## Directory structure

```
cmd/logpile/main.go          # Binary entry point, CLI flag parsing
internal/
  collector/                 # Live data collectors
    registry.go              # Collector registration
    redfish.go               # Redfish connector (real implementation)
    ipmi_mock.go             # IPMI mock connector (scaffold)
    types.go                 # Connector request/progress contracts
  parser/                    # Archive parsers
    parser.go                # BMCParser (dispatcher) + parse orchestration
    archive.go               # Archive extraction helpers
    registry.go              # Parser registry + detect/selection
    interface.go             # VendorParser interface
    vendors/                 # Vendor-specific parser modules
      vendors.go             # Import-side-effect registrations
      inspur/
      supermicro/
      nvidia/
      nvidia_bug_report/
      unraid/
      xigmanas/
      generic/
      pciids/                # PCI IDs lookup (embedded pci.ids)
  server/                    # HTTP layer
    server.go                # Server struct, route registration
    handlers.go              # All HTTP handler functions
  exporter/                  # Export formatters
    exporter.go              # CSV + JSON exporters
    reanimator_models.go
    reanimator_converter.go
  models/                    # Shared data contracts
web/
  embed.go                   # go:embed directive
  templates/                 # HTML templates
  static/                    # JS / CSS
    js/app.js                # Frontend — API contract consumer
```

## In-memory state

The `Server` struct in `internal/server/server.go` holds:

| Field | Type | Description |
|-------|------|-------------|
| `result` | `*models.AnalysisResult` | Current parsed/collected dataset |
| `detectedVendor` | `string` | Vendor identifier from last parse |
| `jobManager` | `*JobManager` | Tracks live collect job status/logs |
| `collectors` | `*collector.Registry` | Registered live collection connectors |

State is replaced atomically on successful upload or collect.
On a failed/canceled collect, the previous `result` is preserved unchanged.

## Upload flow (`POST /api/upload`)

```
multipart form field: "archive"
  │
  ├─ file looks like JSON?
  │     └─ parse as models.AnalysisResult snapshot → store in Server.result
  │
  └─ otherwise
        └─ parser.NewBMCParser().ParseFromReader(...)
              │
              ├─ try all registered vendor parsers (highest confidence wins)
              └─ result → store in Server.result
```

## Live collect flow (`POST /api/collect`)

```
validate request (host / protocol / port / username / auth_type / tls_mode)
  │
  └─ launch async job
        │
        ├─ progress callback → job log (queryable via GET /api/collect/{id})
        │
        ├─ success:
        │     set source metadata (source_type=api, protocol, host, date)
        │     store result in Server.result
        │
        └─ failure / cancel:
              previous Server.result unchanged
```

Job lifecycle states: `queued → running → success | failed | canceled`

## PCI IDs lookup

Load/override order (`LOGPILE_PCI_IDS_PATH` has highest priority because it is loaded last):

1. Embedded `internal/parser/vendors/pciids/pci.ids` (base dataset compiled into binary)
2. `./pci.ids`
3. `/usr/share/hwdata/pci.ids`
4. `/usr/share/misc/pci.ids`
5. `/opt/homebrew/share/pciids/pci.ids`
6. Paths from `LOGPILE_PCI_IDS_PATH` (colon-separated on Unix; later loaded, override same IDs)

This means unknown GPU/NIC model strings can be updated by refreshing `pci.ids`
without any code change.
