Back to blog

Device Abstraction for Multi-Account Management Systems: Four Core Field Groups

When building a multi-account management system, the first thing to define is not the interface but the device-layer fields and lifecycle. A poor abstraction forces cascading rewrites as accounts grow or device types change.

When developing a multi-account management system, most first versions start with the interface: build an account list, attach a browser profile to each account, then call APIs to operate it. It looks sufficient until the system actually runs.

The first implementation is usually very direct. Account A points to profile 001, account B points to profile 002, and account C is attached to a cloud phone. Problems then appear in three places: operations says a machine is broken and asks whether account A can move to the cloud phone, and the answer is database edits, manual work, and risk; a new device source is integrated and the question of how to add it leads to a refactor of the account module; or the same account needs to use a browser environment in the morning and a cloud phone in the afternoon, which is almost impossible to schedule cleanly.

These three scenarios look unrelated, but they share one cause: the account entity contains things that do not belong to it. The currently logged-in device, previously used devices, fingerprint parameters, and egress address are all stored on the account. As a result, changing the device means changing the account, and one change affects everything.

Make devices a separate class of object

Once separated, accounts and devices should have a many-to-many relationship. The account does not store a fingerprint; it only records which device it is currently bound to. Switching devices should be an atomic operation, historical bindings should be kept in a separate table for reference, and each device should have a unique identifier that is the only identifier exposed externally, with status available in real time.

This is not about making the model look elegant. It shortens the distance between an operational adjustment and a code change, and that distance grows with the number of devices.

Four field groups the abstraction layer must define

A device abstraction that can scale only needs to answer four things externally.

  • Environment ID: unique and stable. Upper layers reference an environment only through this ID; internal numbers, container names, and process IDs should not leak out
  • Egress binding: which network egress the environment uses, and whether the associated time zone, language, and DNS are configured as one set. Separating egress means it can be changed without changing the environment itself
  • Status: creating, ready to start, running, occupied by a task, abnormal, awaiting reclamation. Without a status model, pooling and reclamation cannot be managed
  • Lifecycle: who triggers creation, startup, occupation, release, and reclamation; what happens when a task times out; and who cleans up when an environment fails

Status and lifecycle are often merged into one field. That is the easiest approach and also the most expensive. Status answers what the environment is now; lifecycle answers who is allowed to act on it next. In production, the real problems are almost always in the latter: a task crashes and nobody releases the environment, or an environment is reclaimed while it is still running, and only on the next startup does anyone discover that the egress has changed.

账号通过绑定历史连接设备抽象层,再统一接入浏览器环境和移动设备,并由四类字段管理

A bad abstraction sends the bill when you scale

With ten environments, nothing may look wrong. At dozens or hundreds, the problems arrive together:

  • Adding a new device type requires changes to the account module, expanding regression testing from the device layer into the account layer
  • Changing a device requires a database edit, so operations is afraid to touch it and the system gradually becomes maintainable only by developers
  • Without status and occupancy records, environments left behind after abnormal exits are never reclaimed, and zombie environments keep accumulating
  • Upper-layer tasks, content, and automation are all built on a one-to-one account-device assumption, so changing it means reworking the entire chain

Devices from different sources differ greatly in implementation: local browser environments and cloud phones use completely different interfaces. The abstraction layer puts them behind the same set of interfaces. To add a device type, it should be enough to add an adapter that implements start, stop, and status queries; upper-layer logic should not need to change. There is also a rough but useful test for whether the abstraction is sound: when adding a device type, is the code change confined to a single file?

Do as little as possible in the first phase

Once the technical model is settled, the interface becomes much more natural. Organize menus by business objects, with separate areas for accounts, tasks, and devices, rather than by configuration, parameters, and logs. Status and exceptions should be the most visible elements because users are looking for problems, not for a record count.

For functionality, the first phase only needs a device list, a way to add devices, and one minimal end-to-end task flow. Keep the menu as small as possible, get one workflow running first, and postpone anything that is not needed.

If you do not want to implement environment isolation from scratch, you can also rely on existing capabilities. PurpleMark provides independent environments and egress binding, supports batch creation by group and status queries, and leaves the upper layer to implement templates, occupancy, and task scheduling so engineering effort can stay focused on business logic.

The complexity of a multi-account system has never been the number of accounts; it is device lifecycle management. Treat each device first as a resource with an identity, an egress, a status, and a lifecycle, and upper-layer features will not have to be torn down every time something new is added.