Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ecosystem Laravel Package

atannex/ecosystem

Atannex Ecosystem is a Laravel package that integrates the Atannex platform's services and tooling directly into your application, offering streamlined configuration and a consistent API for building connected Laravel projects.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with composer require atannex/ecosystem. Confirm your app meets the hard floor: PHP 8.3+ and Laravel 11 or 12. On older runtimes the package simply won't install, so check php -v and laravel/framework in composer.json before you start a branch.
  • First stop is the README's setup section. Since this is a v1.0.0 with no prior public API history, treat the README as the source of truth for the trait/attribute/config wiring rather than guessing from older examples you may find in blog posts.
  • Run the package's migrations/config publish step if the README calls for one, and commit the published config so environment differences (driver, table prefix, defaults) are visible in review.
  • Pick a deliberately boring first use case: one model, one text column, no relations. Get a query returning ranked results and correct pagination before layering on relation depth, JSON paths, or global search. Those three features each introduce their own failure modes, and debugging them simultaneously is unpleasant.
  • Decide early where search lives in your codebase. A dedicated SearchService (or a query-object class) that wraps the package keeps the package's query builder out of controllers and makes it swappable if you later move to Scout/Meilisearch.

Implementation Patterns

Progressive scope escalation. Start with a direct model query, then add relation depth and JSON paths only where the UX actually needs them. Depth and JSON traversal are the expensive parts; enabling them speculatively on every search endpoint is the fastest way to a slow app.

Treat the search syntax as a parser boundary. Phrases, exclusions, field filters, and ranges mean your users are submitting a mini-language. Parse and normalise input at the edge (form request validation, or a small tokenizer) rather than passing raw ?q= strings straight into the package. This gives you one place to reject malformed ranges, cap the number of terms, and strip operators you don't want exposed.

Global multi-model search as a separate endpoint. Keep "search everything" distinct from per-model listing. Global search usually wants blended ranking, a result-type discriminator in the payload, and highlighting; scoped searches usually want to sit on top of an existing filtered query (tenant, published status, permissions). Mixing them produces a controller with too many conditionals.

Highlighting is presentation, not query logic. Keep the highlight markup out of cached or persisted search results — store match metadata and render highlights at response time so you can change the tag/wrapper without a cache flush. Also escape user content before injecting highlight tags; a highlighting feature is a classic XSS vector if the wrapper is applied to unescaped fields.

Compose with existing constraints. The realistic pattern is search plus your normal scopes: Post::where('tenant_id', $id)->search(...). Verify the ordering of calls against the README, and add a regression test asserting that a tenant-scoped search never returns another tenant's rows — that's the failure that matters and the one ranking logic can accidentally break.

Pagination and ranking stability. Ranked results plus offset pagination can duplicate or skip rows when the underlying data changes between pages. Add a deterministic tiebreaker (usually primary key) to the ordering, and prefer cursor pagination for infinite-scroll UIs.

Cache at the endpoint, not the model. Search results are user- and query-dependent. Cache keyed on the normalised query plus the scope identifiers (tenant, user role), with a short TTL, and invalidate on writes to the searched models if you need freshness.

Gotchas and Tips

  • "No search server" is a tradeoff, not a free lunch. All matching happens in your database. Deep relation traversal and JSON path predicates translate into JOINs and JSON functions, which are far harder for the planner to optimise than a LIKE on an indexed column. Benchmark on production-shaped data volumes early — a search that's instant on 500 seeded rows can be seconds on 500k.
  • JSON path behaviour is driver-specific. MySQL, PostgreSQL, and SQLite differ in JSON operator support, case sensitivity, and type coercion. If you support more than one driver, test the same search on each; a JSON filter that works locally on SQLite may error or silently mismatch in production MySQL.
  • Case sensitivity and collation will bite you. Result sets differ between utf8mb4_unicode_ci MySQL and PostgreSQL LIKE. Decide explicitly whether search is case-insensitive and write tests that pin the behaviour.
  • Escape operator characters in user input. Terms containing quotes, brackets, colons, or hyphens can be interpreted as phrases, field filters, or ranges. Users searching for C++ or state-of-the-art are the ones who find this.
  • Cap relation depth and term count. Unbounded depth is a denial-of-service surface via a crafted query string. Enforce a server-side maximum and reject requests exceeding it with a 422 rather than letting the query planner decide.
  • Highlighting cost scales with result size and field count. Highlight only the fields you display, and only on the current page. Highlighting inside the database on a large candidate set is a common accidental slowdown.
  • Watch for N+1s after the search returns. Ranked results typically eager-load relations for display; the package won't do that for you. with() the relations your view needs and assert query count in a test.
  • Version pinning matters more than usual at x.0.0. A first stable release can still shift API surface in 1.x patch/minor releases. Pin to ^1.0 and read the changelog on upgrades; avoid dev-main in production.
  • Debugging approach. When a search returns nothing, reduce it in this order: raw column search → add one relation → add JSON path → add syntax operators. Dump the underlying SQL (DB::listen or toSql()) at each step; the generated query tells you immediately whether the problem is parsing, joins, or data.
  • Extension points to look for in the README. Model-level configuration (searchable fields, weights, relation allowlists) and any ranking customisation hooks are where you'll want to invest. Centralising that configuration per model keeps ranking behaviour reviewable instead of scattered across call sites.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource