Files
TX/lib
riyadhafraa 60a18e1c7c Task #162: Let admins pre-set required permissions while creating an app
The "Required permissions" section was previously edit-only because
`POST /api/apps/:id/permissions` needs an app id, leaving a brief
window where a freshly created app was visible to everyone before
the admin could re-open the dialog and gate it. The Add app dialog
now lets the admin pick required permissions up front and the new
app + its `app_permissions` rows are written in a single transaction.

Changes:
- `lib/api-spec/openapi.yaml`: extended `CreateAppBody` with an optional
  `permissionIds: integer[]` field. Ran `pnpm --filter @workspace/api-spec
  run codegen` so `lib/api-zod` and `lib/api-client-react` reflect it.
- `artifacts/api-server/src/routes/apps.ts`: `POST /apps` now de-dupes
  and pre-validates `permissionIds`, returns 404 if any id is unknown
  (without creating the app), and inside one transaction inserts the
  app, the `app_permissions` rows (with `.onConflictDoNothing()` against
  the composite primary key), and a single `permission_audit` row
  (`previousIds: []`, `newIds: requestedIds`). After the transaction it
  also writes one `app.permission.add` audit_logs entry per inserted
  permission so the admin log mirrors the post-create flow.
- `artifacts/tx-os/src/pages/admin.tsx`: added `permissionIds: number[]`
  to `AppForm`, a new `NewAppPermissionsPicker` component (rendered only
  in create mode — edit mode keeps the existing `AppPermissionsEditor`
  with its impact preview) that lets admins add/remove permissions
  locally before submit, and wired `handleSaveApp` to forward the
  selected ids when creating. Existing edit path strips the field so
  the update payload remains unchanged.
- `replit.md`: documented the new picker and POST /api/apps behavior.

No impact preview is shown in the create-mode picker because a brand
new app starts with zero users seeing it, so adding permissions cannot
hide it from anyone.

Code-review follow-up: tightened input validation so non-integer or
non-positive `permissionIds` now return 400 with a clear error instead
of being silently dropped by the previous filter. The legacy single-add
endpoint already used this exact 400 message, so behavior stays
consistent across both create and update paths.

Verification:
- `pnpm --filter @workspace/api-spec run codegen` passes.
- `pnpm --filter @workspace/api-server` typechecks with no new errors
  (executive-meetings.ts errors are pre-existing and unrelated).
- Ran the existing app-permission test suites
  (`app-permission-audit.test.mjs`, `app-permissions-crud.test.mjs`,
  `app-permissions-impact.test.mjs`) directly — all 16 tests pass.
- Ran an e2e Playwright test (login as admin → Add app → pick a
  permission → save → verify the row shows 1 restriction → reopen and
  confirm the assigned permission). All steps passed.

Follow-up proposed: automated tests for the new create-with-permissions
endpoint behavior (#231).

Replit-Task-Id: c229777c-4036-4a6a-b4cb-05ccc18f6c9b
2026-04-30 18:21:21 +00:00
..