# NAME

Mojolicious::Plugin::Fondation::User - User management plugin for Fondation

# VERSION

version 0.04

# SYNOPSIS

    # myapp.conf
    {
        'Fondation' => {
            dependencies => [
                { 'Fondation::Model::DBIx::Async' => {
                    backends => [ main => {
                        dsn          => 'dbi:SQLite:dbname=data/app.db',
                        schema_class => 'MySchema',
                    }],
                }},
                'Fondation::User',
            ],
        },
    }

# DESCRIPTION

[Mojolicious::Plugin::Fondation::User](https://metacpan.org/pod/Mojolicious%3A%3APlugin%3A%3AFondation%3A%3AUser) provides the `users` database table
(schema, Result, and ResultSet classes) and a REST controller for CRUD
operations.

Routes are auto-generated by [Fondation::OpenAPI](https://metacpan.org/pod/Fondation%3A%3AOpenAPI). HTML UI is provided by
[Fondation::User::UI::Bootstrap](https://metacpan.org/pod/Fondation%3A%3AUser%3A%3AUI%3A%3ABootstrap).

## Schema

The `users` table has these columns:

    id          INTEGER PRIMARY KEY AUTOINCREMENT
    username    VARCHAR(100) NOT NULL
    email       VARCHAR(255) NOT NULL
    password    VARCHAR(255) NOT NULL  (hashed with Argon2)
    created_at  DATETIME NOT NULL
    updated_at  DATETIME NOT NULL
    active      INTEGER DEFAULT 1

Passwords are automatically hashed with [Crypt::Passphrase](https://metacpan.org/pod/Crypt%3A%3APassphrase) (Argon2) via
`insert()` and `update()` hooks in the Result class. The hashing runs in
the DBIx::Class::Async worker process, keeping the event loop free.

## Controller

REST endpoints (routes generated by OpenAPI):

    GET    /api/user        list all users
    POST   /api/user        create a user
    GET    /api/user/:id    read a user
    PUT    /api/user/:id    update a user
    DELETE /api/user/:id    delete a user

The `password` field is never returned in API responses.

## ResultSet extensions

    $c->model('user')->active;           # users with active = 1
    $c->model('user')->created_today;    # users created today
    $c->model('user')->latest;           # latest 10 users

### with() — many\_to\_many prefetch

    # Include groups in list/read responses (requires Fondation::Group)
    GET /api/User?with=groups

    # Or programmatically:
    $c->model('user')->with('groups')->TO_JSON->then(sub ($data) {
        $self->render(openapi => $data);
    });

`with('groups')` triggers a single-query prefetch via the
`user_group` pivot table.  Each user row includes a `groups`
arrayref with the full group objects — no extra DB round-trips.
The automatic `TO_JSON` serialization (inherited from
[Mojolicious::Plugin::Fondation::Schema::Result::Base](https://metacpan.org/pod/Mojolicious%3A%3APlugin%3A%3AFondation%3A%3ASchema%3A%3AResult%3A%3ABase)) includes
the groups when the data is available.

Without `with()`, m2m relationships are silently excluded.

## Translations

Translations for API notifications are shipped in `share/translations/`.
English and French are included.

# SEE ALSO

- [Mojolicious::Plugin::Fondation::Model::DBIx::Async](https://metacpan.org/pod/Mojolicious%3A%3APlugin%3A%3AFondation%3A%3AModel%3A%3ADBIx%3A%3AAsync) — database backend
- [Mojolicious::Plugin::Fondation::OpenAPI](https://metacpan.org/pod/Mojolicious%3A%3APlugin%3A%3AFondation%3A%3AOpenAPI) — OpenAPI spec and route generation
- [Mojolicious::Plugin::Fondation::User::UI::Bootstrap](https://metacpan.org/pod/Mojolicious%3A%3APlugin%3A%3AFondation%3A%3AUser%3A%3AUI%3A%3ABootstrap) — HTML UI

# AUTHOR

Daniel Brosseau <dab@cpan.org>

# COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Daniel Brosseau.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
