# Customer access

VibePackr exposes General User and Packtory Admin operations through the dedicated `PACKR_CUSTOMER_ACCESS_V1` mTLS protocol. The product has no default public listener. Configure an explicit private IP address and port, and apply network policy outside VibePackr.

The examples below describe the supported customer access request shape. The appliance validates server and client configuration, subject bindings, request envelopes, and wire responses in the Rust Core. Internal contract JSON files are build and validation inputs; they are not installed with the customer package.

## Install and initialize

From the extracted release package:

```sh
sudo ./install.sh
sudo systemctl status vibepackr-control-plane.service
sudo /opt/vibepackr/health
```

Installation creates a release-addressed directory under `/opt/vibepackr/releases`, initializes the appliance on first boot, and publishes `/opt/vibepackr/current`. `health` must report `customer_binding_state` as `BOUND`. Customer access remains disabled until a complete mTLS generation is materialized.

## Materialize the server configuration

Prepare DER certificates and a private JSON server config whose certificate paths point to `/etc/vibepackr/customer-access/current/`. Prepare a subject-binding set for the exact installed customer organization and release-manifest digest. Then create a private materialization request:

```json
{
  "schema_version": "vibepackr.access-configuration-file-request.v1",
  "destination_root": "/etc/vibepackr/customer-access",
  "surface": "CUSTOMER_ACCESS",
  "generation_id": "customer-access-20260912-01",
  "server_config_source": "/absolute/private/customer-access-server.json",
  "server_certificate_source": "/absolute/private/server-certificate.der",
  "server_private_key_source": "/absolute/private/server-private-key.der",
  "client_ca_certificate_source": "/absolute/private/client-ca-certificate.der",
  "subject_bindings_source": "/absolute/private/subject-bindings.json"
}
```

Run the bounded materializer and start the listener:

```sh
sudo /opt/vibepackr/current/bin/packr-customer-access-gateway \
  --materialize-request /absolute/private/customer-access-request.json
sudo systemctl start vibepackr-customer-access-gateway.service
sudo /opt/vibepackr/health
```

The materializer validates the complete set and switches generations atomically. A successful result contains `"status":"ACTIVE"`, `"authority_added":false`, and no secret bytes. An incomplete set, reused generation ID, wrong release/customer binding, symlink, or non-private key is rejected without activating a partial generation.

## Invoke the customer endpoint

Create a client config with schema `vibepackr.customer-access-client-config.v1`, the private endpoint, TLS server name, absolute DER paths, bounded timeouts, and a maximum response size. Keep the client private key mode at `0600`. A health request file is:

```json
{
  "protocol_version": "PACKR_CUSTOMER_ACCESS_V1",
  "request_id": "customer-health-01",
  "issued_at": 1789142400,
  "operation": { "type": "HEALTH" }
}
```

```sh
/opt/vibepackr/current/bin/packr-customer-access-client \
  --config /absolute/private/customer-access-client.json \
  --request-file /absolute/private/customer-health.json
```

A ready endpoint returns `SUCCESS`, status `READY`, reason code `CUSTOMER_ACCESS_READY`, `transport_is_authority:false`, and `authority_added:false`. Replace the example `issued_at` value with the current Unix time; stale requests are rejected.

For a General User session, bind the certificate to `customer-access-role:general-user` and send:

```json
{
  "protocol_version": "PACKR_CUSTOMER_ACCESS_V1",
  "request_id": "general-user-session-01",
  "issued_at": 1789142400,
  "operation": {
    "type": "OPEN_GENERAL_USER_SESSION",
    "payload": {
      "request": {
        "origin": "LOCAL_AGENT",
        "allowed_operations": ["INTEGRATION_DISCOVER"],
        "delegation_mode": "NONE",
        "lifetime_seconds": 300
      }
    }
  }
}
```

Success returns reason code `GENERAL_USER_SESSION_OPENED`. Caller-supplied identity, VM Admin operations, generic RPC, and shell commands are not accepted by this interface. Authentication failure, stale request, release/customer mismatch, wrong role, or unknown operation returns a typed reason code and no authority.

## Rotate, revoke, update, and remove

Rotate a certificate by creating a new complete generation with a new generation ID, new certificate material, and updated subject bindings; after it becomes active, restart the gateway and confirm health before retiring the old client credential. Revoke a client by activating a new binding set that omits it. Never edit the active generation in place.

An appliance update installs a new release-addressed directory and preserves customer-owned configuration. Reconcile every subject binding to the new installed release-manifest digest before enabling customer access for that release. Recovery must restore the exact release/customer bindings and mTLS material before the listener is started.

The product-owned retirement entry point is `sudo /opt/vibepackr/uninstall ADMIN_STATE_ROOT REQUEST_FILE CREDENTIAL_FILE`; it invokes the existing authorized Appliance Admin retirement operation. Purging customer-owned certificate/configuration material is a separate explicit operator action and is not implied by retirement.
