Repository navigation
Releases: teylabs/concierge
Releases · teylabs/concierge
Release list
v0.9.3
Added
MembersIndex::scopeMembersUsing($scope): a host narrows the members the index lists and counts with its own rule (afunction (Builder $memberships, Workspace $workspace): void). It's applied to both the rows and the Members tab count, inside a nestedwhere, so the host'sorWherecan't widen the workspace, guest or status constraints. Without a scope, the index behaves as before.
What's Changed
- Add a host scope to the members index (0.9.3) by @jaspertey in #153
- Release 0.9.3 by @jaspertey in #154
Full Changelog: v0.9.2...v0.9.3
v0.10.0
Added
php artisan concierge:installdetects the app, asks only what it can't detect, and sets concierge up, printing one line per step (#144).- It detects the starter kit (Vue, React, Svelte, Livewire or none), WorkOS AuthKit, the sign-in, the user model, any team or organisation model, and Spatie's setup.
- It asks whether to adopt a team model, which mode to use, and whether to turn on local login, each with a flag;
--no-interactiontakes the defaults. - It publishes and configures Spatie permission, writes
config/concierge.php, migrates and syncs roles. - It never rewrites models: one missing a contract gets the exact lines to add, and the command stops until you run it again.
- Running it again changes nothing that's already in place.
--dry-run --jsongives the plan.
- Default routes, controllers and policies, each overridable (#145). Named
concierge.*routes cover managing members (index, invite, member page, roles, suspend, reinstate, remove, transfer ownership, invitation resend and revoke) and accepting invitations.- They're registered only when concierge is set up, membership is on and
concierge.routes.enabledis true.concierge:installwrites'enabled' => true; the package default isfalse. - Override pieces through config (
routes.prefix,routes.middleware,routes.invitation_middleware,routes.home,routes.pages), by binding a controller subclass, or through Gate abilities (Tey\Concierge\Http\Abilities). An app's own ability definition always wins. - Pages render through the new
Contracts\PageResponder: Inertia when installed, JSON otherwise. - There are new page-prop builders (
MemberPage,InviteMemberPage,AcceptInvitationPage,RoleOptions), plusMembersIndex::row()androleBadges(). - With the routes on,
Concierge::invitationUrl()defaults toconcierge.invitations.show;invitationUrlUsing()still wins.
- They're registered only when concierge is set up, membership is on and
- Laravel Boost guidance (#146): a guideline and a
concierge-developmentskill, so coding agents use concierge's actions and routes instead of rebuilding them. A test fails if a command, option, action or event ships without being named in the skill. - Read-only Boost MCP tools
concierge-statusandconcierge-plan(#147). They're added to Boost's MCP server when Boost is installed, and they work before setup. Inviting, granting roles and creating owners stay withphp artisan concierge:*.
Changed
- Concierge registers nothing until it's set up (#142). Without the app's own
config/concierge.php(or with'setup' => false), it registers no migrations, routes, middleware, listeners, bindings or commands other thanconcierge:install. Socomposer require tey/conciergefollowed byphp artisan migratecreates no concierge tables.php artisan aboutshows the setup state.
Fixed
- The scaffolding tests are safe under
pest --parallel: each test process gets its own copy of the Testbench skeleton (#148).
Upgrading
- Existing apps: nothing changes. Your
config/concierge.phpmarks concierge as set up, so it registers exactly as before. Without arouteskey, the new routes stay off, no Gate abilities are defined, and invitation links still come only frominvitationUrlUsing(). - To adopt the default routes, copy the
routesblock from the package config intoconfig/concierge.phpwith'enabled' => true, runphp artisan concierge:pagesif you haven't, and remove your own routes and controllers for the same pages. Check thatroutes.prefixdoesn't clash with your paths; the default is no prefix, giving/membersand/invitations/{token}. Add rate limiting throughroutes.invitation_middleware(for examplethrottle:30,1). - With Laravel Boost, run
php artisan boost:installorboost:updateto pick up the guidance and tools. - Running
concierge:installon an app that's already set up is safe: it reports what's in place and changes nothing.
What's Changed
- Register nothing until concierge is set up by @jaspertey in #142
- Add concierge:install to detect the app and set concierge up by @jaspertey in #144
- Ship routes, controllers and policies by default, each overridable by @jaspertey in #145
- Add Laravel Boost guidelines and a concierge-development skill by @jaspertey in #146
- Add read-only concierge-status and concierge-plan tools to Laravel Boost by @jaspertey in #147
- Make the scaffolding tests safe under pest --parallel by @jaspertey in #148
- Release 0.10.0 by @jaspertey in #151
Full Changelog: v0.9.2...v0.10.0
v0.9.2
Fixed
- A comma in the members or invitations search no longer returns a 500.
MembersIndexregistered itssearchandrolefilters with Spatie's default,delimiter and then cast the value with(string), so?filter[search]=Viewer, Ownerhit "Array to string conversion". Search and role now take one value (no delimiter). An array value (filter[search][]=x,sort[]=x,tab[]=x) is ignored as invalid input, or fortabrefused as an unknown tab, and never cast to a string. This matches tey/kit 0.5.21's TableQuery fix.
What's Changed
- Keep a comma in the members search as one value; ignore array query values by @jaspertey in #149
- Release 0.9.2 by @jaspertey in #150
Full Changelog: v0.9.1...v0.9.2
v0.9.1
Changed
- The current workspace and a user's memberships are read once per request and remembered in a request-scoped
RequestMemo(bound withscoped(), so it's dropped between requests, queued jobs and Octane requests; no cache store). It's cleared by writes to the membership, ownership, workspace, user and role tables, by a transaction rollback, and when the workspace context is entered or left. For 5 repeated calls in one request:member()20 → 4 queries,workspacesOf()25 → 5,current()5 → 1 (#141, closes #128).
Known limitations
- A host that writes those tables over another database connection, or with query events off, sees the remembered reads until the request ends.
What's Changed
- Link llms.txt and llms-full.txt from the README by @jaspertey in #140
- Read the current workspace and memberships once per request by @jaspertey in #141
- Release 0.9.1 by @jaspertey in #143
Full Changelog: v0.9.0...v0.9.1
v0.9.0
Added
- Scoped invitations: invite someone to act on one record with no other access in the workspace. An invitation takes an optional
scope(a morph type and id, part of its fingerprint). Accepting it creates a guest-only membership plus aconcierge_membership_scopesrow (invited_by, accepted_at, revoked_at). A full member given a scope stays a full member and gains the scope (#138, closes issue 133). ScopedAccesscontract with a membership-backed implementation, aconcierge.scoped:{param}[,members]middleware, and facade helpers, for routes, policies and MCP tools to share one access check.RevokeScope: immediate. It kills a pending link, and removes the guest membership when it was the last scope; the account survives.ScopeAcceptedandScopeRevokedevents.- Guest exclusions by default: scoped guests are left out of member lists, role pickers, role changes, ownership transfer and
concierge.member(a guest-only membership gets 403).
Changed
- Accepting a scoped invitation whose record was deleted refuses with
scope_missing, writes nothing and leaves the invitation pending. A swapped record is refused asGrantsChangedthrough the fingerprint.
Upgrading
- Run the new migration (
update_concierge_invitations_with_scope). App mode refuses a scope.
Known limitations
- No invite UI,
concierge:inviteoption or TypeScript types for scopes yet; those follow.
What's Changed
- Add scoped invitations for one-record guests by @jaspertey in #138
- Release 0.9.0 by @jaspertey in #139
Full Changelog: v0.8.4...v0.9.0
v0.8.4
Added
WorkspaceContext::enter($workspace, $refresh)andleave(), an explicit enter/leave alongside the scopedrun(). Entries nest, andleave()with nothing entered throwsLogicException.run()is now enter, try, finally leave, with unchanged behaviour. This lets a tenant switch task (spatie/laravel-multitenancy) hold the workspace context across a job or command (#136).
Upgrading
- An app with its own
WorkspaceContextimplementation must addenter()andleave().
What's Changed
- Add enter and leave to the workspace context, with run built on them by @jaspertey in #136
- Release 0.8.4 by @jaspertey in #137
Full Changelog: v0.8.3...v0.8.4
v0.8.3
Fixed
- An invited sign-up through Fortify's registration is created with its email verified when a remembered pending invitation (member or tenant) matches the address, so the invitee gets one email, not a second verification email.
- Accepting an invitation as a signed-in, unverified account whose email is the invited address verifies it inside the accept transaction (member, app-wide and tenant invitations) and reports it Ready. A different address is still Unverified.
- A successful password reset through the emailed signed link verifies the account, since it proves control of the mailbox. This covers the first owner created by
concierge:owners. See README, Security (#134).
What's Changed
- Verify an email once its mailbox is proven by @jaspertey in #134
- Release 0.8.3 by @jaspertey in #135
Full Changelog: v0.8.2...v0.8.3
v0.8.2
v0.8.1
Added
- Join as the signed-in account. A new
concierge.invitations.match_emailsetting (defaulttrue, today's behaviour). When it'sfalse, someone signed in with a different, verified email can accept an invitation as themselves. Every other check still applies: expiry, revoked, the workspace accepting members, the inviter still authorised, grants unchanged, and already a member. The invitation records who accepted it and whether they used a different email (#127). - The accept page offers "Join as {email}" before Switch account, with "This invitation was sent to {email}." Member rows in
MembersIndexcarryacceptedWithOtherEmailandinvitedEmail, so a host can show who accepted. docs/scenarios.mdadds the join-as cases and updates the accept decision tree.
Upgrade notes
- Publish and run the new migration (
update_concierge_invitations_with_acceptor). It adds one boolean column, defaulting to false. - Nothing else changes unless you set
concierge.invitations.match_emailtofalse. To offer Join as, passotherEmail: $inspection->otherEmail,signedInAsand theswitchAccountlink on the ready state.
Full Changelog: v0.8.0...v0.8.1
v0.8.0
Added
- Switch account on invitations. Someone signed in as a different email who opens an invitation sees who it is for, with Switch account and Cancel. Switching keeps a signed, short-lived invitation token through sign-out and sign-in (or registration) and returns them to accept it. A signed-out person with an existing account signs in and comes straight back to accept.
- No-workspace landing. A member who is removed, leaves or is suspended is moved to their next active workspace, or to none, and sent to
workspaces.no_workspace_urlinstead of an error. CopyInvitationLinkissues a new invitation link without sending an email, and the previous link stops working.MembersIndexoffers it as acopy_linkrow action to people who may resend, with the confirmation "The previous link will stop working."- Invitations take an optional personal
message(up to 500 characters), set byInviteMemberandResendInvitation. It's shown on the invitation, on member-list rows and in the invitation email. - Suspend and reinstate row actions ask for confirmation.
docs/scenarios.md: every membership and invitation scenario with the test that proves it, plus diagrams of accepting an invitation, the membership lifecycle and where a member lands after signing in.
Fixed
- Searching members and invitations ignores case on every database. It was case-sensitive on PostgreSQL.
Upgrade notes
- Publish and run the new migration (
update_concierge_invitations_with_message). - Member-only workspace routes now return 404 to someone who was never a member (it was 403). A past member is redirected to
workspaces.no_workspace_urlinstead. - The
accept.wrong_accountlabel has new wording.accept.wrong_account_as,accept.switchAccountandaccept.cancelare new labels. MembersIndexrows include acopy_linkaction when the host mapsinvitation.copyLink.
Full Changelog: v0.7.6...v0.8.0