NAME
Concierge::Setup - One-time desk creation and configuration for Concierge
VERSION
v0.5.6
SYNOPSIS
use Concierge::Setup;
# Simple setup -- database backends, all standard user fields
my $result = Concierge::Setup::build_quick_desk(
'./desk',
['role', 'theme'], # application-specific user fields
);
# Advanced setup -- full control over backends and field configuration
my $result = Concierge::Setup::build_desk({
storage => {
base_dir => './desk',
sessions_dir => './desk/sessions',
users_dir => './desk/users',
},
auth => {
file => './desk/auth.pwd',
},
sessions => {
backend => 'database', # or 'file'
},
users => {
backend => 'database', # 'database', 'yaml', or 'file'
include_standard_fields => [qw/email phone first_name last_name/],
app_fields => ['membership_tier', 'department'],
field_overrides => [{ field_name => 'email', required => 1 }],
},
});
DESCRIPTION
Concierge::Setup provides methods for one-time initialization of a Concierge desk -- the storage directory containing configuration and data files for the identity core components (Auth, Sessions, Users).
Setup is separate from runtime operations. Use this module once to create a desk, then use "open_desk" in Concierge at runtime.
The configuration structure passed to build_desk() is organized by component (auth, sessions, users). Applications that introduce additional components under the Concierge:: namespace can extend this structure with their own configuration blocks, following the same pattern. See "Architecture" in Concierge for details.
The ./desk Convention
If $storage_dir is '.', './', or an empty string, it is automatically converted to './desk' to avoid cluttering the application root directory.
METHODS
build_quick_desk
my $result = Concierge::Setup::build_quick_desk(
$storage_dir,
\@app_fields,
);
Creates a desk with opinionated defaults: SQLite backends for both Sessions and Users, all standard user fields included, all storage co-located in $storage_dir. The password file (auth.pwd) is created automatically inside $storage_dir.
Parameters:
$storage_dir(required) -- directory for all data files; created if it does not exist\@app_fields-- additional user data fields beyond the standard set
Returns { success => 1, desk => $desk_location } on success, or { success => 0, message => '...' } on failure.
build_desk
my $result = Concierge::Setup::build_desk(\%config);
Creates a desk with full control over backend selection, storage layout, and user field configuration.
Configuration structure:
{
storage => {
base_dir => $path, # required
sessions_dir => $path, # default: base_dir
users_dir => $path, # default: base_dir
},
auth => {
file => $path, # default: base_dir/auth.pwd
},
sessions => {
backend => 'database', # 'database' or 'file'
},
users => {
backend => 'database', # 'database', 'yaml', or 'file'
include_standard_fields => 'all', # 'all' or \@field_names
app_fields => \@fields, # custom fields
field_overrides => \@overrides, # modify built-in fields
},
}
The users block is where field configuration happens. The sections below describe the available fields and show how to customize them.
User Field Reference
Every user record draws from four field categories:
Core fields (always present):
user_id system Primary authentication identifier (max 30)
moniker moniker Display name, nickname, or initials (max 24)
user_status enum Eligible*, OK, Inactive (max 20)
access_level enum anon*, visitor, member, staff, admin (max 20)
Standard fields (selectable at setup):
first_name name max 50
middle_name name max 50
last_name name max 50
prefix enum (none) Dr Mr Ms Mrs Mx Prof Hon Sir Madam
suffix enum (none) Jr Sr II III IV V PhD MD DDS Esq
organization text max 100
title text max 100
email email max 255
phone phone max 20
text_ok boolean
last_login_date timestamp
term_ends date
System fields (auto-managed, always present):
last_mod_date system Updated on every write
created_date system Set once on creation
Core and system fields cannot be removed. Standard fields default to required => 0.
Validator Types
Ten built-in validators are available for field definitions and overrides:
text Any string (max_length enforced if set)
email user@domain.tld pattern
phone Digits, spaces, hyphens, parens, optional +; min 7 chars
date YYYY-MM-DD
timestamp YYYY-MM-DD HH:MM:SS (or with T separator)
boolean Strictly 0 or 1
integer Optional minus, digits only
enum Value must appear in the field's options list
moniker 2-24 alphanumeric, no spaces
name Letters (incl. accented), hyphens, apostrophes, spaces
See "VALIDATOR TYPES" in Concierge::Users::Meta for patterns and null values.
Set the environment variable USERS_SKIP_VALIDATION to a true value to bypass all validation -- useful for bulk imports or testing.
Selecting Standard Fields
Include all standard fields:
users => {
backend => 'database',
include_standard_fields => 'all',
},
Or pick only the ones your application needs:
users => {
backend => 'database',
include_standard_fields => [qw/first_name last_name email/],
},
Pass an empty arrayref [] to exclude all standard fields -- useful when your application defines its own fields from scratch. Omitting include_standard_fields (or setting it to any falsy value) includes all 12 standard fields, the same as 'all'.
Adding Application Fields
Custom fields are passed as app_fields, an arrayref of field names (string shorthand) or full definition hashrefs:
users => {
backend => 'database',
app_fields => [
'nickname', # string: text, not required
'bio', # string: text, not required
{ # hashref: full control
field_name => 'department',
type => 'enum',
options => ['*Engineering', 'Sales', 'Support'],
required => 1,
label => 'Department',
description => 'Primary department assignment',
},
{
field_name => 'employee_id',
type => 'text',
validate_as => 'moniker', # text storage, moniker validation
required => 1,
must_validate => 1,
max_length => 12,
},
],
},
String shorthand creates a field with type => 'text', required => 0.
Enum default convention: In an options arrayref, prefix exactly one value with * to mark it as the default for new records. ['*Community', 'Maker', 'Pro'] means new records get Community unless another value is supplied. A bare * (as used by the built-in prefix and suffix fields) designates an empty-string default. The * is stripped internally before validation -- stored values never contain it. If no * option exists and no explicit default is set, the default is "".
Available attributes for field definition hashrefs:
field_name-- internal name (snake_case); requiredtype--text,email,phone,date,timestamp,boolean,integer,enumvalidate_as-- validator to use when different fromtype(e.g.,validate_as => 'moniker'on atextfield applies alphanumeric-only validation while storing as text)label-- human-readable display label; auto-generated fromfield_nameif omitted (e.g.,badge_namebecomes "Badge Name")description-- short explanatory text for documentation or UI hintsrequired--1if the field must have a non-null value on creation;0otherwisemust_validate--1to reject the entire operation on validation failure;0to silently drop the invalid value and append a warning (auto-enabled whenrequired => 1)options-- arrayref of allowed values forenumfields; prefix one with*to designate the default (e.g.,['*Free', 'Premium', 'Enterprise']); a bare*means an empty-string defaultdefault-- value assigned on new-record creation when no value is supplied; for enum fields, auto-set from the*-marked option if not specified explicitlynull_value-- sentinel representing "no data" for the field type (e.g.,""for text,0for boolean,"0000-00-00"for date); values equal tonull_valueare treated as emptymax_length-- maximum character length; enforced by thetextvalidator and available as a UI hint
See "FIELD ATTRIBUTES" in Concierge::Users::Meta for the complete attribute reference.
Modifying Standard Fields
Use field_overrides to change attributes of built-in fields without replacing them:
users => {
backend => 'database',
include_standard_fields => [qw/email phone organization/],
field_overrides => [
{
field_name => 'email',
required => 1, # make email mandatory
label => 'Work Email',
},
{
field_name => 'organization',
required => 1,
max_length => 200, # increase from default 100
},
],
},
Overriding enum options: Core fields like user_status and access_level are always present, but their options are not fixed. Replace them with values that fit your domain:
# Makerspace member status instead of the default
# Eligible / OK / Inactive
field_overrides => [
{
field_name => 'user_status',
options => [qw( *Applicant Novice Skilled Expert Mentor Steward )],
},
],
Protected fields (cannot be overridden): user_id, created_date, last_mod_date.
Protected attributes (cannot be changed): field_name, category.
Auto-behaviors: changing type auto-updates validate_as to match; setting required => 1 auto-enables must_validate.
See "FIELD CUSTOMIZATION" in Concierge::Users::Meta for the complete customization reference and "FIELD CATALOG" in Concierge::Users::Meta for full field specifications.
Complete Example
A community makerspace tracking members with custom fields, selective standard fields, and modified built-in defaults:
my $result = Concierge::Setup::build_desk({
storage => {
base_dir => './makerspace-desk',
},
sessions => { backend => 'database' },
users => {
backend => 'database',
include_standard_fields => [qw/
first_name last_name email phone organization
/],
field_overrides => [
{
field_name => 'user_status',
options => [qw( *Applicant Novice Skilled Expert Mentor Steward )],
},
{
field_name => 'email',
required => 1, # mandatory for members
label => 'Contact Email',
},
{
field_name => 'organization',
max_length => 200, # increase from default 100
},
],
app_fields => [
'skills', # string shorthand: text, optional
{
field_name => 'membership_tier',
type => 'enum',
options => ['*Community', 'Maker', 'Pro', 'Sponsor'],
required => 1,
label => 'Membership Tier',
description => 'Determines access to equipment and hours',
},
{
field_name => 'badge_name',
type => 'text',
validate_as => 'moniker', # alphanumeric validation
required => 1,
must_validate => 1,
max_length => 16,
label => 'Badge Name',
description => 'Printed on member access badge',
},
{
field_name => 'newsletter_ok',
type => 'boolean',
default => 0,
label => 'Newsletter Opt-in',
},
],
},
});
This produces a user schema with 4 core fields, 5 selected standard fields (email now required), 4 application fields, and 2 system timestamps -- 15 fields total. The core user_status field keeps its usual role but uses makerspace-specific statuses (defaulting to Applicant). New members default to the Community tier (marked with *) and must provide a badge_name that passes moniker validation (2-24 alphanumeric characters).
Configuration Introspection
After building a desk, the field schema can be inspected at runtime through Concierge::Users (inherited from Concierge::Users::Meta):
# Before setup: view built-in default field definitions
Concierge::Users::Meta->show_default_config();
# After setup: view the active schema for this desk
my $users = Concierge::Users->new('./makerspace-desk/users-config.json');
$users->show_config();
# Get UI-friendly hints for building forms dynamically
my $hints = $users->get_field_hints('membership_tier');
# Returns: { label, type, options, max_length, description, required }
# Get the ordered field list for this schema
my $fields = $users->get_user_fields();
show_default_config() prints the built-in field template to STDOUT -- useful for reviewing available standard fields before writing a setup script. show_config() prints the YAML configuration generated during setup(), reflecting the actual schema including any overrides and application fields. get_field_hints() returns a hashref of display-ready attributes for a single field, suitable for generating form elements programmatically.
Data Archiving
Calling Concierge::Users->setup() when data already exists in the storage directory automatically archives the existing data files (renamed with a timestamp suffix) before creating new storage. This means re-running a setup script to change the field schema will not silently destroy existing user records.
Returns:
{ success => 1, desk => $base_dir, config => \%full_config }
On failure:
{ success => 0, message => '...' }
validate_setup_config
my $result = Concierge::Setup::validate_setup_config(\%config);
Validates a configuration hashref without creating anything. Returns { success => 1 } or { success => 0, errors => [...] }.
SEE ALSO
Concierge -- runtime operations after desk is built
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.