epolabs/boundly

The Metadata-Driven PHP Framework. Define your Domain. BOUNDLY handles the rest.

Maintainers

Package info

github.com/EpOpenLabs/BOUNDLY

Type:project

pkg:composer/epolabs/boundly

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v0.9.1-alpha 2026-03-26 03:08 UTC

README

πŸͺ„ BOUNDLY

The Metadata-Driven PHP Framework

Build enterprise-grade APIs by defining only your Domain. Everything else is automatic.

Metadata-driven. Convention-over-Configuration. Zero Boilerplate.

License: MIT PHP Version Laravel Version CI PHPStan Tests Packagist

πŸ—ΊοΈ Roadmap & Strategy

Stay updated on our progress toward v1.0.0. We are currently in active alpha development.

πŸ‘‰ View Full Roadmap on Wiki

🧠 What is BOUNDLY?

BOUNDLY is a high-performance PHP framework that uses Metadata-Driven Architecture and Convention-over-Configuration. It eliminates boilerplate code by using PHP 8+ Attributes as the single source of truth for your infrastructure.

You define your Domain (entities, actions, business logic). BOUNDLY handles the Infrastructure (routes, controllers, validation, persistence).

  • βœ… Zero manual migrations β€” Your DB schema evolves with your code.
  • βœ… Zero route files β€” Your endpoints are declared on your Actions.
  • βœ… Zero boilerplate repositories β€” Generic CRUD is handled automatically.
  • βœ… Zero validation rules β€” Payloads are validated against your entity attributes.
  • βœ… Enterprise features in one line β€” Auditing, Soft Delete, Multi-Tenancy, Authorization, Rate Limiting.
  • βœ… Real-Time Agnostic β€” Propagate Domain Events to WebSockets without coupling your logic to a visual driver.
  • βœ… Production-ready β€” Static metadata cache, migration history, OpenAPI docs, and full CI/CD included.

πŸ›οΈ Architecture: Pure DDD

BOUNDLY enforces a clean, screaming architecture where the folder structure tells you what the system does, not what framework it uses.

/
β”œβ”€β”€ Application/          # Use Cases (Actions, DTOs)
β”‚   └── Users/
β”‚       β”œβ”€β”€ Actions/      # #[Action] defines the API endpoint
β”‚       └── DTOs/
β”œβ”€β”€ Domain/               # Pure Business Logic
β”‚   └── Users/
β”‚       β”œβ”€β”€ Entities/     # #[Entity] defines the DB table
β”‚       β”œβ”€β”€ Events/
β”‚       └── ValueObjects/
β”œβ”€β”€ Infrastructure/       # Technical Adapters
β”‚   β”œβ”€β”€ FrameworkCore/    # The BOUNDLY Engine (CLI, Repos, Attributes)
β”‚   └── LaravelEngine/   # Laravel internals (config, storage, routes...)
β”œβ”€β”€ bootstrap/            # Framework ignition point
β”œβ”€β”€ config/               # Your project config (boundly.php)
β”œβ”€β”€ public/               # Web entry point
└── artisan               # CLI entry point

πŸ”₯ Key Features

🧬 1. Magic Evolution (Auto DB Sync)

Forget php artisan migrate. Define your entity, run the daemon, and your database evolves automatically.

#[Entity(table: 'users', resource: 'users')]
#[Auditable]
#[SoftDelete]
class User extends AggregateRoot
{
    #[Id]
    private int $id;

    #[Column(type: 'string', length: 150)]
    private string $name;

    #[Column(type: 'string', nullable: true, default: '555-0000')]
    private string $phone;
}

Run php artisan core:watch and your /api/users endpoint is live. ✨

πŸ” 2. Declarative Authorization

Protect any resource with a single attribute β€” no route middleware, no guards to register manually:

// Only admins and managers can access this resource
#[Entity(table: 'salaries', resource: 'salaries')]
#[Authorize(roles: ['admin', 'manager'])]
class Salary extends AggregateRoot { ... }

// Public reads, auth required for writes
#[Entity(table: 'articles', resource: 'articles')]
#[Authorize(roles: [], methods: ['POST', 'PUT', 'PATCH', 'DELETE'])]
class Article extends AggregateRoot { ... }

πŸ›‘οΈ 3. Declarative Behavioral Traits

Add enterprise features with a single attribute:

Attribute What it does
#[Auditable] Injects created_by / updated_by β€” auto-populated from the request
#[SoftDelete] Handles deleted_at and filters queries silently
#[TenantAware] Multi-tenant data isolation at the repository level
#[Authorize] Role-based access control β€” reads PHP Attributes, not config files
#[Blameable] Extended audit trail tracking created_by/updated_by/deleted_by
#[Timestampable] Auto-manage created_at/updated_at timestamps
#[Sluggable] Auto-generate URL-friendly slugs from another field
#[Policy] Map Laravel Policies for fine-grained authorization

πŸ”’ 4. Security Attributes

Protect sensitive data with declarative security:

Attribute What it does
#[Hidden] Exclude properties from API responses
#[Encrypted] Encrypt at rest with AES-256-CBC
#[Hashed] One-way hashing (bcrypt/Argon2)
#[RateLimit] API rate limiting with per-IP/user tracking

πŸ›‘οΈ 5. Built-in Security

Enterprise-grade security out of the box:

Feature Description
Input Sanitization Whitelist approach - only declared columns are accepted
SQL Injection Prevention Column whitelist validation in DynamicRepository
Rate Limiting Built-in #[RateLimit] attribute
Authorization #[Authorize] attribute with role-based access control

βœ… 6. 40+ Validation Attributes

Comprehensive data validation out of the box:

  • Type: Email, Url, IpAddress, Uuid, Json, IsoDate, Timezone, ColorHex, Slug, MacAddress
  • Numeric: Min, Max, Between, Positive, Negative, Integer, Decimal
  • String: MinLength, MaxLength, LengthBetween, Alpha, Alphanumeric, Numeric, Pattern, StartsWith, EndsWith, Contains
  • Format: Phone, CreditCard, PostalCode, Coordinates
  • Database: Unique, Exists, Enum
  • File: Image, Mimes, FileSize
  • Compound: Required, Confirmed, Password, StrongPassword, SameAs, DifferentFrom

πŸ”— 7. Complete Relations Suite

All relationship types supported:

Relation Attribute
One-to-Many #[BelongsTo] / #[HasMany]
One-to-One #[HasOne]
Many-to-Many #[ManyToMany] (with pivot sync)
Polymorphic #[MorphTo] / #[MorphMany] / #[MorphOne]

πŸ”Ž 8. Pro Query Engine

Complex filtering, nested eager loading, and dual pagination out-of-the-box:

# Partial search
GET /api/users?name_like=boundly

# Range filtering with new operators
GET /api/users?age_gte=18&score_lte=100

# NOT and IN operators
GET /api/products?category_not=5&id_in=1,2,3

# OR filter groups
GET /api/users?or[name_like]=john&or[email_like]=john

# Nested eager loading (dot-notation)
GET /api/users?include=posts.comments.author

# Cursor pagination (efficient for large datasets)
GET /api/events?cursor=250&per_page=20

# Sorting & standard pagination
GET /api/users?sort=name&direction=asc&per_page=20

🌍 9. Full Internationalization (i18n)

Console output speaks your language:

php artisan core:watch --lang=es

πŸ“‘ 10. Agnostic WebSockets Bridge

Broadcast your domain events to the frontend in real-time, completely decoupled from infrastructure (Reverb, Pusher, Soketi) using the purely semantic ShouldBroadcastToExterior contract. Read the Integration Guide

πŸš€ Quick Start

1. Create a new project

composer create-project epolabs/boundly boundly --stability=alpha
cd my-project

Or clone the repository:

git clone https://github.com/EpOpenLabs/BOUNDLY.git my-project
cd my-project
composer install

2. Configure environment

cp .env.example .env
php artisan key:generate

Configure your database in .env:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_DATABASE=my_project
DB_USERNAME=root
DB_PASSWORD=secret

2. Configure your database

# .env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_DATABASE=my_project
DB_USERNAME=root
DB_PASSWORD=secret

3. Define your Entity

// Domain/Users/Entities/User.php
#[Entity(table: 'users', resource: 'users')]
#[Auditable]
class User extends AggregateRoot
{
    #[Id]
    private int $id;

    #[Column(type: 'string', length: 150)]
    private string $name;

    #[Column(type: 'string', unique: true)]
    private string $email;
}

4. Start the daemon

php artisan core:watch

πŸŽ‰ Your API is live at http://localhost:8000/api/users.

5. Before deploying to production

# Preview schema changes
php artisan core:migrate --dry-run

# Apply schema
php artisan core:migrate

# Cache metadata for zero-overhead boot
php artisan core:cache

# Generate OpenAPI documentation
php artisan core:docs

βš™οΈ Configuration Reference

Key Default Env Variable Description
locale en BOUNDLY_LOCALE Default language for CLI output
api_prefix api BOUNDLY_API_PREFIX URL prefix for all auto-generated routes
disable_cache true in local BOUNDLY_DISABLE_CACHE Forces scan mode; set false in production
auth.default_guard sanctum BOUNDLY_AUTH_GUARD Guard used by #[Authorize] middleware
pagination.default_per_page 15 BOUNDLY_PER_PAGE Default page size
pagination.max_per_page 100 BOUNDLY_MAX_PER_PAGE Hard cap on page size
rate_limit.enabled true BOUNDLY_RATE_LIMIT_ENABLED Enable/disable rate limiting
rate_limit.max_attempts 60 BOUNDLY_RATE_LIMIT_MAX_ATTEMPTS Max requests per window
rate_limit.decay_minutes 1 BOUNDLY_RATE_LIMIT_DECAY_MINUTES Time window in minutes
paths.domain Domain/ β€” Where BOUNDLY scans for #[Entity]
paths.application Application/ β€” Where BOUNDLY scans for #[Action]

πŸ› οΈ Requirements

  • PHP 8.2+
  • Laravel 13+ (core dependency, hidden in Infrastructure/LaravelEngine)
  • MySQL / PostgreSQL / SQLite

🀝 Contributing

BOUNDLY is an open source project and contributions are welcome!

Please read CONTRIBUTING.md for details on:

  • How to report bugs
  • How to propose new features
  • The Pull Request process
  • Code style guidelines

πŸ“‹ Versioning

BOUNDLY follows Semantic Versioning (SemVer):

  • MAJOR β†’ Breaking changes in the API or architecture
  • MINOR β†’ New backward-compatible features
  • PATCH β†’ Bug fixes

See the full history in CHANGELOG.md.

πŸ“œ License

BOUNDLY is open-sourced software licensed under the MIT License.

β˜• Support the Project

If BOUNDLY has been useful to you or you like what we're building, you can support us to keep creating and maintaining open source software:

Buy us a coffee

A coffee = more time for open source code ❀️

⭐ If you like BOUNDLY, give it a star on GitHub! ⭐

GitHub Β· Issues Β· Discussions

Made with ❀️ by EpOpenLabs