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
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.
Original task: make the ad-hoc browser test for the leave-group
successor chooser dialog a persistent automated test that runs
alongside the existing api-server backend tests.
Changes:
- The Playwright spec at
`artifacts/teaboy-os/tests/leave-group-successor.spec.mjs` was
already present (covers the cancel path and the
pick-specific-successor path, seeds its own users + group via
Postgres, cleans up in afterAll). Verified it passes against the
running web + api workflows.
- Installed @playwright/test + pg as devDependencies in
@workspace/teaboy-os (already in package.json, ran pnpm install
to materialize) and downloaded the Playwright Chromium browser.
- Added a root `test` script in package.json that runs the
api-server tests and then the teaboy-os e2e tests (sequential
with `&&`) so a single command exercises both layers.
- Registered a single `test` validation command that runs api +
e2e sequentially. Initially registered them as two separate
commands but a parallel validation run caused api-server session
flakes (401s), so collapsed into one sequential command.
- Updated `scripts/post-merge.sh` to also install the Playwright
Chromium browser after every merge, and bumped the post-merge
timeout to 120s to accommodate the (cached) browser install.
Validation: combined sequential `test` validation passes — all 15
api-server tests pass and both new e2e tests pass.
Note: `artifacts/teaboy-os/public/opengraph.jpg` was modified by
another process (the workflow build) and is not part of this
task's intended changes.
Replit-Task-Id: ab9b6d6f-b68b-47ea-94e5-c34352afeb64
Problem
- Dev environment login returned 500: `column "clock_style" does not
exist`. Task #20's schema change for the per-user clock style was
never applied to the dev DB because `scripts/post-merge.sh` runs
`drizzle-kit push` interactively, and drizzle-kit got stuck on a
prompt asking whether `app_opens` was a rename of `user_sessions`.
When the prompt couldn't be answered, the whole sync exited without
applying any pending changes — including the new column.
Changes
- Applied the missing column directly:
`ALTER TABLE users ADD COLUMN IF NOT EXISTS clock_style varchar(30);`
(nullable, no default — matches `lib/db/src/schema/users.ts`).
Verified column now present.
- scripts/post-merge.sh: switched
`pnpm --filter db push` → `pnpm --filter db run push-force`.
The `push-force` script (already defined in `lib/db/package.json`)
passes `--force` to drizzle-kit, which auto-accepts safe operations
and treats ambiguous renames as creates — which is the correct
behavior for our case (we genuinely have new tables, not renames).
This prevents the same class of failure from recurring after future
merges.
Verification
- Restarted the API server.
- `POST /api/auth/login` with admin/admin → HTTP 200, returns AuthUser
with `clockStyle: null` (frontend already falls back gracefully, no
home.tsx change needed).
- No new 500s in the API logs.
Out of scope (as planned)
- Backfilling a default value for existing rows.
- Resolving the underlying drizzle-kit `app_opens` rename detection
— `--force` sidesteps it correctly.