> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sensorup.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Core Platform Guide

> Working with platform services including authentication, user management, geospatial operations, data catalogs, and event streaming.

# Core Platform Guide

The Core Platform API provides foundational services that underpin all SensorUp operations. It includes authentication (`su-auth`), user management (`su-user`), core infrastructure (`su-backend`), geospatial services (`su-maps`), data catalogs (`su-catalog`), and event streaming (`su-eventhub`).

## Overview

The Core Platform enables:

* **Authentication**: Session management, API keys, and federated sign-in
* **User Management**: User profiles, permissions, and device tracking
* **Geospatial Services**: Maps, location queries, and spatial operations
* **Data Catalogs**: Schema registry and metadata management
* **Event Streaming**: Real-time event subscriptions and notifications
* **Core Infrastructure**: Configuration, health checks, and system operations

## Authentication (su-auth)

For comprehensive authentication documentation, see the **[Authentication Guide](../authentication)**.

### Quick Reference

**Session-based Authentication:**

```graphql theme={null}
mutation SignIn($input: AuthSignInInput!) {
  signIn(input: $input) {
    session {
      username
      authenticated
      expiresAt
      expiresAtHard
      userGroup
    }
    correlationId
    errors { message type }
  }
}
```

**Check Current Session:**

```graphql theme={null}
query {
  session {
    username
    authenticated
    expiresAt
    userGroup
    lastAuthenticatedAt
  }
}
```

**API Key Creation:**

```graphql theme={null}
mutation CreateAPIKey($input: AuthCreateAPIKeyInput!) {
  createAPIKey(input: $input) {
    apiKey {
      apiKeyId
      apiKeySessionId
      expiresAt
    }
    correlationId
    errors { message type }
  }
}
```

### Session Lifetimes

| Client Type       | Hard Expiry | Soft Expiry (Idle) |
| ----------------- | ----------- | ------------------ |
| Explorer (Web)    | 30 days     | 7 days             |
| SensorHub Android | 365 days    | 60 days            |
| SensorHub iOS     | 365 days    | 60 days            |
| API Key           | 365 days    | 60 days            |

### Authentication Methods

* **Cookie**: `sensorup_sessionid` (auto-set in browser)
* **Header**: `x-sensorup-sessionid` (for API clients and M2M)

```bash theme={null}
curl -X POST https://customer-demo.sensorup.com/api/graphql \
  -H "Content-Type: application/json" \
  -H "x-sensorup-sessionid: YOUR_SESSION_ID" \
  -d '{"query":"{ session { username } }"}'
```

## User Management (su-user)

### Query User Profile

```graphql theme={null}
query GetUser($userId: ID!) {
  user(id: $userId) {
    userId
    username
    email
    firstName
    lastName
    phoneNumber
    preferredLanguage
    timezone
    groups
    permissions {
      resource
      actions
    }
    devices {
      deviceKey
      name
      remembered
      lastSignedInAt
      lastIpAddress
    }
  }
}
```

### Update User Profile

```graphql theme={null}
mutation UpdateUser($input: UpdateUserInput!) {
  updateUser(input: $input) {
    user {
      userId
      firstName
      lastName
      email
      phoneNumber
    }
    correlationId
    errors {
      message
      type
    }
  }
}
```

**Variables:**

```json theme={null}
{
  "input": {
    "userId": "user-123",
    "firstName": "John",
    "lastName": "Smith",
    "phoneNumber": "+1-555-0100",
    "timezone": "America/Edmonton"
  }
}
```

### Query User Permissions

```graphql theme={null}
query GetUserPermissions($userId: ID!) {
  user(id: $userId) {
    userId
    username
    groups
    permissions {
      resource
      actions
      scope
    }
    roles {
      roleId
      roleName
      permissions {
        resource
        actions
      }
    }
  }
}
```

### List Users in Group

```graphql theme={null}
query GetGroupUsers($group: ID!) {
  users(group: $group) {
    all(first: 100) {
      edges {
        node {
          userId
          username
          email
          firstName
          lastName
          active
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}
```

### Device Management

```graphql theme={null}
query GetUserDevices($userId: ID!) {
  user(id: $userId) {
    devices {
      deviceKey
      name
      remembered
      createdAt
      lastSignedInAt
      lastIpAddress
      userAgent
    }
  }
}
```

**Forget Device:**

```graphql theme={null}
mutation ForgetDevice($input: AuthForgetSpecificDevicesInput!) {
  forgetDevices(input: $input) {
    session {
      username
    }
    correlationId
    errors { message type }
  }
}
```

## Geospatial Services (su-maps)

### Query Map Configuration

```graphql theme={null}
query GetMapConfig {
  maps {
    config {
      defaultCenter {
        lat
        lon
      }
      defaultZoom
      baseLayers {
        id
        name
        type
        url
        attribution
      }
      overlayLayers {
        id
        name
        type
        url
      }
    }
  }
}
```

### Get Map Tiles

```graphql theme={null}
query GetMapTiles($bounds: BoundsInput!, $zoom: Int!) {
  maps {
    tiles(bounds: $bounds, zoom: $zoom) {
      tileUrl
      bounds {
        north
        south
        east
        west
      }
      zoom
    }
  }
}
```

**Variables:**

```json theme={null}
{
  "bounds": {
    "north": 51.1,
    "south": 51.0,
    "east": -114.0,
    "west": -114.1
  },
  "zoom": 12
}
```

### Geocoding

```graphql theme={null}
query Geocode($address: String!) {
  maps {
    geocode(address: $address) {
      results {
        formattedAddress
        geometry {
          location {
            lat
            lon
          }
          bounds {
            north
            south
            east
            west
          }
        }
        placeId
        types
      }
    }
  }
}
```

**Variables:**

```json theme={null}
{
  "address": "Calgary, Alberta, Canada"
}
```

### Reverse Geocoding

```graphql theme={null}
query ReverseGeocode($lat: Float!, $lon: Float!) {
  maps {
    reverseGeocode(lat: $lat, lon: $lon) {
      results {
        formattedAddress
        addressComponents {
          longName
          shortName
          types
        }
        placeId
      }
    }
  }
}
```

**Variables:**

```json theme={null}
{
  "lat": 51.0447,
  "lon": -114.0719
}
```

### Spatial Queries

```graphql theme={null}
query FindNearbyAssets($location: LocationInput!, $radiusKm: Float!) {
  maps {
    findNearby(location: $location, radius: $radiusKm) {
      results {
        id
        type
        distance
        geometry {
          type
          coordinates
        }
        properties
      }
    }
  }
}
```

**Variables:**

```json theme={null}
{
  "location": {
    "lat": 51.0447,
    "lon": -114.0719
  },
  "radiusKm": 10.0
}
```

### GeoJSON Support

The platform supports full GeoJSON geometry types:

```graphql theme={null}
type GeoJSONGeometry {
  type: GeoJSONType!  # Point, LineString, Polygon, etc.
  coordinates: GeoJSONCoordinates
  bbox: [Float]
}

enum GeoJSONType {
  Point
  MultiPoint
  LineString
  MultiLineString
  Polygon
  MultiPolygon
  GeometryCollection
  Feature
  FeatureCollection
}
```

**Example Point:**

```json theme={null}
{
  "type": "Point",
  "coordinates": [-114.0719, 51.0447]
}
```

**Example Polygon:**

```json theme={null}
{
  "type": "Polygon",
  "coordinates": [[
    [-114.073, 51.045],
    [-114.071, 51.045],
    [-114.071, 51.044],
    [-114.073, 51.044],
    [-114.073, 51.045]
  ]]
}
```

## Data Catalogs (su-catalog)

### Query Catalog Entries

```graphql theme={null}
query GetCatalogEntries {
  catalog {
    entries(first: 100) {
      edges {
        node {
          id
          name
          description
          schema
          dataType
          category
          tags
          createdAt
          updatedAt
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}
```

### Get Specific Catalog Entry

```graphql theme={null}
query GetCatalogEntry($id: ID!) {
  catalog {
    entry(id: $id) {
      id
      name
      description
      schema
      dataType
      category
      tags
      metadata
      validationRules {
        rule
        message
      }
    }
  }
}
```

### Create Catalog Entry

```graphql theme={null}
mutation CreateCatalogEntry($input: CreateCatalogEntryInput!) {
  createCatalogEntry(input: $input) {
    catalogEntry {
      id
      name
      schema
    }
    correlationId
    errors {
      message
      type
    }
  }
}
```

**Variables:**

```json theme={null}
{
  "input": {
    "id": "pressure-reading",
    "name": "Pressure Reading",
    "description": "Equipment pressure sensor reading",
    "dataType": "numeric",
    "schema": {
      "type": "object",
      "properties": {
        "value": { "type": "number" },
        "unit": { "type": "string", "enum": ["psi", "kPa", "bar"] },
        "timestamp": { "type": "string", "format": "date-time" }
      },
      "required": ["value", "unit", "timestamp"]
    },
    "category": "sensor-data",
    "tags": ["pressure", "sensor", "telemetry"]
  }
}
```

### Query by Category

```graphql theme={null}
query GetCatalogByCategory($category: String!) {
  catalog {
    byCategory(category: $category) {
      id
      name
      description
      dataType
    }
  }
}
```

**Variables:**

```json theme={null}
{
  "category": "sensor-data"
}
```

## Event Streaming (su-eventhub)

### Subscribe to Events

```graphql theme={null}
subscription OnEvents($filter: EventFilter) {
  events(filter: $filter) {
    eventId
    eventType
    source
    timestamp
    data
    correlationId
  }
}
```

**Variables (Filter by Event Type):**

```json theme={null}
{
  "filter": {
    "eventTypes": ["ASSET_CREATED", "ASSET_UPDATED", "ISSUE_CREATED"]
  }
}
```

### Publish Event

```graphql theme={null}
mutation PublishEvent($input: PublishEventInput!) {
  publishEvent(input: $input) {
    event {
      eventId
      eventType
      timestamp
    }
    correlationId
    errors {
      message
      type
    }
  }
}
```

**Variables:**

```json theme={null}
{
  "input": {
    "eventType": "CUSTOM_EVENT",
    "source": "integration-service",
    "data": {
      "action": "data_sync_completed",
      "recordsProcessed": 1500,
      "duration": 45.2
    }
  }
}
```

### Query Event History

```graphql theme={null}
query GetEventHistory($filter: EventFilter!, $first: Int!) {
  eventHub {
    history(filter: $filter, first: $first) {
      edges {
        node {
          eventId
          eventType
          source
          timestamp
          data
        }
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}
```

**Variables:**

```json theme={null}
{
  "filter": {
    "eventTypes": ["ASSET_CREATED"],
    "from": "2025-11-01T00:00:00Z",
    "to": "2025-11-05T23:59:59Z"
  },
  "first": 100
}
```

### Event Types

Common system event types:

| Event Type          | Description               |
| ------------------- | ------------------------- |
| `ASSET_CREATED`     | New asset created         |
| `ASSET_UPDATED`     | Asset modified            |
| `ASSET_DELETED`     | Asset removed             |
| `ISSUE_CREATED`     | New issue opened          |
| `ISSUE_UPDATED`     | Issue modified            |
| `ISSUE_CLOSED`      | Issue resolved and closed |
| `DETECTION_CREATED` | New detection recorded    |
| `FORM_SUBMITTED`    | XForm response submitted  |
| `USER_SIGNED_IN`    | User authentication       |
| `API_KEY_CREATED`   | New API key generated     |

## Core Infrastructure (su-backend)

### System Configuration

```graphql theme={null}
query GetConfig {
  config {
    environment
    version
    features {
      name
      enabled
      configuration
    }
    auth {
      loginEnabled
      ssoEnabled
      ssoUrl
      mfaRequired
    }
    integrations {
      name
      type
      endpoint
      active
    }
  }
}
```

### Health Check

```graphql theme={null}
query HealthCheck {
  health {
    status
    version
    timestamp
    services {
      name
      status
      latency
      lastCheck
    }
  }
}
```

### Feature Flags

```graphql theme={null}
query GetFeatureFlags {
  features {
    all {
      featureId
      name
      enabled
      rolloutPercentage
      conditions {
        type
        value
      }
    }
  }
}
```

**Check Specific Feature:**

```graphql theme={null}
query IsFeatureEnabled($featureId: ID!, $context: FeatureContext) {
  features {
    isEnabled(featureId: $featureId, context: $context)
  }
}
```

### System Metrics

```graphql theme={null}
query GetSystemMetrics {
  metrics {
    apiCalls {
      total
      byEndpoint {
        endpoint
        count
        avgLatency
      }
    }
    errors {
      total
      byType {
        type
        count
      }
    }
    performance {
      avgResponseTime
      p95ResponseTime
      p99ResponseTime
    }
  }
}
```

## Common Patterns

### Authentication Flow

```javascript theme={null}
// 1. Sign in
const { data } = await client.mutate({
  mutation: SIGN_IN,
  variables: {
    input: {
      loginUsername: 'user@example.com',
      password: 'password',
      clientApplicationType: 'EXPLORER'
    }
  }
})

// 2. Store session ID
const sessionId = data.signIn.session.sessionId

// 3. Use in subsequent requests
const result = await fetch('https://customer-demo.sensorup.com/api/graphql', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-sensorup-sessionid': sessionId
  },
  body: JSON.stringify({ query: '{ session { username } }' })
})
```

### Geospatial Queries

```javascript theme={null}
// Find assets near a location
async function findAssetsNearLocation(lat, lon, radiusKm) {
  const { data } = await client.query({
    query: FIND_NEARBY,
    variables: { location: { lat, lon }, radiusKm }
  })

  return data.maps.findNearby.results
}

// Geocode an address
async function getCoordinates(address) {
  const { data } = await client.query({
    query: GEOCODE,
    variables: { address }
  })

  return data.maps.geocode.results[0].geometry.location
}
```

### Event Streaming

```javascript theme={null}
// Subscribe to real-time events
const subscription = client.subscribe({
  query: ON_EVENTS,
  variables: {
    filter: {
      eventTypes: ['ASSET_CREATED', 'ISSUE_CREATED']
    }
  }
}).subscribe({
  next: ({ data }) => {
    console.log('New event:', data.events)
    handleEvent(data.events)
  },
  error: (error) => console.error('Subscription error:', error)
})

// Cleanup
subscription.unsubscribe()
```

### Catalog-Driven Forms

```javascript theme={null}
// Use catalog to validate form data
async function validateFormData(dataType, data) {
  // Get schema from catalog
  const { data: catalogData } = await client.query({
    query: GET_CATALOG_ENTRY,
    variables: { id: dataType }
  })

  const schema = catalogData.catalog.entry.schema

  // Validate against schema
  const valid = validateAgainstJsonSchema(data, schema)

  return valid
}
```

## Best Practices

### 1. Session Management

Monitor session expiration and refresh proactively:

```javascript theme={null}
// Check session expiration
const { data } = await client.query({ query: GET_SESSION })
const expiresAt = new Date(data.session.expiresAt)
const now = new Date()

// Refresh if expiring soon (within 1 hour)
if (expiresAt - now < 3600000) {
  await refreshSession()
}
```

### 2. Geospatial Performance

Use appropriate zoom levels and bounds for map tiles:

```graphql theme={null}
# Good - reasonable bounds
maps { tiles(bounds: { ... }, zoom: 12) }

# Avoid - excessive detail over large area
maps { tiles(bounds: { ... }, zoom: 18) }
```

### 3. Event Filtering

Subscribe only to needed event types:

```graphql theme={null}
# Good - filtered subscription
subscription { events(filter: { eventTypes: ["ASSET_CREATED"] }) }

# Avoid - unfiltered (high volume)
subscription { events }
```

### 4. Catalog Validation

Leverage catalog schemas for data validation:

```graphql theme={null}
# 1. Get schema from catalog
catalog { entry(id: "sensor-reading") { schema } }

# 2. Validate data client-side before submission
# 3. Submit validated data
```

### 5. Permission Checks

Always verify user permissions before restricted operations:

```graphql theme={null}
query CheckPermission($userId: ID!, $resource: String!, $action: String!) {
  user(id: $userId) {
    permissions {
      resource
      actions
    }
  }
}
```

## Error Handling

Platform mutations return consistent error formats:

```json theme={null}
{
  "data": {
    "updateUser": {
      "user": null,
      "correlationId": "abc-123",
      "errors": [
        {
          "message": "Invalid email address format",
          "type": "VALIDATION_ERROR"
        }
      ]
    }
  }
}
```

Common error types:

* `AUTHENTICATION_FAILED`: Invalid credentials
* `AUTHORIZATION_FAILED`: Insufficient permissions
* `VALIDATION_ERROR`: Input validation failed
* `NOT_FOUND`: Resource does not exist
* `DUPLICATE`: Resource already exists
* `RATE_LIMIT_EXCEEDED`: Too many requests

## Related Resources

* **[Authentication Guide](../authentication)** - Comprehensive auth documentation
* **[Auth Subgraph Reference](../subgraphs/auth)** - Complete auth schema
* **[User Subgraph Reference](../subgraphs/user)** - User management schema
* **[Maps Subgraph Reference](../subgraphs/maps)** - Geospatial schema
* **[Catalog Subgraph Reference](../subgraphs/catalog)** - Catalog schema
* **[EventHub Subgraph Reference](../subgraphs/eventhub)** - Event streaming schema
* **[Backend Subgraph Reference](../subgraphs/backend)** - Core infrastructure schema
* **[Common Patterns](../common-patterns)** - Pagination, filtering, and error handling
