File Workspace

TeamsIT EngineersDevelopers

Getting Started

Core Concepts

Manage file transfers separately by workspace

A file workspace groups the files, storage locations, transfer targets, and access scope used for a specific business operation into a single space.

For example, development, content, and data analysis teams can each have a separate workspace with the storage locations and transfer systems required for that work.

text
File Workspace
      │
 ┌────┼───────────────┐
 ▼    ▼               ▼
Files Storage       Access
 │       │             │
 ▼       ▼             ▼
Transfer Targets   Users / Devices

This configuration separates and manages files and transfer environments by workspace across multiple business operations.

Workspace Flow

Continue from file storage through transfer and result confirmation

Users select a workspace for which they have access, then store or review the required files.

When a transfer task connected to the workspace is run, selected files are transferred to the designated system and work environment, and the execution result can be reviewed in the same space.

text
Select Workspace
      │
      ▼
Store · Review Files
      │
      ▼
Run Transfer Task
      │
      ▼
Apply to Destination System
      │
      ▼
Check Processing Result

Separation Benefits

Manage files for multiple operations and systems according to purpose

Organizing workspaces by business purpose provides a single management standard for files, storage locations, transfer targets, and access scope.

CategoryIndividual ManagementWorkspace Management
FilesReview files in multiple locations separatelyManage files by business workspace
Storage LocationsCheck the location for each fileConfigure storage locations by workspace
Transfer TargetsCheck the destination for each taskConnect transfer systems and paths by workspace
Access ScopeReview files by userManage access scope based on the workspace
Result ReviewReview results by taskReview execution results by workspace

Business Teams

Manage and use required files in the workspace

Select a Workspace

View the files and tasks needed for the work in one place

When starting work, select the workspace containing the required files and tasks.

The workspace contains the files used for the business operation and the connected transfer tasks, so users can perform file work in the space needed for their current task.

text
My Workspaces
     │
     ├── Project A
     │      ├── Files
     │      └── Transfers
     │
     ├── Media Team
     │      ├── Files
     │      └── Transfers
     │
     └── Data Analysis
            ├── Files
            └── Transfers

Use Files

Store required files and use them for the next task

Store the files required for work in the workspace and review the files needed for the current task.

Stored files can be used together with the business flows connected to the workspace, allowing users to select the required file and continue to the next task.

text
Workspace
    │
    ├── Upload Files
    │
    ├── Browse Files
    │
    └── Select Files
            │
            ▼
        Next Work

Run a Transfer

Send files using a prepared transfer task

After selecting the required files, run the transfer task configured in the workspace.

Users can select the files and task needed for the current work, then review progress and processing results.

text
Select Files
      │
      ▼
Select Transfer
      │
      ▼
Run
      │
 ┌────┴────┐
 ▼         ▼
Progress   Target
 │         │
 └────┬────┘
      ▼
   Result

Business teams can manage the required files in the workspace and continue to the next task using the prepared transfer flow.

IT Engineers

Configure and manage file workspaces and transfer environments centrally

Workspace Configuration

Configure file storage locations and management scope by business purpose

Create workspaces according to business purpose, then configure the file storage locations and management scope used in each space.

For example, development outputs, media files, and data-processing results can each be configured in separate workspaces.

text
Organization
      │
 ┌────┼───────────────┐
 ▼    ▼               ▼
Dev  Media           Data
 │     │               │
 ▼     ▼               ▼
Storage Storage      Storage

Connect workspaces with destination systems and file paths

Connect the transfer target systems and file paths used by each workspace.

Connect servers, storage systems, and business devices to a workspace and configure file transfer paths to build the transfer environment for each business operation.

text
Workspace
     │
     ├── Source Storage
     │
     ├── Transfer Flow
     │
     └── Target Devices
             │
      ┌──────┼──────┐
      ▼      ▼      ▼
   Server  Storage  System

Access Policy

Manage access scope and transfer rules by user and system

For each workspace, configure the access scope of users and groups, connectable systems, file paths, and transfer tasks that can be run.

When the business environment or user configuration changes, access scope and processing criteria can be adjusted from the same policy screen.

text
Workspace Policy
       │
 ┌─────┼────────────┐
 ▼     ▼            ▼
Users Groups      Devices
 │       │            │
 ▼       ▼            ▼
Access  Operations  Paths
             │
             ▼
       Transfer Rules

Management ItemSetting
WorkspaceWorkspace for users and business operations
Users / GroupsUsers and groups that use the workspace
DevicesSystems that can be connected
PathsPaths where files are used
OperationsFile tasks that can be run
Transfer RulesFile transfer criteria and processing rules

Operations Management

Review transfer results by workspace together with the overall operational status

Review file transfers and processing results executed in each workspace, while centrally managing the status of multiple workspaces and connected systems.

Operators can review the execution status of a specific workspace or understand the overall operational situation based on the status of the entire environment.

text
Central Management
        │
 ┌──────┼───────────────┐
 ▼      ▼               ▼
Workspace Devices      Runs
 │        │              │
 └────────┼──────────────┘
          ▼
     Operations View

Workspaces can be configured and managed through the following flow.

text
Configure Workspace
       │
       ▼
Connect Storage Location
       │
       ▼
Configure Destination Systems · Transfer Paths
       │
       ▼
Configure User · System Access Policies
       │
       ▼
Run Transfer Task
       │
       ▼
Review Workspace · Overall Operational Status

Developers

Send the workspace identifier and token with each request and handle authorization responses

Authentication

Obtain an access token and refresh it when it expires

The workspace API authenticates with an access token. If no token is available, log in to the account to obtain one.

import os
import threading

import requests

BASE_URL = os.getenv("INNORIX_BASE_URL", "https://app.innorix.com").rstrip("/")


def login(email, password):
    response = requests.post(f"{BASE_URL}/api/auth/login",
                             json={"email": email, "password": password},
                             timeout=30)
    response.raise_for_status()

    # the login response nests the tokens under data.user
    user = response.json()["data"]["user"]
    return user["accessToken"], user.get("refreshToken")


def refresh(refresh_token):
    response = requests.post(f"{BASE_URL}/api/auth/token/refresh",
                             headers={"X-Refresh-Token": refresh_token},
                             timeout=30)
    response.raise_for_status()

    # the refresh response nests the tokens directly under data
    data = response.json()["data"]
    return data["accessToken"], data.get("refreshToken")

The response structures for login and refresh are different. Login returns data under data.user, while refresh returns it directly under data.

A refresh token is valid only once. In a server application where multiple threads use the same token, lock the refresh operation so it cannot occur concurrently.

class Session:
    def __init__(self, email, password):
        self._lock = threading.Lock()
        self._access, self._refresh = login(email, password)

    @property
    def access_token(self):
        with self._lock:
            return self._access

    def renew(self):
        with self._lock:
            self._access, self._refresh = refresh(self._refresh)
            return self._access

Assign a Workspace

Send the workspace identifier with every request

The workspace is passed in a header, not in the request body. Setting it directly at each call site can cause omissions, so centralize request construction in one place.

class Client:
    def __init__(self, session, workspace_id=None):
        self.session = session
        self.workspace_id = workspace_id

    def request(self, method, path, body=None, params=None, retried=False):
        headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {self.session.access_token}",
        }

        # when omitted the account's current workspace is used
        if self.workspace_id:
            headers["x-workspace-id"] = self.workspace_id

        response = requests.request(method, BASE_URL + path, headers=headers,
                                    json=body, params=params, timeout=30)

        if response.status_code == 401 and not retried:
            self.session.renew()
            return self.request(method, path, body, params, retried=True)

        return response

If no workspace identifier is specified, the account's currently accessible workspace is used. An application using a single workspace can operate without specifying one.

Token expiration is handled here as well. When 401 is received, refresh once and retry; if the retried request fails again, propagate the failure unchanged.

Check Access Scope

Check the account's view scope and accessible systems

me = api("GET", "/api/auth/me") or {}
print(me)

result = api("GET", "/api/devices", params={"page": 1, "size": 20}) or {}

if result.get("viewScope"):
    print("view scope:", result["viewScope"])

for device in result.get("devices") or []:
    print(device["deviceId"], device["name"])
Response ItemDetails
devicesList of systems connected to the workspace
totalRows · lastPageTotal count and last page
viewScopeCurrent account view scope

The device list is returned in the data.devices array. Use viewScope in the response to determine whether the account can view everything or only a subset.

Permission Handling

Distinguish 401 and 403 and handle them as reauthentication or user guidance

Authentication failure and insufficient permissions must be handled differently. The former requires reauthentication; the latter requires user guidance.

StatusMeaningHandling
401Token is missing or invalidRefresh and retry; if it fails, sign in again
403Workspace or path is inaccessibleInform the user
404System or path does not existInform the user that the target is unavailable
429Too many requestsRetry after a short delay
class WorkspaceForbidden(Exception):
    pass


def call(client, method, path, body=None, params=None):
    response = client.request(method, path, body, params)

    if response.status_code == 403:
        raise WorkspaceForbidden(path)

    payload = response.json() if response.content else {}

    if not response.ok:
        raise RuntimeError(payload.get("message") or f"HTTP {response.status_code}")

    return payload.get("data")


try:
    devices = call(client, "GET", "/api/devices")
except WorkspaceForbidden:
    devices, notice = [], "no permission to access this workspace"

Separating insufficient permissions into a dedicated exception lets the calling code turn it into a user-facing message. Because results can differ for the same user depending on the workspace, display the current workspace at the top of the screen so users do not mistake an empty list for a permissions problem.

Multi-Workspace Handling

Separate credentials in code that handles multiple workspaces

Passing the workspace identifier as a function argument can lead to it being omitted somewhere in the call chain. Create a client for each workspace and pass the client object instead.

clients = {
    workspace_id: Client(session, workspace_id)
    for workspace_id in WORKSPACE_IDS
}


def collect_devices():
    result = {}

    for workspace_id, client in clients.items():
        try:
            result[workspace_id] = call(client, "GET", "/api/devices")
        except WorkspaceForbidden:
            continue

    return result

There is no endpoint for listing workspaces. Check by providing candidate workspaces and filtering to the ones the account can access.

If accounts differ by customer, separate the sessions as well. Keep their creation points separate so they are not mixed with a configuration where one session is shared across multiple workspaces.

def build_client(config):
    session = Session(config["email"], config["password"])
    return Client(session, config["workspace_id"])


clients = {name: build_client(cfg) for name, cfg in TENANTS.items()}

A batch that iterates through multiple workspaces should prevent a failure in one workspace from stopping the entire batch.

failed = []

for name, client in clients.items():
    try:
        run_for(client)
    except Exception as error:
        failed.append((name, error))

for name, error in failed:
    print(f"{name}: {error}")
Management ItemHandled in Code
SessionAccount-level access and refresh tokens
WorkspaceWorkspace identifier in the request header
Permissions403 response and user guidance
ResourcesWorkspace-specific systems and view scope
ExecutionTransfers created within the workspace