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

Laravel User Team Sync Laravel Package

madbox-99/laravel-user-team-sync

Laravel package for syncing users and teams. It offers straightforward helpers for managing team membership and user assignments, keeping relationships consistent across your Eloquent models and existing Laravel application.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit The package description undersells what this actually is. "Synchronization between a subscriber hub and secondary Laravel apps" reads like a config-and-traits helper; the documented internals describe a distributed Publisher/Receiver system: outbound HTTP calls dispatched through queue jobs, inbound API endpoints guarded by bearer tokens, model observers that fire automatically on user changes, and a container-flag guard to prevent sync loops. That is a materially different adoption decision than adding a pivot manager.

The architecture is a good fit only if our topology is genuinely hub-and-spoke with one authoritative identity store and N downstream apps that can tolerate eventual consistency. It is a poor fit for a single app, for a shared-database multi-app setup, or for any peer-to-peer model where multiple apps can authoritatively change a user. The mode config (publisher / receiver / both) is the first thing a TPM must resolve, because both makes every app a potential source of truth and immediately raises conflict-resolution questions the package does not appear to answer.

Note that the UserSyncObserver watches only config('user-team-sync.publisher.sync_fields') — default email and role. Everything else silently diverges. That is a deliberate, defensible design, but it means the product definition of "what is a user" is now split across a config array, and product owners will assume more is synced than actually is.

Integration feasibility Mechanically the install is easy (composer require, user-team-sync:install, publish config). The feasibility question is not install cost — it is surface area:

  • Every receiver needs an inbound, internet-reachable (or at least publisher-reachable) API surface: seven endpoints, a bearer-token middleware, and an app-key store.
  • Every receiver's users table needs to accept a password_hash copied verbatim from the publisher. That is a schema change on every app in the fleet, not just the one we're integrating.
  • Receivers need the package installed even if they never publish, which means the dependency and its upgrade cadence spread to every app.

Technical risk Ranked by severity:

  1. Credential blast radius. Passwords are hashed publisher-side and the same hash is replicated to every receiver. Compromising any one receiver exposes a hash that is valid against the hub. Hashing is correct practice, but this concentrates risk in the lowest-security app in the fleet. We need a hard answer on hasher parity (driver + cost) across apps and a decision on whether receiving apps should be able to authenticate against that hash at all.
  2. Referential identity is undefined in the docs. create-team on a receiver "creates a team." If receiver-side team IDs are locally generated, the same logical team has different IDs per app, which breaks cross-app URLs, deep links, and any downstream reporting. If IDs are preserved from the publisher, we inherit collision risk with pre-existing receiver rows. This is the single highest-impact unknown and must be resolved before any schema work.
  3. Idempotency and duplicate delivery. Jobs carry retry/backoff (initRetryConfig), but no endpoint is documented as accepting an idempotency key or performing an upsert. A retried CreateUserJob against a receiver that already has the row is either an error the queue retries forever or a silent duplicate. Unverified.
  4. Loop suppression is request-scoped. The guard is an app() binding set in middleware with try/finally. It works for HTTP. It is not obviously safe for console commands, queue workers, or seeders that mutate users — and a job dispatched synchronously inside an inbound request would inherit the flag and skip outbound work silently. Needs a test, not a reading.
  5. No deletion propagation. The endpoint set covers create, update, active-toggle, and team detach — but not user deletion. GDPR/offboarding erasure across N apps remains entirely ours.
  6. Information risk. v1.7.0's notes are a compare link and nothing else. We cannot confirm new migrations, renamed config keys, or trait signature changes. The release metadata should also be sanity-checked before it is trusted in a dependency policy.

Organizational risk: 0 stars, 0 dependents, one maintainer, no disclosed security process — for a component that terminates authenticated write traffic and stores API keys.

Key questions

  1. What is the team/user ID strategy on the receiver — preserved from publisher, or locally generated with a mapping table?
  2. Are the receiver endpoints idempotent? What happens on duplicate create-user / create-team?
  3. Does the loop-prevention flag hold for queued, console, and synchronous-dispatch paths?
  4. What exactly changed in v1.6.0...v1.7.0, and does it add migrations or config keys?
  5. Are publisher and receiver required to run the same package version? Is there a version handshake?
  6. Where is SyncLog written (publisher, receiver, or both), is it pruned, and does it contain PII?
  7. Is api_key rotation supported without downtime, and how are keys distributed to N receivers?
  8. Is there any reconciliation or full-resync command, or only event-driven deltas?
  9. Laravel/PHP version floor and illuminate/* constraints — does it match our fleet's oldest app?
  10. What is the maintainer's response time on security issues, and is there a disclosure channel?

Integration Approach

Stack fit PHP 8.3+ (per the package's own code style), Composer 2, a durable queue backend on the publisher (Redis/SQS/database — not sync), HTTPS between hub and every receiver, and a real secret store for the per-app bearer tokens. The SyncApp model stores api_key encrypted, which implies APP_KEY discipline across the fleet — if receiver and publisher APP_KEYs differ in a shared table scenario, decrypt fails. Prefer app_source = config for the first pilot and database only once key management is settled.

Confirm the illuminate/* constraint against the oldest app in the fleet, not the newest. That constraint, not our PHP version, will decide the rollout order.

Migration path This replaces bespoke glue, so treat it as a cutover with a parity gate, not an install:

  1. Verify the diff. Read v1.6.0...v1.7.0. Hard gate.
  2. Decide the authority map. Write down, per app, which fields it owns and which it accepts. Anything not in sync_fields stays local; document that explicitly or it will be rediscovered as a bug in month three.
  3. Resolve ID strategy. No schema work until question 1 is answered.
  4. Pilot one receiver in staging with a production-shaped data clone. Run a full backfill (seed existing users/teams into receivers using the package's own paths so SyncLog stays truthful) and diff row counts and hashes.
  5. Harden transport. Per-app bearer tokens, rotation runbook, network allowlist, inbound rate limiting, and a WAF rule on the receiver endpoints.
  6. Dual-run. Keep the legacy glue active but make it a no-op observer behind a flag; compare SyncLog against legacy sync records for a full business cycle (at minimum: a password change, an email change, a role change, a team add, a team remove).
  7. Cut one low-risk receiver over, then expand. Do not flip all receivers in one window — the failure mode is partial fan-out, and you want the blast radius to be one app while you learn the runbook.

Compatibility Pin ^1.7 in the publisher and all receivers, and treat publisher/receiver version skew as an unsupported matrix until proven otherwise. Record the resolved version in the lockfile and add a scheduled check that the fleet is converged. Verify hasher driver and cost parity across apps; a bcrypt round mismatch between hub and a receiver means replicated hashes verify in one place and not the other.

Sequencing Sequence as: diff review → authority map → ID strategy → single receiver in staging → transport hardening → dual-run parity → one production receiver → fleet rollout. The two steps teams skip are the dual-run parity window and the ID strategy, and those are precisely the two that produce silent cross-app data corruption rather than a loud failure.

Operational Impact

Maintenance Higher than the package's size suggests, because it is a two-sided protocol. Every upgrade is a coordinated fleet operation, not a composer update in one repo: publisher and receivers must move together, and with an opaque changelog each hop requires a manual diff read. Budget a recurring release-review tax and a version-convergence check. The good news is that the codebase is small, final, strict-typed, and MIT — fork cost is low, which is the main thing that makes the maintenance burden acceptable.

Support GitHub issues, one maintainer, no SLA, no evidence of a security disclosure process, zero dependents — meaning we would be among the first production users and would find the integration bugs. For a component that authenticates inbound writes and holds credentials, "we'll fork it" needs to be a genuine, resourced plan rather than a throwaway line. Name an internal owner for this dependency and give them authority to hold the pin when upstream moves.

Scaling Fan-out is O(apps) per user change, so a 50k-user import becomes 50k × N queued jobs — the queue, not the database, is the first thing to fall over. Rate-limit outbound calls per receiver and chunk bulk operations. On receivers, roster loading is users × teams; watch for N+1 through the package's relationships and confirm both pivot foreign keys are indexed before the table is large, because retrofitting indexes on a hot membership table is an outage. SyncLog grows monotonically on both sides — define retention and a prune job on day one.

Failure modes

  • Partial fan-out — three of five receivers updated, no sweeper, no reconciliation command. Silent divergence that surfaces as a login failure in a specific app. We must write the periodic full-resync ourselves; assume the package does not provide one until proven otherwise.
  • Async password change — user changes password on the hub and immediately hits a receiver; the job has not landed. Expect support tickets. Mitigate with a hub-side redirect or an explicit "changes may take a moment" UX.
  • Queue backlog — identity staleness proportional to queue depth. Alert on queue age, not depth.
  • Infinite sync storm — if loop suppression fails on any path (console, worker, sync dispatch), two apps ping-pong user updates. Rate limits and a per-user event budget are the backstop.
  • API key compromise — write access to every receiver. Keys must be per-app, rotated, and revoked independently; a shared secret across receivers converts one breach into a fleet breach.
  • Upgrade drift — a receiver left on 1.6 while the publisher is on 1.7 is an undocumented protocol combination.
  • Non-propagation of deletes — offboarded users persist in every receiver until someone scripts it.

Ramp-up Low for a Laravel developer to use; moderate to own. The concepts engineers must actually internalize are eventual consistency, idempotency, and loop suppression — not Laravel conventions. Ops needs a runbook covering key rotation, queue backlog response, partial-sync reconciliation, and receiver rollback. The reconciliation tooling is ours to build and is not documented upstream; scope it as a deliverable of the integration project, not a follow-up.

Assessment Adopt conditionally, and only as a pilot on one non-critical receiver. This is infrastructure with an auth surface, a credential-replication model, and a multi-app upgrade matrix — it should go through the same review as any service that terminates authenticated traffic, not the review of a helper library. Two gates are non-negotiable before any production cutover: a read of the v1.6.0...v1.7.0 diff, and a written answer on cross-app team/user ID strategy. If the ID strategy turns out to be locally generated IDs with no mapping, the package becomes a reference implementation and we build the mapping layer ourselves — that single answer determines whether this is a two-week integration or a quarter-long platform project.

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.
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
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator