Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions client-tauri/src/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ export default function Settings({ email, onLogout }: SettingsProps) {
try {
await invoke("api_create_user", {
email: newUserEmail,
firstName: newUserFirst,
lastName: newUserLast,
first_name: newUserFirst,
last_name: newUserLast,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-11-04
31 changes: 31 additions & 0 deletions openspec/changes/fix-client-create-user-ipc-arguments/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## Context

See `proposal.md` for background and problem statement. In `client-tauri/src/Settings.tsx`, `handleCreateUser` calls `invoke("api_create_user", { email: newUserEmail, first_name: newUserFirst, last_name: newUserLast })`.
In `client-tauri/src-tauri/src/lib.rs`, `api_create_user` is defined as:
```rust
#[tauri::command]
fn api_create_user(email: String, first_name: String, last_name: String) -> Result<serde_json::Value, String>
```
Tauri's procedural macro converts Rust parameter names to `lowerCamelCase` when deserializing incoming JSON arguments unless explicitly configured with `rename_all`. As a result, Tauri expects `firstName` and `lastName`. Because `Settings.tsx` supplies `first_name` and `last_name`, Tauri IPC throws a deserialization error (`missing required key firstName`) and aborts the command before invoking the backend API.

## Goals / Non-Goals

**Goals:**
- Fix `handleCreateUser` in `Settings.tsx` to supply `firstName` and `lastName` to satisfy Tauri's IPC deserializer.
- Provide both `firstName`/`lastName` and `first_name`/`last_name` in the invocation payload to maintain full forward/backward compatibility.
- Ensure the desktop client build and static analysis succeed without regressions.

**Non-Goals:**
- Changing backend FastAPI HTTP endpoints (FastAPI expects snake_case, which `api.rs` already formats in `CreateUserBody`).
- Altering the user creation modal UX or password handling.

## Decisions

### Decision 1: Frontend Payload Parameter Casing Alignment
- **Choice**: In `Settings.tsx`, pass `firstName: newUserFirst, lastName: newUserLast, first_name: newUserFirst, last_name: newUserLast`.
- **Rationale**: Tauri v2 `CommandItem::deserialize_json` expects `firstName` and `lastName` based on Rust parameter names. Passing both camelCase and snake_case ensures that default Tauri command deserialization succeeds immediately while safeguarding against any variant expectations.
- **Alternatives considered**: Adding `#[tauri::command(rename_all = "snake_case")]` in `lib.rs`. While valid, all other commands across the Tauri client (`api_change_password`, `set_sync_folder_path`, etc.) follow the standard Tauri camelCase convention. Aligning the frontend invocation maintains consistency across the entire client IPC layer.

## Risks / Trade-offs

- None identified. Passing additional keys in the JSON payload is safely ignored by Tauri's IPC deserializer.
27 changes: 27 additions & 0 deletions openspec/changes/fix-client-create-user-ipc-arguments/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Why

In the Tauri desktop client (`client-tauri`), the user administration dialog allows administrators to create new users. When submitting the user creation form, `Settings.tsx` invokes the Tauri command `api_create_user` with a payload containing `{ email, first_name, last_name }`.

However, Tauri's `#[tauri::command]` procedural macro converts Rust parameter names (`email`, `first_name`, `last_name`) to `lowerCamelCase` (`email`, `firstName`, `lastName`) for IPC command arguments by default. Tauri's JSON deserializer strictly expects the keys `"firstName"` and `"lastName"`. Because the frontend sends snake_case keys (`first_name`, `last_name`), Tauri fails deserialization immediately with:
`command api_create_user missing required key firstName`.

As a result, creating a new user from the desktop client settings UI always fails with an error and cannot be completed.

## What Changes

- Update `handleCreateUser` in `client-tauri/src/Settings.tsx` to supply camelCase parameter keys (`firstName`, `lastName`) as required by Tauri's IPC deserializer, while also providing `first_name` and `last_name` for defense-in-depth compatibility.
- Ensure the user creation flow correctly completes against the Tauri IPC command interface.

## Capabilities

### New Capabilities
<!-- None -->

### Modified Capabilities
- `desktop-client`: Align Tauri IPC command invocation parameters for `api_create_user` with Tauri's command deserialization requirements (`firstName` and `lastName`).

## Impact

- Affected files: `client-tauri/src/Settings.tsx`.
- User-facing impact: Administrators can successfully create new user accounts from the desktop client settings interface without encountering `missing required key firstName` errors.
- No breaking changes or external dependencies added.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## ADDED Requirements

### Requirement: Desktop Client User Creation IPC Compatibility
The desktop client settings UI SHALL supply user creation arguments adhering to Tauri's lowerCamelCase IPC parameter conventions (`firstName` and `lastName`) when invoking the `api_create_user` command.

#### Scenario: Submitting new user form from settings
- **WHEN** an administrator enters email, first name, and last name and submits the user creation dialog
- **THEN** the frontend invokes `api_create_user` with `firstName` and `lastName` matching the deserialization contract of the Tauri command handler
- **AND** the command does not fail with `missing required key firstName` or parameter deserialization errors
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## 1. Implementation

- [x] 1.1 Update `handleCreateUser` in `client-tauri/src/Settings.tsx` to include `firstName` and `lastName` (along with `first_name` and `last_name`) in the `api_create_user` invocation payload

## 2. Verification

- [x] 2.1 Build `client-tauri` frontend (`npm run build`) and verify TypeScript compilation and bundle generation succeed
- [x] 2.2 Run `cargo test` in `client-tauri/src-tauri` and verify all desktop client tests pass
- [x] 2.3 Run `./scripts/run-qa.sh` or relevant verification checks to ensure no regressions
Loading