chore: update AGENTS.md and CLAUDE.md for improved documentation

- Revised AGENTS.md to provide comprehensive guidance for AI coding assistants, including project overview, architecture, and development commands.
- Enhanced CLAUDE.md by adding the `auth` directory to the infrastructure section, clarifying the project's structure and components.
- Improved formatting and organization of both documentation files for better readability and usability.
This commit is contained in:
2026-01-07 03:35:07 +00:00
parent 207fa8e9b1
commit bae4e775d7
2 changed files with 787 additions and 93 deletions

869
AGENTS.md
View File

@@ -1,109 +1,796 @@
# Repository Guidelines
# AGENTS.md
## Repository Overview
- Noteflow ships a Python backend (gRPC server + domain services) and a Tauri + React desktop client.
- The gRPC API is the shared contract between backend and client; schema lives in `src/noteflow/grpc/proto/noteflow.proto`.
- Backend code is layered: domain (pure models + ports), application (use-cases), infrastructure (IO implementations).
- The repo is split into backend package (`src/noteflow/`) and frontend app (`client/`), with tests and docs alongside.
- When you touch shared contracts (proto fields/enums, DTOs), update Python, Rust, and TypeScript counterparts together.
This file provides guidance to AI coding assistants (Cursor, Copilot, Codex, etc.) when working with code in this repository.
## Quick Orientation (Start Here)
- Backend entry point: `python -m noteflow.grpc.server` (service implementation in `src/noteflow/grpc/service.py`).
- Tauri/React client: `cd client && npm run dev` (web), or `npm run tauri dev` (desktop).
- Tauri IPC bridge: `client/src/api/tauri-adapter.ts` (TS) <-> `client/src-tauri/src/commands/` (Rust).
- Protobuf contract and generated stubs live in `src/noteflow/grpc/proto/`.
## Project Overview
## Project Structure & Module Organization
- `src/noteflow/domain/` defines entities, value objects, and port protocols; keep this layer pure and testable.
- `src/noteflow/application/` hosts use-case services (Meeting, Recovery, Export, Summarization, Trigger, Webhook, Calendar, Retention, NER).
- `src/noteflow/infrastructure/` provides concrete adapters (audio, ASR, persistence, security, summarization, triggers, calendar, ner, observability, webhooks, converters).
- `src/noteflow/grpc/` contains the server, client wrapper, modular mixins (streaming/, diarization/ as packages), and proto conversions.
- `src/noteflow/cli/` provides CLI tools for retention management and model commands.
- `client/` is the Tauri/Vite React client; UI in `client/src/`, Rust shell in `client/src-tauri/`, e2e tests in `client/e2e/`.
NoteFlow is an intelligent meeting notetaker: local-first audio capture + navigable recall + evidence-linked summaries. It is a client-server system built around a gRPC API for bidirectional audio streaming and transcription. The repository includes:
## Backend Architecture & Data Flow
- gRPC server entry point lives in `src/noteflow/grpc/server.py`; `NoteFlowServicer` in `src/noteflow/grpc/service.py` composes feature mixins.
- Proto <-> domain conversions and enum mappings are centralized in `src/noteflow/grpc/_mixins/converters.py`.
- Unit-of-work and repositories live under `src/noteflow/infrastructure/persistence/`, with memory fallback when no DB is configured.
- Streaming audio ingestion uses `src/noteflow/infrastructure/audio/` and ASR/VAD components in `src/noteflow/infrastructure/asr/`.
- Encryption, key storage, and secure asset handling live in `src/noteflow/infrastructure/security/`.
- **Python backend** (`src/noteflow/`) — gRPC server, domain logic, infrastructure adapters
- **Tauri + React desktop client** (`client/`) — Rust for IPC, React UI (Vite)
## Client Architecture (Tauri + React)
- React components are in `client/src/components/`, custom hooks in `client/src/hooks/`, and shared types in `client/src/types/`.
- API layer lives in `client/src/api/` with adapters (`tauri-adapter.ts`, `mock-adapter.ts`, `cached-adapter.ts`) and connection management.
- React contexts are in `client/src/contexts/` (e.g., `connection-context.tsx` for gRPC state).
- Tauri command calls are in `client/src/api/tauri-adapter.ts`; Rust command handlers live in `client/src-tauri/src/commands/`.
- Rust app entry points are `client/src-tauri/src/main.rs` and `client/src-tauri/src/lib.rs`; shared state lives in `client/src-tauri/src/state/`.
- Rust gRPC client is organized under `client/src-tauri/src/grpc/` with `client/` and `types/` subdirectories.
- Client tests are colocated with UI code (Vitest) and end-to-end tests live in `client/e2e/` (Playwright).
The gRPC schema is the shared contract between backend and client; keep proto changes in sync across Python, Rust, and TypeScript.
## Contracts & Sync Points (High Risk of Breakage)
- Source-of-truth API schema: `src/noteflow/grpc/proto/noteflow.proto`.
- Python gRPC stubs are checked in under `src/noteflow/grpc/proto/`; regenerate them when the proto changes.
- Rust/Tauri gRPC types are generated at build time by `client/src-tauri/build.rs`; keep Rust types aligned with proto changes.
- Frontend enums/DTOs in `client/src/types/` mirror proto enums and backend domain types; update together to avoid runtime mismatches.
- When adding or renaming RPCs, update server mixins, `src/noteflow/grpc/client.py`, Tauri command wrappers, and `client/src/api/tauri-adapter.ts`.
---
## Common Pitfalls & Change Checklist
## Quick Orientation
### Proto / API evolution
- Update `src/noteflow/grpc/proto/noteflow.proto` first; treat it as the schema source of truth.
- Regenerate Python stubs under `src/noteflow/grpc/proto/` and verify imports in `src/noteflow/grpc/`.
- Update gRPC server mixins in `src/noteflow/grpc/_mixins/` and service wiring in `src/noteflow/grpc/service.py`.
- Update the Python client wrapper in `src/noteflow/grpc/client.py`.
- Update Tauri/Rust command handlers in `client/src-tauri/src/commands/` and any Rust gRPC types.
- Update TypeScript adapters in `client/src/api/tauri-adapter.ts` and DTOs/enums in `client/src/types/` and `client/src/api/types/`.
- Add or adjust tests in both backend and client to cover payload changes.
| Entry Point | Description |
|-------------|-------------|
| `python -m noteflow.grpc.server` | Backend server (`src/noteflow/grpc/server/__main__.py`) |
| `cd client && npm run dev` | Web UI (Vite) |
| `cd client && npm run tauri dev` | Desktop Tauri dev (requires Rust toolchain) |
| `src/noteflow/grpc/proto/noteflow.proto` | Protobuf schema |
| `client/src/api/tauri-adapter.ts` | TypeScript → Rust IPC bridge |
| `client/src-tauri/src/commands/` | Rust Tauri command handlers |
### Database schema & migrations
- Update ORM models and add Alembic migrations under `src/noteflow/infrastructure/persistence/migrations/`.
- Review autogenerated migrations before applying; keep them deterministic and reversible.
- Update repository and UnitOfWork implementations when introducing new tables/relationships.
- Keep export/summarization converters in `src/noteflow/infrastructure/converters/` aligned with schema changes.
---
### Client sync points (Rust + TS)
- Tauri command signatures in `client/src-tauri/src/commands/` must match TypeScript calls in `client/src/api/tauri-adapter.ts`.
- Rust gRPC types are generated by `client/src-tauri/build.rs`; verify proto paths when moving files.
- Frontend enums in `client/src/types/` and `client/src/api/types/` mirror proto enums; update both sides together.
## Build and Development Commands
## Build, Test, and Development Commands
- Backend setup/run: `python -m pip install -e ".[dev]"`, `python -m noteflow.grpc.server`.
- Backend checks: `pytest`, `pytest -m "not integration"`, `ruff check .`, `ruff check --fix .`, `mypy src/noteflow`.
- Frontend dev/test: `cd client && npm run dev`, `npm run build`, `npm run test`, `npm run typecheck`.
- Frontend lint/format: `cd client && npm run lint`, `npm run lint:fix`, `npm run format`, `npm run format:check`.
- Rust checks: `cd client && npm run lint:rs` (clippy), `npm run format:rs` (rustfmt); install tools via `rustup component add rustfmt clippy`.
- Packaging: `python -m build`.
```bash
# Install (editable with dev dependencies)
python -m pip install -e ".[dev]"
## Makefile, Hygiene Output, and Code Quality Standards
- The Makefile is the source of truth for repo-wide code quality checks; use targets there before adding ad-hoc commands.
- Linter/type-checker outputs are written to `./.hygeine/` for review and troubleshooting.
- Keep Makefile targets flexible: they accept optional file or directory arguments in addition to repo-wide defaults.
- Never modify linter configurations (e.g., Ruff/Biome/ESLint/Pyrefly/Clippy/Prettier configs) unless the user explicitly requests it.
- Linting and type checking must stay strict: no relaxing rules, no suppressing warnings, no removing checks.
# Run gRPC server
python -m noteflow.grpc.server --help
## Coding Style & Naming Conventions
- Python 3.12 with 4-space indentation and 100-character line length (Ruff).
- Naming: `snake_case` for modules/functions, `PascalCase` for classes, `UPPER_SNAKE_CASE` for constants.
- Keep typing explicit and compatible with strict `mypy`; generated `*_pb2.py` files are excluded from lint.
- Frontend formatting uses Prettier (single quotes, 100 char width); linting uses Biome.
- Rust formatting uses `rustfmt`; linting uses `clippy` via the client scripts.
# Run Tauri + React client UI
cd client && npm install && npm run dev
cd client && npm run tauri dev # Desktop (requires Rust)
## Type Safety Rules (Strict)
- `Any` is forbidden in type annotations, including indirect use via `typing.Any`.
- Ignore-based suppression is forbidden (`# type: ignore`, `# pyright: ignore`, `# noqa: ANN`, or similar).
- Use precise types, casts, and guards instead of weakening types or silencing errors.
# Tests
pytest # Full suite
pytest -m "not integration" # Skip external-service tests
pytest tests/domain/ # Run specific test directory
pytest -k "test_segment" # Run by pattern
## Testing Guidelines
- Pytest with asyncio auto mode; test files `test_*.py`, functions `test_*`.
- Use markers: `@pytest.mark.slow` for model-loading tests and `@pytest.mark.integration` for external services.
- Integration tests may require PostgreSQL via `NOTEFLOW_DATABASE_URL`.
- React unit tests use Vitest; e2e uses Playwright from `client/e2e/`.
- Keep proto/type changes covered with at least one backend test and one client-facing test.
# Docker (hot-reload enabled)
docker compose up -d postgres # PostgreSQL with pgvector
python scripts/dev_watch_server.py # Auto-reload server
```
### Forbidden Docker Operations (without explicit permission)
- `docker compose build` / `up` / `down` / `restart`
- `docker stop` / `docker kill`
- Any command that would interrupt the hot-reload server
---
## Quality Commands (Makefile)
**Always use Makefile targets instead of running tools directly.**
### Primary Quality Commands
```bash
make quality # Run ALL quality checks (TS + Rust + Python)
make quality-py # Python: lint + type-check + test-quality
make quality-ts # TypeScript: type-check + lint + test-quality
make quality-rs # Rust: clippy + lint
```
### Python Quality
```bash
make lint-py # Basedpyright lint → .hygeine/basedpyright.lint.json
make type-check-py # Basedpyright strict mode
make test-quality-py # pytest tests/quality/
make lint-fix-py # Auto-fix Ruff + Sourcery issues
```
### TypeScript Quality
```bash
make type-check # tsc --noEmit
make lint # Biome linter → .hygeine/biome.json
make lint-fix # Auto-fix Biome issues
make test-quality # Vitest quality tests
```
### Rust Quality
```bash
make clippy # Clippy linter → .hygeine/clippy.json
make lint-rs # Code quality script → .hygeine/rust_code_quality.txt
make fmt-rs # Format with rustfmt
make fmt-check-rs # Check rustfmt formatting
```
### Formatting
```bash
make fmt # Format all code (Biome + rustfmt)
make fmt-check # Check all formatting
```
### E2E Tests
```bash
make e2e # Playwright tests (requires frontend on :5173)
make e2e-ui # Playwright tests with UI mode
make e2e-grpc # Rust gRPC integration tests
```
---
## Architecture
```
src/noteflow/
├── domain/ # Entities, ports, value objects
│ ├── entities/ # Meeting, Segment, Summary, Annotation, NamedEntity, Integration, Project, Processing, SummarizationTemplate
│ ├── identity/ # User, Workspace, WorkspaceMembership, roles, context
│ ├── auth/ # OIDC discovery, claims, constants
│ ├── ports/ # Repository protocols
│ │ ├── repositories/
│ │ │ ├── transcript.py # MeetingRepository, SegmentRepository, SummaryRepository
│ │ │ ├── asset.py # AssetRepository
│ │ │ ├── background.py # DiarizationJobRepository
│ │ │ ├── external/ # WebhookRepository, IntegrationRepository, EntityRepository, UsageRepository
│ │ │ └── identity/ # UserRepository, WorkspaceRepository, ProjectRepository, MembershipRepository, SummarizationTemplateRepository
│ │ ├── unit_of_work.py # UnitOfWork protocol (supports_* capability checks)
│ │ ├── async_context.py # Async context utilities
│ │ ├── diarization.py # DiarizationEngine protocol
│ │ ├── ner.py # NEREngine protocol
│ │ └── calendar.py # CalendarProvider protocol
│ ├── webhooks/ # WebhookEventType, WebhookConfig, WebhookDelivery, payloads
│ ├── triggers/ # Trigger, TriggerAction, TriggerSignal, TriggerProvider
│ ├── summarization/# SummarizationProvider protocol
│ ├── rules/ # Business rules registry, models, builtin rules
│ ├── settings/ # Domain settings base
│ ├── constants/ # Field definitions, placeholders
│ ├── utils/ # time.py (utc_now), validation.py
│ ├── errors.py # Domain-specific exceptions
│ └── value_objects.py
├── application/ # Use-cases/services
│ ├── services/
│ │ ├── meeting/ # MeetingService (CRUD, segments, annotations, summaries, state)
│ │ ├── identity/ # IdentityService (context, workspace, defaults)
│ │ ├── calendar/ # CalendarService (connection, events, oauth, sync)
│ │ ├── summarization/ # SummarizationService, TemplateService, ConsentManager
│ │ ├── project_service/ # CRUD, members, roles, rules, active project
│ │ ├── recovery/ # RecoveryService (meeting, job, audio recovery)
│ │ ├── webhook_service.py
│ │ ├── ner_service.py
│ │ ├── export_service.py
│ │ ├── trigger_service.py
│ │ ├── retention_service.py
│ │ ├── auth_service.py
│ │ ├── auth_workflows.py
│ │ ├── auth_integration_manager.py
│ │ ├── auth_token_exchanger.py
│ │ ├── auth_types.py
│ │ ├── auth_constants.py
│ │ └── protocols.py
│ └── observability/ # Observability ports
├── infrastructure/ # Implementations
│ ├── audio/ # sounddevice capture, ring buffer, VU levels, playback, writer, reader
│ ├── asr/ # faster-whisper engine, VAD segmenter, streaming, DTOs
│ ├── auth/ # OIDC discovery, registry, presets
│ ├── diarization/ # Session, assigner, engine (streaming: diart, offline: pyannote)
│ ├── summarization/# CloudProvider, OllamaProvider, MockProvider, parsing, citation verifier, template renderer
│ ├── triggers/ # Calendar, audio_activity, foreground_app providers
│ ├── persistence/ # SQLAlchemy + asyncpg + pgvector
│ │ ├── database.py # create_async_engine, create_async_session_factory
│ │ ├── models/ # ORM models (core/, identity/, integrations/, entities/, observability/, organization/)
│ │ ├── repositories/ # Repository implementations
│ │ │ ├── meeting_repo.py
│ │ │ ├── segment_repo.py
│ │ │ ├── summary_repo.py
│ │ │ ├── annotation_repo.py
│ │ │ ├── entity_repo.py
│ │ │ ├── webhook_repo.py
│ │ │ ├── preferences_repo.py
│ │ │ ├── asset_repo.py
│ │ │ ├── summarization_template_repo.py
│ │ │ ├── diarization_job/
│ │ │ ├── integration/
│ │ │ ├── identity/
│ │ │ ├── usage_event/
│ │ │ └── _base/ # BaseRepository with _execute_scalar, _execute_scalars, _add_and_flush
│ │ ├── unit_of_work/
│ │ ├── memory/ # In-memory implementations
│ │ └── migrations/ # Alembic migrations
│ ├── security/ # Keystore (keyring + AES-GCM), protocols, crypto/
│ ├── crypto/ # Cryptographic utilities
│ ├── export/ # Markdown, HTML, PDF (WeasyPrint), formatting helpers
│ ├── webhooks/ # WebhookExecutor (delivery, signing, metrics)
│ ├── converters/ # ORM ↔ domain (orm, webhook, ner, calendar, integration, asr)
│ ├── calendar/ # Google/Outlook adapters, OAuth flow
│ ├── ner/ # spaCy engine
│ ├── observability/# OpenTelemetry tracing, usage tracking
│ ├── metrics/ # Metric collection
│ ├── logging/ # Log buffer utilities
│ └── platform/ # Platform-specific code
├── grpc/ # gRPC server and client
│ ├── server/ # Server entry point (__main__.py, __init__.py)
│ ├── service.py # NoteFlowServicer (composes mixins)
│ ├── client.py # Python gRPC client wrapper
│ ├── _mixins/ # Modular RPC implementations
│ │ ├── streaming/ # ASR streaming (package)
│ │ │ ├── _mixin.py # Main StreamingMixin class
│ │ │ ├── _session.py # Session management
│ │ │ ├── _asr.py # ASR processing
│ │ │ ├── _processing/ # Audio processing pipeline
│ │ │ │ ├── _audio_ops.py
│ │ │ │ ├── _chunk_tracking.py
│ │ │ │ ├── _congestion.py
│ │ │ │ ├── _constants.py
│ │ │ │ ├── _types.py
│ │ │ │ └── _vad_processing.py
│ │ │ ├── _partials.py # Partial transcript handling
│ │ │ ├── _cleanup.py # Resource cleanup
│ │ │ └── _types.py # Type definitions
│ │ ├── diarization/ # Speaker diarization (package)
│ │ │ ├── _mixin.py # Main DiarizationMixin class
│ │ │ ├── _jobs.py # Background job management
│ │ │ ├── _refinement.py# Offline refinement
│ │ │ ├── _streaming.py # Real-time diarization
│ │ │ ├── _speaker.py # Speaker assignment
│ │ │ ├── _status.py # Job status tracking
│ │ │ └── _types.py # Type definitions
│ │ ├── meeting/ # Meeting lifecycle (package)
│ │ │ ├── meeting_mixin.py
│ │ │ ├── _project_scope.py
│ │ │ └── _stop_ops.py
│ │ ├── summarization.py # Summary generation
│ │ ├── annotation.py # Segment annotations CRUD
│ │ ├── export.py # Document export
│ │ ├── entities.py # Named entity extraction
│ │ ├── calendar.py # Calendar sync
│ │ ├── webhooks.py # Webhook management
│ │ ├── preferences.py # User preferences
│ │ ├── observability.py # Usage tracking, metrics
│ │ ├── sync.py # State synchronization
│ │ ├── identity.py # Identity operations
│ │ ├── projects.py # Project operations
│ │ ├── oidc.py # OIDC operations
│ │ ├── converters.py # Protobuf ↔ domain converters
│ │ ├── errors.py # gRPC error helpers
│ │ ├── protocols.py # ServicerHost protocol
│ │ └── _audio_helpers.py # Audio utilities
│ ├── _client_mixins/ # Python client mixins
│ │ ├── streaming.py
│ │ ├── meeting.py
│ │ ├── diarization.py
│ │ ├── export.py
│ │ ├── annotation.py
│ │ ├── converters.py
│ │ └── protocols.py
│ ├── interceptors/ # gRPC server interceptors
│ │ └── identity.py # Identity context propagation
│ └── proto/ # Protobuf definitions and generated stubs
├── cli/ # CLI tools
│ ├── __main__.py # CLI entry point
│ ├── retention.py # Retention management
│ ├── constants.py # CLI constants
│ └── models/ # Model commands (package)
│ ├── _download.py
│ ├── _parser.py
│ ├── _registry.py
│ ├── _status.py
│ └── _types.py
└── config/ # Configuration
├── settings/ # Pydantic settings (_base, _features, _server, _security, etc.)
├── constants.py # Application constants
└── feature_flags.py
```
### Client Architecture (`client/src/`)
```
client/src/
├── api/ # API layer with adapters
│ ├── tauri-adapter.ts # Main Tauri IPC adapter
│ ├── mock-adapter.ts # Mock adapter for testing
│ ├── cached-adapter.ts # Caching layer
│ ├── connection-state.ts # Connection state machine
│ ├── reconnection.ts # Auto-reconnection logic
│ ├── interface.ts # Adapter interface definition
│ └── types/ # API type definitions
│ ├── core.ts
│ ├── meetings.ts
│ ├── segments.ts
│ ├── diarization.ts
│ ├── annotations.ts
│ ├── templates.ts
│ ├── webhooks.ts
│ ├── calendar.ts
│ ├── entities.ts
│ ├── preferences.ts
│ ├── observability.ts
│ ├── triggers.ts
│ ├── audio.ts
│ ├── playback.ts
│ ├── apps.ts
│ └── readonly.ts
├── hooks/ # Custom React hooks
│ ├── use-diarization.ts
│ ├── use-cloud-consent.ts
│ ├── use-webhooks.ts
│ ├── use-oauth-flow.ts
│ ├── use-calendar-sync.ts
│ ├── use-entity-extraction.ts
│ ├── use-audio-devices.ts
│ ├── use-project.ts
│ ├── use-project-members.ts
│ ├── use-oidc-providers.ts
│ ├── use-auth-flow.ts
│ ├── use-integration-sync.ts
│ ├── use-integration-validation.ts
│ ├── use-secure-integration-secrets.ts
│ ├── use-guarded-mutation.ts
│ ├── use-panel-preferences.ts
│ ├── use-preferences-sync.ts
│ ├── use-meeting-reminders.ts
│ ├── use-recording-app-policy.ts
│ ├── use-post-processing.ts
│ ├── use-toast.ts
│ ├── use-mobile.tsx
│ └── post-processing/
├── contexts/ # React contexts
│ ├── connection-context.tsx # gRPC connection context
│ ├── connection-state.ts
│ ├── workspace-context.tsx # Workspace context
│ ├── workspace-state.ts
│ ├── project-context.tsx # Project context
│ └── project-state.ts
├── components/ # React components
│ ├── ui/ # Reusable UI components (shadcn/ui)
│ ├── recording/ # Recording-specific components
│ ├── settings/ # Settings panel components
│ ├── analytics/ # Analytics visualizations
│ ├── projects/ # Project components
│ ├── icons/ # Icon components
│ └── ... # Top-level components
├── pages/ # Route pages
│ ├── Home.tsx
│ ├── Meetings.tsx
│ ├── MeetingDetail.tsx
│ ├── Recording.tsx
│ ├── Projects.tsx
│ ├── ProjectSettings.tsx
│ ├── Settings.tsx
│ ├── settings/ # Settings sub-pages
│ ├── People.tsx
│ ├── Tasks.tsx
│ ├── Analytics.tsx
│ ├── Index.tsx
│ └── NotFound.tsx
├── lib/ # Utilities
│ ├── config/ # Configuration (server, defaults, app-config, provider-endpoints)
│ ├── cache/ # Client-side caching (meeting-cache)
│ ├── format.ts
│ ├── utils.ts
│ ├── time.ts
│ ├── crypto.ts
│ ├── cva.ts
│ ├── styles.ts
│ ├── tauri-events.ts
│ ├── preferences.ts
│ ├── preferences-sync.ts
│ ├── entity-store.ts
│ ├── speaker-utils.ts
│ ├── ai-providers.ts
│ ├── ai-models.ts
│ ├── integration-utils.ts
│ ├── default-integrations.ts
│ ├── status-constants.ts
│ ├── timing-constants.ts
│ ├── object-utils.ts
│ ├── error-reporting.ts
│ ├── client-logs.ts
│ ├── client-log-events.ts
│ ├── log-groups.ts
│ ├── log-converters.ts
│ ├── log-messages.ts
│ ├── log-summarizer.ts
│ └── log-group-summarizer.ts
├── types/ # Shared TypeScript types
└── test/ # Test utilities
```
### Rust/Tauri Backend (`client/src-tauri/src/`)
```
src-tauri/src/
├── commands/ # Tauri IPC command handlers
│ ├── recording/ # capture.rs, device.rs, audio.rs, app_policy.rs
│ ├── playback/ # audio.rs, events.rs, tick.rs
│ ├── triggers/ # audio.rs, polling.rs
│ ├── meeting.rs
│ ├── diarization.rs
│ ├── annotation.rs
│ ├── export.rs
│ ├── summary.rs
│ ├── entities.rs
│ ├── calendar.rs
│ ├── webhooks.rs
│ ├── preferences.rs
│ ├── observability.rs
│ ├── sync.rs
│ ├── projects.rs
│ ├── identity.rs
│ ├── oidc.rs
│ ├── connection.rs
│ ├── audio.rs
│ ├── audio_testing.rs
│ ├── apps.rs
│ ├── apps_platform.rs
│ ├── diagnostics.rs
│ ├── shell.rs
│ └── testing.rs
├── grpc/ # gRPC client
│ ├── client/ # Client implementations by domain
│ │ ├── core.rs
│ │ ├── meetings.rs
│ │ ├── annotations.rs
│ │ ├── diarization.rs
│ │ ├── identity.rs
│ │ ├── projects.rs
│ │ ├── preferences.rs
│ │ ├── calendar.rs
│ │ ├── webhooks.rs
│ │ ├── observability.rs
│ │ ├── oidc.rs
│ │ ├── sync.rs
│ │ └── converters.rs
│ ├── types/ # Rust type definitions
│ │ ├── core.rs
│ │ ├── enums.rs
│ │ ├── identity.rs
│ │ ├── projects.rs
│ │ ├── preferences.rs
│ │ ├── calendar.rs
│ │ ├── webhooks.rs
│ │ ├── observability.rs
│ │ ├── oidc.rs
│ │ ├── sync.rs
│ │ └── results.rs
│ ├── streaming/ # Streaming converters
│ └── noteflow.rs # Generated protobuf types
├── state/ # Runtime state management
│ ├── app_state.rs
│ ├── preferences.rs
│ ├── playback.rs
│ └── types.rs
├── audio/ # Audio capture and playback
├── cache/ # Memory caching
├── crypto/ # Cryptographic operations
├── events/ # Tauri event emission
├── triggers/ # Trigger detection
├── error/ # Error types
├── identity/ # Identity management
├── config.rs # Configuration
├── constants.rs # Constants
├── helpers.rs # Helper functions
├── oauth_loopback.rs # OAuth callback server
├── main.rs # Application entry point
└── lib.rs # Library exports
```
---
## Database
PostgreSQL with pgvector extension. Async SQLAlchemy with asyncpg driver.
```bash
# Alembic migrations
alembic upgrade head
alembic revision --autogenerate -m "description"
```
Connection via `NOTEFLOW_DATABASE_URL` env var or settings.
### ORM Models (`persistence/models/`)
| Directory | Models |
|-----------|--------|
| `core/` | MeetingModel, SegmentModel, SummaryModel, AnnotationModel, DiarizationJobModel |
| `identity/` | UserModel, WorkspaceModel, WorkspaceMembershipModel, ProjectModel, ProjectMembershipModel, SettingsModel |
| `integrations/` | IntegrationModel, IntegrationSecretModel, CalendarEventModel, MeetingCalendarLinkModel, WebhookConfigModel, WebhookDeliveryModel |
| `entities/` | NamedEntityModel, SpeakerModel |
| `observability/` | UsageEventModel |
| `organization/` | SummarizationTemplateModel, TaskModel, TagModel |
---
## Testing Conventions
- Test files: `test_*.py`, functions: `test_*`
- Markers: `@pytest.mark.slow` (model loading), `@pytest.mark.integration` (external services)
- Integration tests use testcontainers for PostgreSQL
- Asyncio auto-mode enabled
- React unit tests use Vitest; e2e tests use Playwright in `client/e2e/`
### Test Quality Gates (`tests/quality/`)
**After any non-trivial changes**, run:
```bash
pytest tests/quality/
```
This suite enforces:
| Check | Description |
|-------|-------------|
| `test_test_smells.py` | No assertion roulette, no conditional test logic, no loops in tests |
| `test_magic_values.py` | No magic numbers in assignments |
| `test_code_smells.py` | Code quality checks |
| `test_duplicate_code.py` | No duplicate code patterns |
| `test_stale_code.py` | No stale/dead code |
| `test_decentralized_helpers.py` | Helpers consolidated properly |
| `test_unnecessary_wrappers.py` | No unnecessary wrapper functions |
| `test_baseline_self.py` | Baseline validation self-checks |
### Global Fixtures (`tests/conftest.py`)
**Do not redefine these fixtures:**
| Fixture | Description |
|---------|-------------|
| `reset_context_vars` | Reset logging context variables |
| `mock_uow` | Mock Unit of Work |
| `crypto` | Crypto utilities |
| `meetings_dir` | Temporary meetings directory |
| `webhook_config` | Single-event webhook config |
| `webhook_config_all_events` | All-events webhook config |
| `sample_datetime` | Sample datetime |
| `calendar_settings` | Calendar settings |
| `meeting_id` | Sample meeting ID |
| `sample_meeting` | Sample Meeting entity |
| `recording_meeting` | Recording-state Meeting |
| `sample_rate` | Audio sample rate |
| `mock_grpc_context` | Mock gRPC context |
| `mockasr_engine` | Mock ASR engine |
| `mock_optional_extras` | Mock optional extras |
| `mock_oauth_manager` | Mock OAuth manager |
| `memory_servicer` | In-memory servicer |
| `approx_float` | Approximate float comparison |
| `approx_sequence` | Approximate sequence comparison |
---
## Code Style
### Python
- Python 3.12+, 100-char line length
- 4-space indentation
- Naming: `snake_case` modules/functions, `PascalCase` classes, `UPPER_SNAKE_CASE` constants
- Strict basedpyright (0 errors, 0 warnings, 0 notes required)
- Ruff for linting (E, W, F, I, B, C4, UP, SIM, RUF)
- Module soft limit 500 LoC, hard limit 750 LoC
- Generated `*_pb2.py`, `*_pb2_grpc.py` excluded from lint
### TypeScript
- Biome for linting and formatting
- Single quotes, 100 char width
- Strict TypeScript (noEmit checks)
### Rust
- `rustfmt` for formatting
- `clippy` for linting (warnings treated as errors)
---
## Type Safety (Zero Tolerance)
### Forbidden Patterns (Python)
| Pattern | Why Blocked | Alternative |
|---------|-------------|-------------|
| `# type: ignore` | Bypasses type safety | Fix the actual type error |
| `# pyright: ignore` | Bypasses type safety | Fix the actual type error |
| `Any` type annotations | Creates type safety holes | Use `Protocol`, `TypeVar`, `TypedDict`, or specific types |
| Magic numbers | Hidden intent | Define `typing.Final` constants |
| Loops in tests | Non-deterministic | Use `@pytest.mark.parametrize` |
| Conditionals in tests | Non-deterministic | Use `@pytest.mark.parametrize` |
| Multiple assertions without messages | Hard to debug | Add assertion messages |
### Type Resolution Hierarchy
When facing dynamic types:
1. **`Protocol`** — For duck typing (structural subtyping)
2. **`TypeVar`** — For generics
3. **`TypedDict`** — For structured dictionaries
4. **`cast()`** — Last resort (with comment explaining why)
### Validation Requirements
After any code changes:
```bash
source .venv/bin/activate && basedpyright src/noteflow/
```
**Expected output:** `0 errors, 0 warnings, 0 notes`
---
## Protected Files (Require Explicit Permission)
| File/Directory | What's Blocked |
|----------------|----------------|
| `Makefile` | All modifications |
| `tests/quality/` (except `baselines.json`) | All modifications |
| `pyproject.toml`, `ruff.toml`, `pyrightconfig.json` | All edits |
| `biome.json`, `tsconfig.json`, `.eslintrc*` | All edits |
| `.rustfmt.toml`, `.clippy.toml` | All edits |
### Quality Gate Requirement
Before completing any code changes:
```bash
make quality
```
All quality checks must pass.
### Policy: No Ignoring Pre-existing Issues
If you encounter lint errors, type errors, or test failures—**even if they existed before your changes**—you must either:
1. Fix immediately (for simple issues)
2. Add to todo list (for complex issues)
3. Launch a subagent to fix (for parallelizable work)
---
## Proto/gRPC
Proto definitions: `src/noteflow/grpc/proto/noteflow.proto`
Regenerate after proto changes:
```bash
python -m grpc_tools.protoc -I src/noteflow/grpc/proto \
--python_out=src/noteflow/grpc/proto \
--grpc_python_out=src/noteflow/grpc/proto \
src/noteflow/grpc/proto/noteflow.proto
```
Then run stub patching:
```bash
python scripts/patch_grpc_stubs.py
```
### Sync Points (High Risk of Breakage)
When changing proto:
1. **Python stubs** — Regenerate `*_pb2.py`, `*_pb2_grpc.py`
2. **Server mixins** — Update `src/noteflow/grpc/_mixins/`
3. **Python client** — Update `src/noteflow/grpc/client.py`
4. **Rust types** — Generated by `client/src-tauri/build.rs`
5. **Rust commands** — Update `client/src-tauri/src/commands/`
6. **TypeScript types** — Update `client/src/api/types/`
7. **TypeScript adapter** — Update `client/src/api/tauri-adapter.ts`
---
## Key Subsystems
### Speaker Diarization
- **Streaming**: diart for real-time speaker detection
- **Offline**: pyannote.audio for post-meeting refinement
- **gRPC**: `RefineSpeakerDiarization`, `GetDiarizationJobStatus`, `RenameSpeaker`
### Summarization
- **Providers**: CloudProvider (Anthropic/OpenAI), OllamaProvider (local), MockProvider (testing)
- **Templates**: Configurable tone, format, verbosity
- **Citation verification**: Links summary claims to transcript evidence
- **Consent**: Cloud providers require explicit user consent
### Export
- **Formats**: Markdown, HTML, PDF (via WeasyPrint)
- **Content**: Transcript with timestamps, speaker labels, summary
### Named Entity Recognition (NER)
- **Engine**: spaCy with transformer models
- **Categories**: person, company, product, technical, acronym, location, date, other
- **Segment tracking**: Entities link to source `segment_ids`
### Trigger Detection
- **Signals**: Calendar proximity, audio activity, foreground app
- **Actions**: IGNORE, NOTIFY, AUTO_START
### Webhooks
- **Events**: `meeting.completed`, `summary.generated`, `recording.started`, `recording.stopped`
- **Delivery**: Exponential backoff retries
- **Security**: HMAC-SHA256 signing
### Authentication
- **OIDC**: OpenID Connect with discovery
- **Providers**: Configurable via OIDC registry
---
## Feature Flags
| Flag | Default | Controls |
|------|---------|----------|
| `NOTEFLOW_FEATURE_TEMPLATES_ENABLED` | `true` | AI summarization templates |
| `NOTEFLOW_FEATURE_PDF_EXPORT_ENABLED` | `true` | PDF export format |
| `NOTEFLOW_FEATURE_NER_ENABLED` | `false` | Named entity extraction |
| `NOTEFLOW_FEATURE_CALENDAR_ENABLED` | `false` | Calendar sync |
| `NOTEFLOW_FEATURE_WEBHOOKS_ENABLED` | `true` | Webhook notifications |
Access via `get_feature_flags().<flag_name>` or `get_settings().feature_flags.<flag_name>`.
---
## Common Pitfalls Checklist
### When Adding New Features
- [ ] Update proto schema first (if gRPC involved)
- [ ] Regenerate Python stubs
- [ ] Run `scripts/patch_grpc_stubs.py`
- [ ] Implement server mixin
- [ ] Update Python client wrapper
- [ ] Update Rust commands
- [ ] Update TypeScript adapter
- [ ] Update TypeScript types
- [ ] Add tests (both backend and client)
- [ ] Run `make quality`
### When Changing Database Schema
- [ ] Update ORM models in `persistence/models/`
- [ ] Create Alembic migration
- [ ] Update repository implementation
- [ ] Update UnitOfWork if needed
- [ ] Update converters in `infrastructure/converters/`
### When Modifying Existing Code
- [ ] Search for all usages first
- [ ] Update all call sites
- [ ] Run `make quality`
- [ ] Run relevant tests
---
## Known Issues & Technical Debt
See `docs/triage.md` for tracked technical debt.
See `docs/sprints/` for feature implementation plans.
---
## Configuration & Security
- Runtime settings from `.env` or `NOTEFLOW_` environment variables
- Settings module: `src/noteflow/config/settings/`
- Keep secrets and credentials out of the repo
- Use `.env` for local development configuration
---
## Commit & Pull Request Guidelines
- Use Conventional Commits (e.g., `feat:`, `fix:`, `chore:`) and include a concise scope when helpful.
- PRs should describe the change, link related issues/specs, note DB or proto changes, and include UI screenshots when any client UI changes.
## Configuration & Security Notes
- Runtime settings come from `.env` or `NOTEFLOW_` environment variables (see `src/noteflow/config/settings.py`).
- Keep secrets and local credentials out of the repo; use `.env` and local config instead.
- Use Conventional Commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`, `test:`
- Include concise scope when helpful: `feat(grpc): add streaming backpressure`
- PRs should:
- Describe the change clearly
- Link related issues/specs
- Note any DB or proto changes
- Include UI screenshots for client changes
- Pass all quality checks (`make quality`)

View File

@@ -168,6 +168,7 @@ src/noteflow/
├── infrastructure/ # Implementations
│ ├── audio/ # sounddevice capture, ring buffer, VU levels, playback, writer, reader
│ ├── asr/ # faster-whisper engine, VAD segmenter, streaming, DTOs
│ ├── auth/ # OIDC discovery, registry, presets
│ ├── diarization/ # Session, assigner, engine (streaming: diart, offline: pyannote)
│ ├── summarization/# CloudProvider, OllamaProvider, MockProvider, parsing, citation verifier, template renderer
│ ├── triggers/ # Calendar, audio_activity, foreground_app providers
@@ -215,9 +216,15 @@ src/noteflow/
│ ├── _mixins/ # Server-side gRPC mixins (see below)
│ └── _client_mixins/# Client-side gRPC mixins
├── cli/ # CLI tools
│ ├── __main__.py # CLI entry point
│ ├── retention.py # Retention management
│ ├── models/ # Model commands
│ └── constants.py
│ ├── constants.py # CLI constants
│ └── models/ # Model commands (package)
│ ├── _download.py
│ ├── _parser.py
│ ├── _registry.py
│ ├── _status.py
│ └── _types.py
└── config/ # Pydantic settings (NOTEFLOW_ env vars)
├── settings/ # _main.py, _features.py, _triggers.py, _calendar.py, _loaders.py
└── constants/