NAME

Concierge::Users - User data management with multiple storage backends

VERSION

v0.7.3

SYNOPSIS

use Concierge::Users;

# One-time setup -- creates storage and config file
my $result = Concierge::Users->setup({
    storage_dir             => './data/users',
    backend                 => 'database',    # 'database', 'file', or 'yaml'
    include_standard_fields => 'all',
    app_fields              => ['role', 'theme'],
});

# Runtime -- load from saved config
my $users = Concierge::Users->new('./data/users/users-config.json');

# Register a user
my $result = $users->register_user({
    user_id => 'alice',
    moniker => 'Alice',
    email   => 'alice@example.com',
});

# Retrieve a user
my $result = $users->get_user('alice');
my $data   = $result->{user};

# Update a user
$users->update_user('alice', { email => 'new@example.com' });

# List users (optionally with filters)
my $result = $users->list_users('user_status=Active');
my @ids    = @{ $result->{user_ids} };

# Delete a user
$users->delete_user('alice');

DESCRIPTION

Concierge::Users manages user data records with a two-phase lifecycle:

1. Setup (one-time) -- Concierge::Users->setup(\%config) configures the storage backend, defines the field schema, and writes a JSON config file.
2. Runtime -- Concierge::Users->new($config_file) loads the saved config and provides CRUD operations.

All public methods return hashrefs with a success key (1 or 0) and a message on failure:

{ success => 1, user_id => 'alice', user => \%data }
{ success => 0, message => 'User not found' }

Concierge::Users is the user data component of the Concierge suite, alongside Concierge::Auth (password authentication) and Concierge::Sessions (session management). It can also be used standalone.

Storage Backends

file -- CSV/TSV flat file. Simple, human-readable, no database dependency.
yaml -- One YAML file per user via YAML::Tiny. Good for individual user access patterns.

All backends provide the same CRUD API. The backend is selected at setup time and recorded in the config file.

Field System

Every user record has two required fields: user_id and moniker. Beyond these, the field schema is configured at setup time from four categories:

Core (4): user_id, moniker, user_status, access_level -- always present.

Standard (12): first_name, middle_name, last_name, prefix, suffix, organization, title, email, phone, text_ok, last_login_date, term_ends -- included by default. Select specific ones with an arrayref, or pass an empty arrayref [] to exclude all standard fields.

System (2): last_mod_date, created_date -- auto-managed timestamps, protected from overrides and API writes.

Application: Custom fields defined with app_fields as name strings or full definition hashrefs.

Field definitions can also be modified with field_overrides. See "FIELD CATALOG" in Concierge::Users::Meta for complete field details and "FIELD CUSTOMIZATION" in Concierge::Users::Meta for the customization guide.

Validation

Field values are validated on register_user and update_user. Ten validator types are available:

text, email, phone, date, timestamp, boolean, integer, enum, moniker, name.

Each field's validator is determined by its validate_as attribute, or by type as a fallback. Fields where must_validate is 1 will reject the entire operation on failure. Fields where must_validate is 0 produce a non-fatal warning and the invalid value is dropped.

Set the environment variable USERS_SKIP_VALIDATION to a true value to bypass all validation (useful for bulk imports or testing).

See "VALIDATOR TYPES" in Concierge::Users::Meta for accepted patterns and null values for each type.

Data Archiving

Calling setup() when data already exists automatically archives the existing data (renamed with a timestamp suffix) before creating new storage. This prevents accidental data loss during schema changes.

METHODS

setup

my $result = Concierge::Users->setup(\%config);

One-time initialization. Creates the storage directory, backend storage, and writes the config files (JSON and YAML).

Configuration keys:

storage_dir (required) -- directory for data files; created if absent.
backend (required) -- 'database', 'file', or 'yaml'.
include_standard_fields -- Optional. When omitted or set to 'all', all 12 standard fields are included (the default). Pass an arrayref of field names to select specific standard fields, or an empty arrayref [] to exclude all standard fields.
app_fields -- arrayref of application-specific field names (strings) or field definition hashrefs.
file_format -- 'csv' or 'tsv' (file backend only; default 'tsv').
field_overrides -- arrayref of hashrefs that modify built-in field definitions. Core enum fields like user_status and access_level cannot be removed, but their options can be replaced to fit your application. See "Field Overrides" in Concierge::Users::Meta.

Returns { success => 1, config_file => $path } on success.

Croaks if storage_dir or backend is missing, or if the directory cannot be created.

new

my $users = Concierge::Users->new($config_file);

Loads a previously created config file and instantiates the backend.

Croaks if the config file does not exist, cannot be parsed, or the backend module cannot be loaded.

register_user

my $result = $users->register_user(\%user_data);

Registers a new user. %user_data must include user_id and moniker. Additional fields are validated against the schema and stored. Fields not in the schema are silently ignored.

User IDs must be 2-30 characters (alphanumeric plus ., _, @, -). Monikers must be 2-24 alphanumeric characters.

Returns { success => 1, message => "User 'id' created" } on success. May include a warnings arrayref for non-fatal validation issues.

get_user

my $result = $users->get_user($user_id);
my $result = $users->get_user($user_id, { fields => [qw/email phone/] });

Retrieves a user record. With the fields option, returns only the specified fields (user_id is always included).

Returns { success => 1, user_id => $id, user => \%data }.

update_user

my $result = $users->update_user($user_id, \%updates);

Updates an existing user record. The user_id, created_date, and last_mod_date fields are stripped from updates automatically. Remaining fields are validated before writing.

Returns { success => 1 } on success.

list_users

my $result = $users->list_users();
my $result = $users->list_users('user_status=OK');
my $result = $users->list_users('access_level=staff|access_level=admin');

Returns user IDs, optionally filtered. The filter string supports five operators: = (exact), : (contains), ! (not-contains), > (greater than), < (less than). Combine conditions with ; (AND) or | (OR); AND binds tighter than OR.

# Active members
user_status=OK;access_level=member

# Staff or admin
access_level=staff|access_level=admin

See "FILTER DSL" in Concierge::Users::Meta for the full reference.

Returns:

{
    success        => 1,
    user_ids       => \@ids,
    total_count    => $n,
    filter_applied => $filter_string,
}

delete_user

my $result = $users->delete_user($user_id);

Deletes a user record. Fails if the user does not exist.

show_default_config

Concierge::Users::Meta->show_default_config();

Prints the built-in default field configuration template to STDOUT. Can be called as a class or instance method (inherited from Concierge::Users::Meta).

show_config

$users->show_config();
$users->show_config(output_path => '/tmp/my-config.yaml');

Prints the active YAML configuration for this instance to STDOUT. Must be called on an instance (after new). Inherited from Concierge::Users::Meta.

SEE ALSO

Concierge::Users::Meta -- field definitions, validators, and configuration utilities

Concierge::Users::Database, Concierge::Users::File, Concierge::Users::YAML -- storage backend implementations

Concierge::Auth, Concierge::Sessions -- companion Concierge components

AUTHOR

Bruce Van Allen <bva@cruzio.com>

LICENSE

This module is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0.