-
Notifications
You must be signed in to change notification settings - Fork 0
Behavioral Traits
lpachecob edited this page Mar 23, 2026
·
6 revisions
In BOUNDLY, you add enterprise features with a single class attribute. These traits automate horizontal concerns like auditing, deletion, segmentation, and authorization.
Automates traceability for creation and modifications.
| Column Added | Source |
|---|---|
created_by |
X-User-ID request header (or 'System') |
updated_by |
X-User-ID request header (or 'System') |
-
The DB:
core:migrateaddscreated_byandupdated_byasVARCHARcolumns. -
The Logic: On every
insert()orupdate(), BOUNDLY auto-populates these from theX-User-IDrequest header.
#[Entity(table: 'products', resource: 'products')]
#[Auditable]
class Product extends AggregateRoot { ... }Enables logical deletion — the row is never physically removed.
| Column Added | Behavior |
|---|---|
deleted_at |
Set to now() on DELETE. NULL means active. |
-
The DB:
core:migrateaddsdeleted_atas aTIMESTAMP. -
The Queries: All
GETrequests automatically filterWHERE deleted_at IS NULL. -
The Action:
DELETEsets the timestamp instead of executing aDELETESQL command.
#[Entity(table: 'orders', resource: 'orders')]
#[SoftDelete]
class Order extends AggregateRoot { ... }Isolates data by Tenant ID. Essential for SaaS applications.
| Parameter | Default | Description |
|---|---|---|
tenantColumn |
'tenant_id' |
The DB column holding the tenant identifier. |
-
The DB:
core:migrateadds the tenant column. -
The Queries: Every
SELECT,INSERT,UPDATE, andDELETEscopes automatically toWHERE tenant_id = <X-Tenant-ID header>. -
Zero configuration: Pass the
X-Tenant-IDheader in every API request.
#[Entity(table: 'inventories', resource: 'inventories')]
#[TenantAware(tenantColumn: 'tenant_id')]
class Inventory extends AggregateRoot { ... }Protects an entity's API routes with authentication and role-based access control (RBAC). The programmer never touches route files or middleware registration.
| Parameter | Default | Description |
|---|---|---|
roles |
[] |
Array of required role names. Empty = any authenticated user. |
methods |
[] |
HTTP methods this rule applies to. Empty = all methods. |
guard |
'sanctum' |
Laravel auth guard to use. |
- The
ResourceAuthorizemiddleware reads the#[Authorize]attribute automatically before every request. - If
rolesis empty: any authenticated user is allowed. - If
rolesis set: compatible with Spatie Laravel Permission (hasAnyRole) and a simplerolecolumn. - The
methodsparameter allows fine-grained control (e.g., allow public reads but require auth for writes).
// Any authenticated user can access this resource
#[Entity(table: 'reports', resource: 'reports')]
#[Authorize]
class Report extends AggregateRoot { ... }
// Only admins can access this resource
#[Entity(table: 'salaries', resource: 'salaries')]
#[Authorize(roles: ['admin'])]
class Salary extends AggregateRoot { ... }
// Public reads, authenticated writes
#[Entity(table: 'articles', resource: 'articles')]
#[Authorize(roles: [], methods: ['POST', 'PUT', 'PATCH', 'DELETE'])]
class Article extends AggregateRoot { ... }💡
#[Authorize]is repeatable — you can stack multiple rules on the same class.
Combine all traits for a truly enterprise-level entity:
#[Entity(table: 'clients', resource: 'clients')]
#[Auditable]
#[SoftDelete]
#[TenantAware]
#[Authorize(roles: ['admin', 'manager'])]
class Client extends AggregateRoot { ... }With this single declaration, the clients resource:
- ✅ Auto-creates and evolves its table
- ✅ Tracks who created and modified each record
- ✅ Uses logical deletion
- ✅ Is isolated per tenant
- ✅ Is only accessible to
adminandmanagerroles
Next Step: Query-Engine 🔎