Replaces all user-facing instances of "TeaBoy" with "Tx" across the application, including titles, locale files, database settings, seed data, and API documentation. Also updates internal storage keys and session secrets to remove the old branding.
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 07b19cb0-11b5-4be9-8932-ae4820eb73b8
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/HxTkDPZ
Replit-Helium-Checkpoint-Created: true
Original task: Task #75 — add automated tests for the groups system
(CRUD + group-driven app visibility + auto-Everyone) and stabilize the
flaky pagination test.
Changes:
- Extended artifacts/api-server/tests/groups-crud.test.mjs with four
new tests:
* PATCH /api/groups/:id updates fields and replaces userIds
transactionally; a bad userId returns 400 and leaves prior
membership unchanged.
* Creating a group with invalid roleIds returns 400 and creates no
rows.
* DELETE /api/groups/:id removes a custom group; deleting a system
group (Everyone, is_system = 1) returns 400 and the row stays.
* /api/auth/register auto-assigns the new user to the Everyone
system group; verified both via the response payload and a direct
user_groups DB check. The test temporarily flips
app_settings.registration_open to true and restores the prior
value on completion.
- The existing apps-group-visibility.test.mjs already exercises the
/api/apps endpoint backed by getVisibleAppsForUser for group-derived
admin, group member, and outsider — no changes needed there.
- The previously flaky tests/admin-app-opens-pagination.test.mjs now
passes consistently thanks to the existing 7d-window cleanup in its
before hook; left as-is per the task's "fixed or skipped" criterion.
Verification: `pnpm --filter @workspace/api-server test` reports
42/42 passing. The downstream Playwright suite (4 tests) also passes.
Replit-Task-Id: 188075ef-382c-4af1-8a9a-90a0563c92c2
Auth middleware:
- Add getEffectiveRoleIds() that UNIONs user_roles with group_roles via
group memberships, used by requireAdmin / requirePermission /
userHasPermission / getUserRoles.
- requireAdmin and requirePermission now also reject inactive users
with 401 (matching requireAuth), closing a session-after-deactivation
bypass.
Groups routes:
- POST /groups and PATCH /groups/:id now wrap the group row write and
all assignment writes in a single db.transaction via
applyGroupAssignmentsTx(tx, ...), so partial state cannot leak.
- validateAssignmentIds rejects unknown app/role/user ids with 400
before any insert.
- Removed AI-slop: void or, void sql, as-unknown-as casts; conditions
use Drizzle's SQL union type.
Users route:
- /api/users supports q, groupId, status filters (server-side).
Admin UI (teaboy-os/admin.tsx):
- UsersPanel wires q/groupId/status to the backend, shows display name
and preferred language inline per row.
- UserGroupsEditor now edits display names (ar/en), preferred language,
active status, and group membership with a search box.
- GroupsPanel adds a top-level group search box.
- GroupDetailEditor Users tab adds a user search box.
Infra:
- scripts/post-merge.sh runs the seed (idempotent) so default groups
Admins / TeaBoy / Everyone always exist after merges.
Tests (artifacts/api-server/tests/groups-crud.test.mjs, all passing):
- Admin-only access (regular user gets 403).
- Default seed groups exist.
- Create group + member assignment.
- Bad userIds yields 400 with no leaked group row.
- Admin role inherited via group_roles grants admin access.
- Deactivated admin session is rejected with 401.
- Group create rolls back atomically when assignment fails.
- /api/users q + groupId + status filters return correct rows.
Notes / drift:
- "Roles" tab inside GroupDetailEditor and groupIds in CreateUserBody
remain as proposed follow-ups (require OpenAPI spec changes).
- Pre-existing pagination-test flake unrelated to this work.