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
Agents
jeffersongoncalves/laravel-short-url
claude-code
cursor
url-shortening
redirect-pipeline
analytics
multi-tenancy
contracts
feature-flags
testing

Instructions for AI coding agents working in this repository.

Install
php artisan boost:add-skill jeffersongoncalves/laravel-short-url

Save this content to: AGENTS.md

# AGENTS.md

Instructions for AI coding agents working in this repository.

## Project

`jeffersongoncalves/laravel-short-url` — a headless URL-shortening engine for Laravel (redirect pipeline, analytics, targeting rules, custom domains, conversion tracking, multi-tenancy). No Filament dependency; consumed via its `ShortUrl` facade, contracts, or console commands. See [README.md](README.md) for the full feature list and [resources/boost/skills/short-url-development/SKILL.md](resources/boost/skills/short-url-development/SKILL.md) for a deeper development reference.

## Setup

```bash
composer install
```

## Commands

```bash
composer test           # Pest test suite
composer test-coverage  # Pest with coverage
composer analyse        # PHPStan (Larastan) level 6
composer format          # Pint (Laravel preset)
```

Run all three (`test`, `analyse`, `format`) before considering a change done — CI enforces all three on every push.

## Conventions

- **Namespace**: everything under `JeffersonGoncalves\LaravelShortUrl\`; tests under `JeffersonGoncalves\LaravelShortUrl\Tests\`.
- **Contracts first**: swappable behavior (analytics driver, DNS verifier, VPN detector, conversion dispatcher, ...) is an interface under `src/Contracts/`, bound in `LaravelShortUrlServiceProvider`. Add a new provider by implementing the contract and registering it there — don't special-case call sites.
- **`custom_domain_id` is `NOT NULL`**, sentinel `0` means "no custom domain" — never pass `null` directly into a raw query; the manager/builder coerce it. This exists because `NULL != NULL` in a composite unique index would silently break `unique(custom_domain_id, url_key)`.
- **Never bypass the redirect pipeline.** `GET /{urlKey}` already routes through caching, security checks, and tracking — don't write a competing redirect controller.
- **Tracking is async and must stay non-blocking.** A failure in GeoIP, Safe Browsing, VPN detection, or an analytics driver must never break a redirect or a test relying on one.
- **Multi-tenancy is a pure feature flag** (`short-url.tenancy.enabled`) — a complete no-op when off. Don't add tenancy-aware code paths that behave differently when the flag is off; gate on the flag explicitly.
- **PHP 8.3+, Laravel 12 or 13.** Don't add code that only works on one of the two supported majors without a compatibility check.

## Testing notes

- Pest 4 on Orchestra Testbench, SQLite in-memory by default. `tests/TestCase.php` reads `SHORT_URL_TEST_DB_*` env vars (not `DB_*`, which Testbench itself sets by convention) to point at MySQL/Postgres in CI.
- Migration order matters: `tests/TestCase.php::defineDatabaseMigrations()` copies stubs using the order in `LaravelShortUrlServiceProvider::MIGRATIONS`, not alphabetically — a foreign-key-dependent table must stay listed after what it depends on in that array.
- **On Postgres**, wrap any assertion expecting a `QueryException` (e.g. a uniqueness constraint) in `DB::transaction()`. Postgres aborts the whole enclosing transaction on any uncaught error until a rollback — that poisons `RefreshDatabase`'s per-test transaction for whatever query runs next, unlike MySQL/SQLite.
- Never edit `CHANGELOG.md` by hand except to fix a broken auto-generated entry — `.github/workflows/update-changelog.yml` populates it from GitHub Releases, and it only fires once per release.

## Commit style

Conventional commits (`feat:`, `fix:`, `docs:`, `chore:`, `refactor:`, `test:`, `ci:`), English, explaining *why* over *what*. Primary branch is `main`.

AGENTS.md

Instructions for AI coding agents working in this repository.

Project

jeffersongoncalves/laravel-short-url — a headless URL-shortening engine for Laravel (redirect pipeline, analytics, targeting rules, custom domains, conversion tracking, multi-tenancy). No Filament dependency; consumed via its ShortUrl facade, contracts, or console commands. See README.md for the full feature list and resources/boost/skills/short-url-development/SKILL.md for a deeper development reference.

Setup

composer install

Commands

composer test           # Pest test suite
composer test-coverage  # Pest with coverage
composer analyse        # PHPStan (Larastan) level 6
composer format          # Pint (Laravel preset)

Run all three (test, analyse, format) before considering a change done — CI enforces all three on every push.

Conventions

  • Namespace: everything under JeffersonGoncalves\LaravelShortUrl\; tests under JeffersonGoncalves\LaravelShortUrl\Tests\.
  • Contracts first: swappable behavior (analytics driver, DNS verifier, VPN detector, conversion dispatcher, ...) is an interface under src/Contracts/, bound in LaravelShortUrlServiceProvider. Add a new provider by implementing the contract and registering it there — don't special-case call sites.
  • custom_domain_id is NOT NULL, sentinel 0 means "no custom domain" — never pass null directly into a raw query; the manager/builder coerce it. This exists because NULL != NULL in a composite unique index would silently break unique(custom_domain_id, url_key).
  • Never bypass the redirect pipeline. GET /{urlKey} already routes through caching, security checks, and tracking — don't write a competing redirect controller.
  • Tracking is async and must stay non-blocking. A failure in GeoIP, Safe Browsing, VPN detection, or an analytics driver must never break a redirect or a test relying on one.
  • Multi-tenancy is a pure feature flag (short-url.tenancy.enabled) — a complete no-op when off. Don't add tenancy-aware code paths that behave differently when the flag is off; gate on the flag explicitly.
  • PHP 8.3+, Laravel 12 or 13. Don't add code that only works on one of the two supported majors without a compatibility check.

Testing notes

  • Pest 4 on Orchestra Testbench, SQLite in-memory by default. tests/TestCase.php reads SHORT_URL_TEST_DB_* env vars (not DB_*, which Testbench itself sets by convention) to point at MySQL/Postgres in CI.
  • Migration order matters: tests/TestCase.php::defineDatabaseMigrations() copies stubs using the order in LaravelShortUrlServiceProvider::MIGRATIONS, not alphabetically — a foreign-key-dependent table must stay listed after what it depends on in that array.
  • On Postgres, wrap any assertion expecting a QueryException (e.g. a uniqueness constraint) in DB::transaction(). Postgres aborts the whole enclosing transaction on any uncaught error until a rollback — that poisons RefreshDatabase's per-test transaction for whatever query runs next, unlike MySQL/SQLite.
  • Never edit CHANGELOG.md by hand except to fix a broken auto-generated entry — .github/workflows/update-changelog.yml populates it from GitHub Releases, and it only fires once per release.

Commit style

Conventional commits (feat:, fix:, docs:, chore:, refactor:, test:, ci:), English, explaining why over what. Primary branch is main.

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.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log