---
title: NoteService
summary: API reference for NoteService (SAIF.Services.Agencies.Notes).
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-09-24
library: SAIF.Services
reference_type: package
---

# NoteService

Implements `INoteService` for agency notepad entries, coordinating retrieval, filtering, adding, appending, editing, and deleting notes attached to agencies (`AgencyNote`/`Notepad`), returning outcomes and errors through a caller-supplied `IMessageContainer` rather than throwing. It depends on `IUnitOfWork` for repository access and transactions, `IValidationService` for FluentValidation-based edit validation, `IUserProfileService` for current-user identity and role checks, and `IWorkCalendarService` to compute the "two work days ago" cutoff that gates edit/delete/append permissions. Its static constructor registers AutoMapper maps for `AgencyNote`/`Notepad`→`Note` and reuses `AgenciesMappingHelper.CreateAgencyMap()`.

## Purpose
- Retrieves a single note or all notes for an agency, filtering out confidential notes unless the current user is authorized to see them.
- Adds a new note (as the current user or, via `AddNoteBySystem`, attributed to `"SYSTEM"`), enforcing edit authorization (for the user-attributed path) and validation.
- Appends text to an existing note (only allowed once the note is older than two work days) or edits a note's text directly (only allowed within two work days of creation), enforcing optimistic-concurrency checks and optional producer association.
- Deletes a note, allowing unrestricted deletion for super-delete users and time-limited deletion (within two work days) for regular edit users.
- Reports whether the current user can add notes or see confidential notes, and returns the available note categories.

## Context
- Namespace: `SAIF.Services.Agencies.Notes`
- Assembly/package: `SAIF.Services` (packaged inside the `SAIF.SAIFCode.Core` NuGet package)

## Public members
| Member | Signature | Purpose |
| --- | --- | --- |
| NoteService(...) | `public NoteService(IUnitOfWork unitOfWork, IValidationService validationService, IUserProfileService userProfileService, IWorkCalendarService workCalendarService)` | Validates all four collaborators are non-null and stores them for use by every other member. |
| CanUserAddNote | `public bool CanUserAddNote { get; }` | Returns whether the current user is authorized to add notes (same check used to gate `AddNote`/`AppendNote`/`EditNote`). |
| CanUserSeeConfidentialNotes | `public bool CanUserSeeConfidentialNotes { get; }` | Returns whether the current user holds the confidential-notes role. |
| GetNotes(agencyId, criteria) | `public IEnumerable<Note> GetNotes(long agencyId, NoteFilterCriteria criteria)` | Returns the agency's notes narrowed by `criteria` via the shared `Filter` extension. |
| GetNotes(agencyId) | `public IEnumerable<Note> GetNotes(long agencyId)` | Returns all visible notes for the agency, mapped to `Note` contracts, each flagged `IsProducerNote` when a producer is associated. |
| GetNote | `public Note GetNote(long noteId)` | Returns the mapped `Note` for `noteId`, or `null` if not found or the caller lacks confidential-note visibility. |
| GetCategories | `public IEnumerable<Category> GetCategories()` | Returns the note categories scoped to the agency-note context (`NotepadContext.AgencyNoteContextCode`). |
| AddNote | `public long? AddNote(NoteEdit noteEdit, IMessageContainer messages)` | Adds a new note attributed to the current user if authorized and valid, committing within a transaction; returns the new note ID, or `null` (with messages populated) on authorization/validation failure. |
| AddNoteBySystem | `public long? AddNoteBySystem(NoteEdit noteEdit, IMessageContainer messages)` | Adds a new note attributed to `"SYSTEM"` without the edit-authorization check (validation still applies), committing within a transaction; returns the new note ID, or `null` (with messages populated) on validation failure. |
| DeleteExpiredNotes | `public bool DeleteExpiredNotes()` | Always throws `NotImplementedException`; this capability is not implemented for agency notes. |
| DeleteNote | `public bool DeleteNote(long noteId, IMessageContainer messages)` | Deletes the note without considering concurrency if found, and if the caller is a super-delete user or the note was created within the last two work days; returns whether the delete succeeded. |
| EditNote | `public bool EditNote(long noteId, NoteEdit noteEdit, IMessageContainer messages)` | Edits an existing note's agency/producer, confidentiality, type, and text (with an "Updated <date> by <user>" suffix) if the caller is authorized, there is no intervening update, the edit window has not passed when text changed, and validation succeeds; returns whether the edit succeeded. |
| AppendNote | `public bool AppendNote(long noteId, NoteEdit noteEdit, IMessageContainer messages)` | Appends new text (with an "Added <date> by <user>" prefix) to an existing note if the caller is authorized, the note is older than two work days, there is no intervening update, and the appended text validates; returns whether the append succeeded. |
| AppendPrefixTextLength | `public int AppendPrefixTextLength { get; }` | Returns the character length of the "Added <date> by <user>" prefix that will be inserted when appending. |
| EditSuffixTextLength | `public int EditSuffixTextLength { get; }` | Returns the character length of the "Updated <date> by <user>" suffix appended when a note's text is edited. |

## Behavioral notes
- `AddNote`, `AddNoteBySystem`, `AppendNote`, `EditNote`, and `DeleteNote` each wrap their write in `unitOfWork.Begin()`/`Commit()`; none explicitly call `Rollback()` on failure paths, relying instead on returning early before `Commit()` is reached*.
- Edit authorization (`IsEditUser`) is cached per-instance in the `isUserAuthorizedToEditNotes` nullable field after the first check, so subsequent calls on the same service instance reuse the cached result*.
- The optimistic-concurrency check compares `noteEdit.UpdateDate` to the stored `Note.UpdateDate` and rejects the write with "Error: Another user updated this note." on mismatch.
- `EditNote`/`AppendNote`/`AddNote` all route note text through `.ReplaceUnicodeCharactersWithAscii()` before persisting, normalizing non-ASCII characters.
- `DeleteExpiredNotes` is unimplemented (`throw new NotImplementedException()`), so callers must not invoke it in current builds.
- A sibling type, `MoreReadableNoteService`, implements the same agency-note operations using thrown `NoteServiceException`s instead of an `IMessageContainer` result pattern*.

> **Note:** Statements marked with * were inferred from code structure, naming conventions, or
> contextual evidence where direct confirmation was not available in source artifacts. Statements
> marked with ** could not be confirmed; treat as unknown until verified.

## Sources
- Services/SAIF.Services/Agencies/Notes/NoteService.cs
