| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Original HTTPS Page] |
Prevent this user from interacting with your repositories and sending you notifications. Learn more about blocking users.
You must be logged in to block users.
Contact GitHub support about this user鈥檚 behavior. Learn more about reporting abuse.
Report abuseSix years of PHP, most of it on the unglamorous half. The queue that has to drain. The webhook that cannot return a 502. The migration that would have taken a table lock at 4pm on a Friday.
I write the boring, load鈥慴earing code, and the static analysis that keeps other people from breaking it.
I shipped this for one client: GrapesJS canvas, a ~900鈥憀ine server renderer, headless鈥慍hrome PDF export, cryptographic sealing, in鈥慴rowser signature capture. It works. Now I am pulling the single鈥憈enant assumptions out of it one at a time, which is turning out to be harder than building it was.
The editor was never the hard part. Tenancy is. Every B2B leak postmortem I have read comes down to the same thing: someone treated isolation as a query filter instead of a boundary the query cannot escape.
flowchart TD
C["Company<br/><i>tenant 路 billing entity</i>"]
T["Team<br/><i>grouping inside a company</i>"]
U["User<br/><i>1 company 路 0..n teams</i>"]
R1["Owner 路 Admin 路 Member"]
R2["team_admin 路 member"]
C -->|"SECURITY BOUNDARY<br/>never removed"| T
T -->|"VISIBILITY FILTER<br/>layered on top"| U
U -.company role.-> R1
U -.team role.-> R2
classDef sec fill:#132E5C,stroke:#1F6FEB,stroke-width:2px,color:#F0F6FC
classDef vis fill:#2A1B4D,stroke:#8957E5,stroke-width:2px,color:#F0F6FC
classDef ent fill:#161B22,stroke:#30363D,color:#C9D1D9
classDef role fill:#0D1117,stroke:#21262D,color:#8B949E
class C sec
class T vis
class U ent
class R1,R2 role
Important
CompanyScope applies no filter at all when no tenant resolves. That sounds like the bug. It is deliberate, so console commands and migrations still work, and it is safe for exactly one reason: users.company_id is NOT NULL. An authenticated user can never resolve to null and see everything. Make that column nullable and the whole design becomes a data leak.
| Invariant | What breaks without it |
|---|---|
| Scope narrows, never swaps | Team visibility built by replacing the company scope instead of layering on it. This is the classic leak. |
| Fails open, deliberately | Console commands and migrations stop working. Safe only while users.company_id stays NOT NULL. |
| Roles are per company | Spatie's team_foreign_key points at company_id. Point it at teams.id and roles leak across tenants. |
| Authorisation self鈥憇copes | User::can() binds to the user's own company. Otherwise every check inside a job or command silently returns false. |
| Two locale axes | users.locale is the sender's UI. proposals.locale is the signed document. A German agency sends an English proposal to a UK buyer. |
This one already bit me twice, in defaultTeam() and again in provisionRoles():
- // Looks harmless. Returns an empty collection when another tenant is current,
- // which produces users with no team and no visibility. No error, no warning.
- $company->teams()->get();
+ // Team carries CompanyScope, so any walk of a company's children has to run
+ // inside that company's context, even when you already hold the model.
+ CompanyContext::for($company->id, fn () => $company->teams()->get());Phase 1 is not done until an isolation suite proves Company A cannot reach Company B's proposals, templates, settings, media, smart content, email templates, users or teams through any route. Nothing downstream starts before that gate passes.
Debt I have written down rather than pretended away: the PDF endpoint regenerates with headless Chrome on every download. Sealed proposals are immutable, so that is pure waste, and it becomes the dominant hosting cost the moment a free tier exists. It gets cached before launch, not after.
Translation policy: formatting works for all 25 locales, but reviewed strings ship for en and de only. A proposal is a quasi鈥憀egal document somebody signs. A mistranslated accept, decline or expiry clause is a dispute, not a typo, so machine translation does not go near the client鈥慺acing axis.
Meta does not care about your queue depth. Return slowly enough, often enough, and it marks the endpoint unhealthy and throttles the campaign. So nothing does real work on the request thread.
sequenceDiagram
autonumber
participant M as Meta Lead Ads
participant W as Webhook endpoint
participant D as MySQL
participant Q as Redis 路 Supervisor
participant A as WhatsApp Cloud API
M->>W: POST lead payload
W->>W: verify X-Hub-Signature-256<br/>via hash_equals()
W->>D: INSERT (unique meta_leadgen_id)
Note over D: replay collides here,<br/>not in application code
W-->>M: 200 in milliseconds
W->>Q: dispatch job
Q->>A: send templated message
A--xQ: 5xx or rate limit
Q->>Q: exponential backoff, time-bounded
Q->>A: retry
A-->>Q: delivered
Two integrity gates, deliberately independent. The signature check rejects forgeries. The unique index on meta_leadgen_id makes a replay a no鈥憃p at the database level. I want the second one in the schema rather than in a service class, because schemas do not get refactored around at 2am.
Backoff is time鈥慴ounded, not attempt鈥慴ounded. A provider outage should degrade throughput and then recover. It should not silently exhaust retries and drop a lead somebody paid for.
Log a decision, revisit it on a schedule, find out whether your instincts actually calibrate. Backed by Google Cloud for Startups and MongoDB for Startups.
Building it alone taught me more about cost than about code. Embeddings are cheap to call and expensive to call badly, and the difference is entirely in what you cache.
Eight packages, 83 stars, all PHP. Each one exists because I hit the problem on a real project, went looking for the fix, and did not find one that worked properly.
|
Stock sync for Laravel across Shopify, WooCommerce, Amazon and Etsy. The easy part is the webhooks. The real part is what happens when two channels sell the last unit inside the same second. Laravel 10-12 聽Webhooks 聽Job queues |
Watches the JSON a third party actually sends you and infers its shape over time. When a field quietly disappears or changes type, you hear about it from this instead of from a customer. PHP 8.3+ 聽Schema drift 聽MIT |
|
Reads your migrations in CI and fails the build on the ones that take a table lock or drop a column with data behind it. Zero config. Rails has strong_migrations; Laravel did not. AST parser 聽CI gate 聽Zero config |
Orphaned listeners, unheard hooks, misspelled action names. Finds all three by reading source, without ever bootstrapping WordPress, so it is fast enough to run on every commit. PHP CLI 聽WordPress 聽Static analysis |
|
Multi鈥慶hannel dispatch for Laravel 12. When a provider starts timing out the breaker trips and reroutes, instead of parking twenty workers on a dead endpoint until the queue backs up. Laravel 12 聽Circuit breaker 聽Telemetry |
73 WCAG 2.1 AA rules for Blade and Livewire, aimed at the European Accessibility Act. Ships a baseline file, because a linter that turns a legacy codebase red on day one just gets switched off. WCAG 2.1 AA 聽Baseline 聽CI |
|
Makes a WordPress site readable by AI agents. Semantic chunking, FAQ extraction, media and author indexing, llms.txt and an MCP manifest, all over REST. MCP 聽WordPress 聽REST |
Gates OTP before the user row is written, so bots never create the account at all. Includes SMS pumping and AIT fraud defence, which is the bill most OTP plugins leave you to find out about. WooCommerce 聽Fraud defence 聽Multisite |
| CORE | |
| DATA | |
| INFRA | |
| FRONT | |
| APIS | |
| TEST |
The install count is the number I actually watch. Stars are a bookmark; an install means somebody put the package in a composer.json and let it run in their build.
PHP 87.1% 聽路聽 Blade 6.6% 聽路聽 JavaScript 3.5% 聽路聽 CSS and HTML 2.8%
Measured across the eight packages, not every repo on the account. Counting everything puts JavaScript on top at 33.6%, which is just my portfolio site's vendored assets talking. The number that means something is the one over code other people run in their own CI.
A test that never disagrees with you is decoration. Write the one that fails when the invariant breaks, not the one that passes today. In a multi鈥憈enant system the tests worth having are the ones that go red the second somebody collapses two axes into one.
Fail loudly at the boundary, gracefully in the middle. Reject a malformed payload at ingestion, where it is cheap and you still have the context. The alternative is a half鈥憌ritten row three services deep that a customer finds for you next week.
Write down the deviation and the reason. Plans are wrong in places. Six months later the useful artefact is not the plan, it is knowing why the code went the other way and what would have to change for the original idea to work.
Comments explain why. Code explains what. If a block needs a comment to say what it does, rewrite the block. Save the comments for the constraints you cannot see from the syntax, like a port collision that presents as an auth error.
Enterprise-grade multi-channel notification engine for Laravel 12 with parallel dispatching, smart routing, and real-time monitoring
Catch dangerous Laravel migrations before they reach production. Static analysis, zero config. The strong_migrations equivalent for Laravel.
PHP 18
Passive API Contract Monitoring for PHP 8.3+. Detects breaking changes, json schema drift, and unexpected structural modifications in third-party REST APIs via probabilistic inference.
PHP 18
The ultimate Laravel package for multi-channel inventory synchronization. Connect Shopify, WooCommerce, Amazon, and Etsy to Laravel with real-time webhooks, job queues, and a unified API.
Static analysis for WordPress hooks. Detect orphaned listeners, unheard hooks, and typos in actions and filters without running WordPress. Faster, safer WP development.
PHP 10
Static accessibility analyzer for Laravel Blade & Livewire - 73 WCAG 2.1 AA rules, CI integration, baseline system, zero runtime dependency.
PHP
| Back | FazBrowse Home | New Git URL |