Design spec for the case-page half of #14: a single "Kopieren +
Schließen" text button below the document that copies the document
text to the clipboard and then closes the case, landing on /cases.
The H1 trash-can close button is removed; the standalone icon copy
button stays. A failed clipboard write aborts the close so a finished
case never disappears with an empty clipboard.
Frontend-only (one Askama template + its inline script); no Rust
route change — the close handler already strips the case-page Referer
to /cases. The case-list half of #14 is deferred.
refs #14
Activate the skills plugin for this project with a project profile at
.claude/dev-cycle-profile.yml: server-focused inner-loop build/test,
scripts/check.sh as the audit regression gate, and the Gitea tracker
wired as the boss forward queue.
Set the naming policy to stable_per_directory_4digit (0001-slug.md) for
docs/specs and docs/plans, and rename the existing date-prefixed
artefacts to match. The one internal spec cross-link is updated.
Plan for issue #10. CSS-only: viewport meta tag on every page plus a
@media (max-width: 640px) breakpoint on the three desktop-width pages.
Desktop (>=900px) render stays byte-identical.
Three named profiles (brummel-dev, brummel-minerva, krey-minerva) with
hard-locked watch-serial whitelist in run.sh, to enable safe parallel
testing on Brummel's and Krey's watches against dev and minerva servers.
refs #3
One-line wrapper around docker compose ... restart plus a /api/health
poll, useful after editing users.toml/settings.toml/.env on minerva
(boot-time read). docs/deployment.md updated (user-mgmt, troubleshooting,
TLS-proxy sections) to reference the wrapper instead of the inline
ssh+docker command.
Multi-stage Dockerfile, host-network compose, idempotent deploy script.
Configs and persistent data bind-mounted from /opt/stacks/doctate-server.
deploy-server.sh handles bootstrap + re-deploy in one command with
auto-prune (keep 5 last SHA-tagged images).
See docs/deployment.md for bootstrap, rollback, and TLS-proxy notes.
This commit adjusts the configuration for the `gpt-oss-120b` model to
run in plain-text mode. This is necessary because when
`reasoning_effort` is set to "medium", the reasoning tokens combined
with schema-constrained decoding can exhaust the `max_completion_tokens`
budget, leading to an empty content response.
The change restores the previous behavior where `gpt-oss-120b` was
configured without `response_format` or `top_p`, ensuring the request
body sent to Ionos remains byte-identical to the pre-multi-backend
state. This prevents regressions and maintains stability for existing
production workflows.
When an LLM analysis fails, a `.analysis_failed.json` marker is created.
If no document exists yet and the auto-trigger is blocked by this
marker,
the case page must display a banner. This banner provides the failure
reason and a button to retry the analysis, ensuring users are not left
in a dead-end state.
The `read_failure_marker` function is made public to allow the web layer
to access this failure information. The `CasePageTemplate` is updated to
include `analysis_failed` data, which conditionally renders the new
`.failure-banner` HTML.
This change prevents cases from becoming unrecoverable due to transient
LLM errors.
The `client-desktop` crate is now located within the `clients/desktop/`
directory and renamed to `doctate-desktop`. This change improves
organization and clarity within the project structure.
This commit introduces the `doctate-canary` service and associated sweep
experiments.
The service provides access to the `nvidia/canary-1b-v2` ASR model via a
native FastAPI API. It includes deployment scripts, Docker
configurations, and detailed documentation on installation, API usage,
and environment variables.
The sweep experiments aim to thoroughly evaluate the Canary model's
performance under various configurations. This includes testing
different inference pipelines (single-shot vs. buffered), decoding
strategies (greedy vs. beam search), and parameter tuning (chunk length,
overlap, batch size, precision). The goal is to reproduce previous
findings and identify optimal settings.
The commit also includes:
- Utility scripts for audio transcoding and manipulation.
- Comprehensive logging and result collection mechanisms for the sweep
runs.
- Detailed analysis of `dur=0` occurrences and word confidence,
concluding they are not reliable indicators of hallucination.
- Documentation on the interaction between decoding parameters,
especially `return_hypotheses`, and the availability of confidence
scores.
This commit changes the way transcriptions are stored and accessed.
Instead of using plain text files (`.transcript.txt`), transcriptions
will now be part of a JSON metadata file (`<stem>.json`). This allows
for richer metadata to be stored alongside the transcript, such as
duration, and provides a more robust mechanism for tracking
transcription states.
The changes include:
- Updating documentation and code to reflect the new `.json` file
extension.
- Modifying file handling logic to read and write JSON metadata.
- Adjusting tests to accommodate the new file format.
Replaces the `.transcript.txt` sidecar with a structured `.json` file
for recording metadata. This change consolidates transcript text,
duration, and other potential metadata into a single, extensible JSON
object.
This also refactors the `TranscriptState` enum to better represent the
on-disk state (absence of file means pending) and the in-memory
representation. The `Transcript` enum now specifically models the
terminal outcomes of the transcriber (`Silent` or `Content`).
The commit includes updates to documentation, data structures, path
handling, and various tests to align with the new metadata format.
The project plan has been updated to reflect the successful testing of
the Pixel Watch 2 hardware. The plan now includes details about
ADB-over-WiFi pairing and testing against a local development server. It
also mentions the successful manual verification of the end-to-end flow
on the real device.
Further testing, including LTE mode, doze mode, and long-term foreground
service behavior, is still pending.
Add details about the `purge-closed` endpoint, including its admin-only
nature and confirmation requirement.
Clarify the admin-only checks for bulk actions, emphasizing that they
are now performed at the entry handler level.
Refine the explanation of the case list display, particularly the
`open_count/total_count` grouping and how closed cases are handled.
Introduce the concept of analysis preview in the case list, explaining
its implementation using CSS `line-clamp` and avoiding server-side
truncation.
Enhance the description of admin
The /api/oneliners time window is now read per-user from users.toml
(window_hours, default 72h). Clients no longer carry a window:
client.toml oneliner_window_hours, SyncConfig.window_hours, the
?hours=N query param, and the render_case_list cutoff filter are
gone. ETag suffix keeps the effective hours so an admin edit to
users.toml invalidates client caches on the next request.
OnelinersResponse.window_hours stays in the wire format, but now
exists solely to anchor client reconciliation.
The `oneliner.txt` file marker has been updated to `oneliner.json`. This
change reflects the new state management for the oneliner, which now
uses an internally-tagged enum (`OnelinerState`) to represent different
states (Ready, Empty, Error) along with a `generated_at` timestamp. This
provides a more robust way to handle different outcomes of the LLM call,
particularly differentiating between an intentionally empty response and
a transient error.
Implement Server-Sent Events to push real-time updates to the client,
eliminating the need for manual refreshes. The SSE endpoint filters
events for non-admins based on slugs and provides a 15-second
keep-alive to prevent proxy timeouts.
Introduce `doctate-client-core` to house UI-agnostic client business
logic. This promotes code reuse and allows consumption by different
client platforms, such as iOS via UniFFI bindings.
This commit also updates `client-desktop` to depend on
`doctate-client-core` and removes duplicated logic.
Refine documentation regarding the desktop client, including its
architecture, tech stack, and development rationale. Emphasize the
choice of `eframe`/`egui` over alternatives like Tauri and Compose
Multiplatform, and explain the decision to use `ffmpeg` as a subprocess
for audio recording and graceful stopping. Clarify the rationale for
prioritizing the desktop client's development.
Update the project plan documentation to reflect recent architectural
changes and planned features. This includes clarifying the role of Axum,
the filesystem structure, endpoint definitions, and the management of
prompts.
Key changes:
- Clarified Axum's role as a coordinator handling sequential workers and
the web interface.
- Adjusted filesystem structure to use user slugs instead of open/done
directories and introduced a soft-delete marker.
- Updated endpoint definitions to reflect current and planned API
structures.
- Removed the mention of `prompts.toml` as prompts are now hardcoded,
with plans for future override capabilities.
- Added detail on marker semantics for file states.
- Refined the description of LLM provider configuration and its impact
on the UI.
- Introduced user-specific Whisper settings in `users.toml`.
Updates the `LLM_URL` in the project plan and `.env.example` to the
correct value.
Also, adds a warning in `main.rs` to inform the user if the LLM is not
configured, which effectively disables the 'Fall abschließen' feature.
This commit introduces the foundation for web-based authentication and
user interface. It includes:
- **Session Management**: Securely handling user sessions using
cryptographically generated tokens, cookies with appropriate security
flags, and server-side storage.
- **Login/Logout Functionality**: Endpoints for users to log in with
their credentials and log out, clearing their session.
- **User Interface**: Basic templates for the login page, a list of
cases, and a detailed view of a single case, allowing users to
navigate and view their data.
- **Authorization**: An `AuthenticatedWebUser` extractor to ensure only
logged-in users can access protected web routes.
- **Configuration**: Added a `cookie_secure` option to the configuration
to control the `Secure` flag on session cookies, useful for local
development.
- **Dependencies**: Added necessary dependencies for password hashing,
time handling, and TOML file manipulation.
- **Helper Binary**: Included a `hash-password` binary to simplify
generating bcrypt hashes for user passwords.
This commit introduces the capability to configure user-specific Whisper
settings, including language, hotwords, and initial prompts. These
settings are stored in `users.toml` and are passed to the Whisper
service for more tailored transcription results.
New unit tests have been added to verify that the `transcribe` function
correctly forwards these optional settings to the Whisper client and
omits them when they are not provided.
Additionally, a new directory `tests/fixtures/dictations` has been
created to store M4A audio files, their expected transcripts, and
associated hotword files. This serves as a regression corpus for the
Whisper pipeline. A README file explains the structure and conventions
for adding new fixtures. Several new fixtures have been added, covering
various medical domains and transcription scenarios.
Update task status to 'done' for several items in the project plan. This
includes setting up the Axum server, filesystem structure,
configuration, logging, and upload endpoints. It also covers the Docker
setup for Axum and faster-whisper, as well as Ollama configuration.
Additionally, the plan now reflects a dedicated `whisper/` service for
faster-whisper, detailing its endpoints, model configuration, hotword
support, and deployment. Changes to the Ollama client configuration and
the oneliner generation logic are also documented.
The transcription queue and recovery mechanisms are marked as done,
along with the faster-whisper and Ollama health checks and retries.
Several aspects of the case management and UI development, including
askama templates and the detail view, have been updated.
Finally, the project plan includes a decision to use `large-v3-turbo`
for the Whisper model and details the implementation of a dedicated
`whisper/` service due to hallucination issues with previous wrappers.
The Ollama model is updated to `gemma4:latest`, and the GPU phase worker
logic is adjusted to leverage the smaller VRAM footprint of the
`large-v3-turbo` model. A new script `scripts/dictate.sh` is introduced
as a stand-in for testing the watch-flow without actual hardware.
Introduces a new web interface to list cases and play back audio
recordings. This includes:
- A new `web` module in `routes` to handle web requests.
- `handle_case_list` to scan and display available cases and their
recordings.
- `handle_audio` to serve audio files, with validation to prevent path
traversal and ensure correct file types.
- `AppError::NotFound` variant to handle missing resources gracefully.
- Updates to `projektplan.md` to document the change in STT container
and m4a preprocessing.
- New tests in `server/tests/web_test.rs` to ensure the web interface
functions correctly.
Refactor configuration loading to separate user credentials from server
settings.
Update dependencies to their latest compatible versions to leverage new
features
and security patches.
Key changes include:
- Moving user credentials (`api_key`, `web_password`, `role`) from
`.env`
to a dedicated `users.toml` file for better manageability and
security.
- Introducing an `AuthenticatedUser` struct and extractor for API
key-based
authentication.
- Updating `axum` and related crates to leverage Rust edition 2024
improvements.
- Adjusting configuration values and tests to reflect these changes.