# Concierge::Sessions - Session Management System

**Version:** 0.8.1

Concierge::Sessions is a comprehensive session management system for Perl applications,
providing flexible storage backends, sliding window expiration, and application-controlled data storage.

Sessions enable applications to track user actions and maintain state across multiple operations.
Keep session data in memory for fast access, persist to storage when needed, and maintain continuity
between user interactions whether in online services, CLI tools, games, time-billing systems, or any
application that needs to track state over time.

## Features

- **Application-controlled data storage**: Store any serializable data structure in sessions
- **In-memory performance**: Fast access to state and configuration
- **Optional persistence**: Session tracks changes, saves when App tells it to
- **Single-session enforcement**: Enforces one active session per user
- **Sliding window expiration**: Sessions auto-extend when users are active
- **Indefinite sessions**: Application-wide sessions that never expire
- **Multiple backends**: database (production), file (testing/small user population)
- **Modern Perl**: v5.36+ with contemporary best practices
- **Service layer pattern**: Non-fatal errors with descriptive messages

## Installation

Standard CPAN installation:

```bash
cpanm Concierge::Sessions
# OR
perl Makefile.PL
make
make test
make install
```

## Requirements

- Perl 5.36 or later
- DBI (for SQLite backend)
- DBD::SQLite (for SQLite backend)
- JSON::PP or JSON
- Time::HiRes
- File::Spec
- Test2::V0 (for testing)

## Quick Start

```perl
use Concierge::Sessions;

# Create session manager
my $sessions = Concierge::Sessions->new(
    backend => 'database',
    storage_dir => '/var/app/sessions',
);

# Create user session
my $result = $sessions->new_session(
    user_id => 'user123',
    data => {
        cart => [],
        preferences => { theme => 'dark' },
    },
);

if ($result->{success}) {
    my $session = $result->{session};
    my $session_id = $session->session_id();

    # Read session data
    my $data_result = $session->get_data();
    my $data = $data_result->{value};

    # Update session data
    $data->{cart} = ['item1', 'item2'];
    $session->set_data($data);

    # Save changes (extends session timeout)
    $session->save();
}

# Retrieve session later
my $retrieved = $sessions->get_session($session_id);
```

## Usage Patterns

### Sliding Window Expiration

Sessions automatically extend when `save()` is called:

```perl
my $session = $sessions->new_session(
    user_id => 'user123',
    session_timeout => 3600,  # 1 hour
)->{session};

# User activity - save() extends the session
$session->save();  # Session now expires 1 hour from now
```

Active users stay logged in; inactive users expire automatically.

### Indefinite Sessions

For application-wide state that never expires:

```perl
my $app_session = $sessions->new_session(
    user_id         => 'application_main',
    session_timeout => 'indefinite',
    data            => {
        metrics    => { requests_processed => 0 },
        subsystems => { database => 'connected' },
    },
)->{session};

# This session never expires
$app_session->is_expired();  # Always returns false
```

### Data Access

All data operations work with the entire data field:

```perl
# Get entire data structure
my $result = $session->get_data();
my $data = $result->{value};

# Modify the data structure
$data->{username} = 'alice';
$data->{preferences}{language} = 'en';
$data->{cart} = [@items];

# Replace entire data field (marks session as dirty)
$session->set_data($data);

# Persist to backend (also extends session timeout)
$session->save();
```

### Session Lifecycle

```perl
# Create
my $result = $sessions->new_session(user_id => 'user123');
my $session = $result->{session};

# Check session status
if ($session->is_valid()) {
    # Session is active and not expired
}

# Retrieve later
my $retrieved = $sessions->get_session($session->session_id());

# Delete when done
$sessions->delete_session($session->session_id());
```

### Backend Selection

```perl
# Database backend (production, high performance)
my $sessions = Concierge::Sessions->new(
    backend     => 'database',
    storage_dir => '/var/app/sessions',
);

# File backend (testing, human-readable)
my $sessions = Concierge::Sessions->new(
    backend     => 'file',
    storage_dir => '/tmp/sessions',
);
```

## API Overview

### Concierge::Sessions (Factory)

All factory methods return hashrefs with `{success => 1|0, ...}`:

```perl
$sessions->new_session(user_id => ..., data => ...)
# Returns: {success => 1, session => $session_object}

$sessions->get_session($session_id)
# Returns: {success => 1, session => $session_object}

$sessions->delete_session($session_id)
# Returns: {success => 1, message => '...'}

$sessions->delete_user_session($user_id)
# Returns: {success => 1, deleted_count => 3}

$sessions->cleanup_sessions()
# Returns: {success => 1, deleted_count => 5}
```

### Concierge::Sessions::Session (Session Object)

```perl
# Data methods
$session->get_data()           # {success => 1, value => $data}
$session->set_data($data)      # {success => 1}
$session->save()               # {success => 1}

# Status checks
$session->is_valid()           # 1 if active and not expired
$session->is_active()          # 1 if state is 'active'
$session->is_expired()         # 1 if past expiration time
$session->is_dirty()           # 1 if unsaved changes exist

# Accessors
$session->session_id()         # Session ID string
$session->created_at()         # Creation timestamp
$session->expires_at()         # Expiration timestamp
$session->last_updated()       # Last update timestamp
$session->storage_backend()    # Backend class name
$session->status()             # {state => 'active', dirty => 0}
```

## Design Principles

### Explicit Persistence

No automatic saving on scope exit. You control when data is persisted:

```perl
$session->set_data($new_data);  # Changes in memory only
$session->is_dirty();            # True - changes not saved
$session->save();                # Persists to backend
$session->is_dirty();            # False - saved
```

### Single-Session Enforcement

Only one active session per user. Creating a new session invalidates old ones:

```perl
my $session1 = $sessions->new_session(user_id => 'user123')->{session};
my $session2 = $sessions->new_session(user_id => 'user123')->{session};

# $session1 is now deleted (enforced by backend)
```

### Service Layer Pattern

All methods return consistent result hashrefs. The module only dies/croaks during
initialization if the backend cannot be initialized. All other failures are non-fatal:

```perl
# Factory methods return hashrefs
my $result = $sessions->new_session(user_id => 'user123');

if ($result->{success}) {
    my $session = $result->{session};
    # Use session
} else {
    warn "Failed to create session: " . $result->{message};
}

# Session object methods also return hashrefs
my $save_result = $session->save();

if ($save_result->{success}) {
    # Session saved successfully
} else {
    warn "Failed to save session: " . $save_result->{message};
}
```

**Default Session Timeout**: If not specified, sessions timeout after 3600 seconds (1 hour).
Use `session_timeout => 'indefinite'` for sessions that never expire.

## Documentation

Full API documentation is available in the module POD:

```bash
perldoc Concierge::Sessions
perldoc Concierge::Sessions::Session
```

## Testing

```bash
# Run all tests
prove -lv t/

# Run specific test file
prove -lv t/01-sessions-manager.t
```

Test coverage: 75 tests across 4 test files, all passing.

## Examples

See the `examples/` directory for usage examples:

- `04-indefinite-session.pl` - Application-wide session demonstration

## Performance

- **SQLite backend**: 4,000-5,000 operations per second
- **File backend**: ~1,000 operations per second

Benchmarks performed on typical hardware with default settings.

## License

Artistic License 2.0 - See [LICENSE](LICENSE) file for details.

This is the same license as Perl itself.

## Author

Bruce Van Allen <bva@cruzio.com>

## See Also

- [DBI](https://metacpan.org/pod/DBI) - Database interface
- [JSON::PP](https://metacpan.org/pod/JSON::PP) - JSON handling
- [Time::HiRes](https://metacpan.org/pod/Time::HiRes) - High resolution time

## Version History

### Version 0.8.1 (Current)

- Backend parameter names: 'database' and 'file' (case-insensitive)
- Method name updates: delete_user_session, cleanup_sessions
- Version alignment across all modules

### Version 0.7.0

- Initial release as Concierge::Sessions
- Sliding window session expiration
- Indefinite session support
- Multiple backend support (database, file)
- 75 tests, all passing
- Production-ready
