---
title: User Bounded Context
type: entity
created: 2026-09-06
updated: 2026-09-06
sources: [codebase snapshot 2026-09-06]
tags: [user, context, auth]
---

# User Bounded Context

`User` models a human account and is referenced by `Workspace` (owner) and `Ticket` (assignee). It is the **only context with an Application command**, but that command **leaks into Infrastructure**, and the context has notable inconsistencies.

> **Note on provenance:** reflects the code as of 2026-09-06; no written ADR exists.

## Domain

- **Aggregate:** `Domain\User\Entities\User` (`src/Domain/User/Entities/User.php`)
    - Reconstitute-only (`reconstitute(UserId, name, email, role, password)`).
    - Getters: `id()`, `full_name()`, `email()`, `role()`, `password()`.
- **Value object:** `UserId` (string id).
- **Exception:** `InvalidUserException extends \Exception`.
- **Repository interface:** `Domain\User\Repositories\UserRepository` — `getUserByEmail()`, `getUserById()`, `userExists()`, `save()`.

## Application

- **Command:** `CreateSession` (`src/Application/Commands/User/CreateSessionCommand/CreateSession.php`) — looks up a user by email, `Hash::check`s the password, issues a Sanctum token, returns a raw array (`user`, `token`, `message`, `result`).

## Infrastructure

- `UserModel` (table `users`, string PK `user_id`, casts `password` hashed, hides `created_at`/`updated_at`).
- `UserMapper`, `EloquentUserRepository`.
- **Separate auth model:** `App\Models\User` (`app/Models/User.php`) — extends `Authenticatable`, uses `HasApiTokens` (Sanctum), same `user_id` PK. This is a **second, Laravel-native `User`** distinct from the domain aggregate.

## Presentation / wiring

- **API:** `Api\V1\Auth\CreateSessionController` → `CreateSessionRequest` → `AuthResource`.
- **Route:** `POST /api/v1/auth/login` (name `auth.session.create`) — the **only** API route registered (the template's `/api/v1/orders` routes were removed).
- **Web:** no web user controller; the frontend `users` page is disconnected from this context.

## Flagged issues

1. **Application-layer leak.** `CreateSession` imports `App\Models\User`, `Illuminate\Support\Facades\Hash`, and the concrete `EloquentUserRepository`, and returns a raw array. This violates the "Application depends only on Domain" rule (see [ddd-layering](../concepts/ddd-layering.md)).
2. **Naming inconsistency.** The interface is `UserRepository` (no `Interface` suffix, unlike every other context). It also lacks `nextIdentity()` and its `save()` has no return type.
3. **Unused DTO.** `Application\DTOs\Auth\SessionDto` exists but is not used; the command returns a raw array that the controller wraps in `AuthResource`.
4. **Password handling mismatch.** The domain `User` carries the raw password string; `UserMapper` writes it; both `UserModel` and `App\Models\User` apply a `hashed` cast. How the domain's plaintext password reconciles with the Eloquent hashed cast is unresolved.
5. **Type mismatch.** The frontend `User` types (`types/auth.ts`, `domains/users/types`) use `id: number`; the domain uses a string `user_id`. The `/users` route injects hardcoded numeric users, disconnected from this context.
6. **Sanctum token guard** is configured but `auth:sanctum` is not applied to the API routes yet (see `bootstrap/app.php`).

## Related pages

- [workspace](workspace.md) — references `User` as owner
- [ticket](ticket.md) — references `User` as assignee
- [validation-strategy](../concepts/validation-strategy.md) — login validation
- [identity-value-objects](../concepts/identity-value-objects.md) — `UserId`
- [overview](../overview.md) — project context