Domains are, more or less, the equivalent of an organizational unit. Domains (generally) don't own resources, but they can impose resource limits upon all accounts held within them. Domains can house projects and accounts, but domains don't really own any instances, volumes, or other resources on their own. A domain is basically a container for other things which can own resources such as instances, volumes, networks, snapshots, templates, etc. Domains must be unique to their parent (ROOT/dom1, ROOT/dom2, etc), however they can repeat if they are a child of another domain (ROOT/dom1/sub1 and ROOT/dom2/sub1 is acceptable even though "sub1" is not unique, it is unique to its parent).
The root domain is somewhat special because all domains are a child of this parent domain. An admin account of the ROOT domain has the ability to manipulate (via the API) other resources belonging to all child domains (e.g. ALL domains, because all domains are a child of ROOT). So admin accounts of the ROOT domain have global admin privileges.
At the time of writing, Cloudstack doesn't currently support RBAC, so permissions exist at two levels – Admin and User. Account names must be unique to a domain, but not unique to all domains (e.g. email@example.com and firstname.lastname@example.org are acceptable because although "joe" is not unique foo.tld and bar.tld are separate domains).
An admin account has domain admin privileges. It is still constrained to domain limitations set by the ROOT admin on that domain (# of instances permitted, # of volumes, etc) but it has more privileges. For example, a domain admin can create additional accounts within a domain or generate API keys for users. It can also create sub-domains within its own domain and report on their resource utilization. For a full list of the differences, please see the API guide.
A user account has privileges to create new resources (instances, volumes, snapshots, etc) but very little administrative privileges. At this time, user accounts cannot generate API keys or additional users within their account, they can only view them. For a full list of commands available to users, please consult the API guide.
Usernames, passwords, and API keys belong to an account. This is the username & password you would log into the Web UI with (and if you generated an API key, the API key you would use for making API calls). Usernames must be unique to the domain they belong to (e.g. two users within the domain foo.tld cannot have the same username – you can't have two email@example.com users), but they can be duplicative between multiple domains (e.g. firstname.lastname@example.org and email@example.com). Users do not own any resources, they are simply used as a means to manipulate and access resources owned by the account they are a part of. Users cannot have separate permissions between them, they inherit the permissions of the account they belong to.
Accounts own resources. This is extremely important so I'll state it again: Accounts own resources. If you delete an account all resources associated with it (instances, volumes, snapshots, etc) will be removed as well. Usage is also tracked at an account level. So for billing or chargeback purposes, if the usage module is enabled, reporting is available for resources used at an account level.
Projects are similar to accounts but unique in one special aspect. Projects can share control of resources amongst multiple accounts. The resources themselves (instances, volumes, snapshots, etc) are owned by the project and are allowed to be manipulated by multiple accounts within the same domain. So if there was a joint project being worked on by multiple departments within an organization a project could be created and could invite other accounts (departments in the organization) to take part in the project. With a project, one account must be delegated as the project administrator. A project admin has the ability to invite and revoke access to other accounts within the domain with regard to access on that project. A project admin only has control of the project and has no other authority over other accounts (e.g. it cannot impose account-level restrictions such as limits on the number of instances, volumes, snapshots, etc permitted), only over which accounts can access the project. While there can only be one project admin, it can be moved between accounts without affecting anything because all resources created by the project are owned by the project and not the individual accounts that are participating in it.