# K1 users
`K1Users` registers an account and its permanent Person anchor as one consumer-facing user view. The caller keeps the supplied Accounts facade for authentication and authorization.
## Public API
```rust
use std::sync::Arc;
use kcode_k1_accounts::{K1Accounts, PersonId};
use kcode_k1_invites::{InviteCode, UserId};
use kcode_k1_persons::K1Persons;
pub struct NewUser;
impl NewUser {
pub fn new(
username: &str,
full_name: &str,
public_key: [u8; 32],
tos_revision: u64,
tos_digest: [u8; 32],
acceptance_signature: [u8; 64],
) -> Result<Self, String>;
pub fn username(&self) -> &str;
pub fn full_name(&self) -> &str;
pub fn public_key(&self) -> [u8; 32];
pub fn tos_revision(&self) -> u64;
pub fn tos_digest(&self) -> [u8; 32];
pub fn acceptance_signature(&self) -> [u8; 64];
}
pub struct User;
impl User {
pub fn user_id(&self) -> UserId;
pub fn username(&self) -> &str;
pub fn person_anchor_id(&self) -> PersonId;
pub fn person_id(&self) -> PersonId;
pub fn full_name(&self) -> &str;
pub fn public_key(&self) -> [u8; 32];
pub fn tos_revision(&self) -> u64;
pub fn tos_digest(&self) -> [u8; 32];
pub fn acceptance_signature(&self) -> [u8; 64];
}
pub struct K1Users;
impl K1Users {
pub fn new(accounts: Arc<K1Accounts>, persons: Arc<K1Persons>) -> Self;
pub fn register(&self, code: &InviteCode, user: NewUser) -> Result<User, String>;
pub fn get(&self, user_id: UserId) -> Result<Option<User>, String>;
pub fn find_by_username(&self, username: &str) -> Result<Option<User>, String>;
}
```
All three public types are `Send + Sync`. Their fields are private, and `NewUser` and `User` expose immutable values.
## Validation and behavior
`NewUser::new` applies the Accounts username, key, current Terms, digest, and signature validation. A full name preserves exact UTF-8, must contain 1 through 128 bytes, must contain no control character, and must contain a non-whitespace character.
Registration serializes calls through this facade. An existing username returns its current User only when every submitted Account field except the Person anchor matches; the submitted full name is then ignored and neither Persons nor Invites is mutated. A mismatch returns `username already registered` before either mutation.
A new username creates one Person with the exact full name and submits one Account registration with that anchor. There is no retry or deletion; if Account registration fails after Person creation, that Person remains orphaned.
Every returned User resolves the immutable Account anchor through a fresh Persons read. `person_anchor_id` remains the registered anchor, while `person_id` and `full_name` reflect current canonical resolution and updates. A missing anchored Person is an error rather than an absent User.
## Performance
Construction is linear in username, full-name, and fixed Terms verification work; reads use expected constant-time dependency lookups plus one name copy, while serialized registration performs at most one synchronous Person creation and one Account registration without a facade timeout or retry.