---
title: Project-Board Overview
type: overview
created: 2026-09-06
updated: 2026-09-06
sources: [codebase snapshot 2026-09-06]
tags: [project-board, laravel, inertia, react, ddd, clean-architecture]
---

# Project-Board Overview

Project-Board is an attempt to build a self-hosted, Jira-like issue tracker on top of Laravel + React + Inertia, using Domain-Driven Design and Clean Architecture layering. The driving motivation was Jira's data-retention deletion policy — the desire to own the data and the application.

> **Note on provenance:** This page reflects the codebase **as of 2026-09-06**. There is no written decision doc (ADR) yet; everything here is derived from reading the source. The repository is at an early stage, and the Jira-ward intent is _scaffolding_ rather than a finished product.

## What the code actually is right now

The `composer.json` package name is `laravel/blank-react-starter-kit` and the README is titled **"Laravel + Inertia DDD Template."** The template originally shipped a demo `Order` checkout vertical slice; that was removed on 2026-09-06 (see [log](log.md)). The Jira-like intent lives in the `Workspace → Board → Ticket` bounded contexts. The `User` context is partially wired (a login command exists but is leaky — see [user](entities/user.md)).

On 2026-09-06 the Plane-style issue-tracking frontend was ported in as real Inertia routes, which **wired the `Ticket` context end-to-end**: `Ticket` became the central issue aggregate (feature/sub-task, status, parent, key, labels), and `Label`/`TimeEntry`/`Activity` contexts were added to support it. There is now a working login → workspace → issues → ticket-detail → time/activity/labels/settings flow backed by the DDD layers.

## Stack

- **Backend:** PHP 8.3, Laravel 13, Sanctum, custom DDD layering in `src/`
- **Frontend:** React 19, Inertia v3, Vite, TypeScript, Tailwind v4, Zustand, Zod, Radix UI, React Compiler
- **Tooling:** Pint (format), PHPStan (type checks), PHPUnit, `vite-plus` (check/fmt), GitHub Actions CI

## High-level architecture

Dependencies point inward, arranged as concentric rings:

- **`src/Domain`** — pure PHP, zero framework dependencies. Entities, value objects, aggregates, domain events, repository _interfaces_.
- **`src/Application`** — use cases (commands/queries) that orchestrate the Domain and talk outward only through Ports.
- **`src/Infrastructure`** — the only layer allowed to touch Eloquent, facades, mail, queues; implements Domain/Application contracts.
- **`app/Http`** — thin controllers/requests/resources; no business logic, no Eloquent.

For the ring rules and dependency table see [ddd-layering](concepts/ddd-layering.md).

## Bounded contexts on disk

| Context     | Aggregate   | Status                                                                   |
| ----------- | ----------- | ------------------------------------------------------------------------ |
| `Board`     | `Board`     | Scaffold (aggregate + repo interface + mapper + model)                   |
| `Ticket`    | `Ticket`    | **Wired** (issue model: type/status/parent/key/labels; use cases + UI)   |
| `Workspace` | `Workspace` | **Wired** (aggregate + repo + web controller + default board)            |
| `Label`     | `Label`     | Wired (aggregate + repo + web controller)                                |
| `TimeEntry` | `TimeEntry` | Wired (aggregate + repo + web controller)                                |
| `Activity`  | `Activity`  | Wired (aggregate + repo + web controller)                                |
| `User`      | `User`      | Partial (aggregate + repo interface + a leaky login command)             |
| `Shared`    | —           | Base primitives: `Entity`, `AggregateRoot`, `DomainEvent`, `ValueObject` |

See [entities/](entities/) for each, and [shared-bases](entities/shared-bases.md) for the primitives.

## Frontend / Inertia wiring

Inertia v3 + React 19, SSR enabled. Page components live in `resources/js/pages/` and are resolved by string from controllers (`Route::inertia(...)`, `Inertia::render(...)`). Shared props come from `HandleInertiaRequests`. The frontend is organized into `app/`, `components/` (atoms→molecules→organisms→templates→ui), `domains/<name>/` (hooks/schemas/stores/types), `lib/`, `types/`. See [inertia-react-integration](concepts/inertia-react-integration.md).

## Notable open questions / flagged inconsistencies

Several areas look inconsistent or incomplete and would benefit from an ADR before the architecture hardens:

1. `UserRepository` lacks the `Interface` suffix and the standard `nextIdentity()`; see [user](entities/user.md).
2. `CreateSession` (Application) imports Eloquent + `Hash` facade and a concrete repository — an Application-layer leak.
3. The migration `2026_09_05_071303_add_tickets_table.php` is misnamed — it creates `workspace`, `board`, and `tickets` tables.
4. User password handling is inconsistent between the domain (raw string) and Eloquent (`hashed` cast).
5. Sub-task statuses exclude `QA` in the UI, but the aggregate allows any of `STATUSES`; validation isn't enforced server-side for sub-tasks.
6. PHPStan level 7 excludes the `src/` DDD layers (only `app/`, `bootstrap/`, `config/`, `database/`, `routes/` are analyzed).

These are surfaced in the relevant entity/concept pages and flagged as candidates for a future decision doc.

## Related pages

- [ddd-layering](concepts/ddd-layering.md) — the ring architecture and dependency rules
- [cqrs](concepts/cqrs.md) — command/query separation
- [domain-events](concepts/domain-events.md) — event recording and dispatch
- [repository-mapper-pattern](concepts/repository-mapper-pattern.md) — repositories + mappers
- [validation-strategy](concepts/validation-strategy.md) — input vs. domain validation
- [inertia-react-integration](concepts/inertia-react-integration.md) — frontend/Inertia wiring
- [identity-value-objects](concepts/identity-value-objects.md) — string UUID ids
- [custom-generators](concepts/custom-generators.md) — the `make:*` source generators