This documentation is intended for contributors working on openvino-notes.
The repository has a meaningful CI/build setup and an active Android application with local storage, editor flows, and on-device text AI. The goal of these documents is to help contributors understand the project quickly and reproduce the same checks that gate pull requests and main.
What is already in place:
- a four-module Android build
- reusable GitHub Actions workflows
- shared formatting, lint, and coverage policy
- on-device OpenVINO GenAI text assistance for summary, tags, and rewrite
What is intentionally still limited:
- image tagging is not implemented in the text LLM path
- model and OpenVINO runtime bundles are large and are consumed from release assets instead of being stored in git
- full model-behavior validation requires an Android target matching the selected OpenVINO runtime prebuild ABI;
arm64-v8ais the default, andx86_64is selected with-PopenvinoAndroidAbi=x86_64
- Application code:
app,domain,data,ai - Automation and CI:
.github
This documentation describes the Domain layer of the openvino-notes application. It is intended for contributors working on business logic, AI integration, and unit testing.
The Domain layer is the central part of the architecture, defining business rules for notes and folders, AI operations, and repository contracts. It is independent of storage, UI, and AI implementation details.
- Maintain business logic separately from UI, storage, and AI.
- Define domain entities, repository contracts, and use cases.
- Provide testable interfaces for both normal and AI-enhanced operations.
The Domain layer contains:
- Domain models (
Note,NoteFolder) - Repository interfaces (
NotesRepository,NoteFolderRepository) - Use cases for notes and folders
- AI service interface (
NoteAiService) - AI-related use cases (
SuggestSummaryUseCase,ApplyTagsUseCase, etc.)
The Domain layer does not contain:
- UI elements or ViewModels
- Android-specific code
- Implementation details of repositories or AI
- OpenVINO or network code
domain/ ├─ ai/ │ └─ NoteAiService.kt ├─ aiusecase/ │ ├─ ApplySummaryUseCase.kt │ ├─ ApplyTagsUseCase.kt │ ├─ SuggestSummaryUseCase.kt │ └─ SuggestTagsUseCase.kt ├─ model/ │ ├─ Note.kt │ ├─ NoteFolder.kt │ └─ ContentItem.kt ├─ repository/ │ ├─ NotesRepository.kt │ └─ NoteFolderRepository.kt └─ usecase/ ├─ CreateNoteUseCase.kt ├─ DeleteNoteUseCase.kt ├─ GetNoteUseCase.kt ├─ UpdateNoteUseCase.kt └─ MoveNoteToFolderUseCase.kt
id: unique identifiertitle: note titlefolderId: optional folder IDcontentItems: list ofContentItemcreatedAt: creation timestampupdatedAt: last update timestamptags: set of tagsisFavorite: favorite flagsummary: optional AI-generated summary
Sealed class representing a note's content:
Text: text blockImage: image block (LocalorRemotesource)File: file attachmentLink: URL link
PLAIN,MARKDOWN,HTML
Local: local file pathRemote: remote URL
id: unique identifiername: folder namecreatedAt,updatedAt: timestampsmetadata: optional extra info
observeNotes(): flow of all notesobserveNotesByFolder(folderId): flow of notes for a foldergetNoteById(id): retrieve note by IDcreateNote(note): create noteupdateNote(note): update notedeleteNote(id): delete note
observeFolders(): flow of folderscreateFolder(folder): create folderrenameFolder(id, name): rename folderdeleteFolder(id): delete foldergetFolderById(id): retrieve folder by IDupdateFolder(folder): update folder
Repositories abstract storage for testable domain logic.
CreateFolderUseCaseDeleteFolderUseCaseGetFolderUseCaseObserveFoldersUseCaseUpdateFolderUseCase
CreateNoteUseCaseDeleteNoteUseCaseGetNoteUseCaseUpdateNoteUseCaseMoveNoteToFolderUseCaseObserveNotesUseCaseObserveNotesByFolderUseCase
Interface for AI operations.
suspend fun warmUp()fun release()suspend fun summarize(text: String, maxInputTokens: Int, maxNewTokens: Int): Stringsuspend fun suggestTags(text: String, maxInputTokens: Int, maxTags: Int): Set<String>suspend fun rewrite(text: String, style: RewriteStyle, maxInputTokens: Int, maxNewTokens: Int): Stringsuspend fun tagIMGs(img: List<String>): Set<String>tagTXTis deprecated and remains only as a compatibility shim oversuggestTags.
SuggestSummaryUseCase: extract text, call AI, return proposed summarySuggestTagsUseCase: extract text, call AI, return text tagsRewriteNoteUseCase: extract text, call AI, return a rewritten note proposalWarmUpNoteAiUseCase: initialize reusable model resources before the first user requestReleaseNoteAiUseCase: release model resources when the editor no longer needs themApplySummaryUseCase: update note with AI-generated summaryApplyTagsUseCase: update note with AI-generated tagsApplyRewriteUseCase: update note text with an accepted rewrite proposal
AI operations are separated into suggest (proposal) and apply (commit) stages.
- UI triggers an action
- ViewModel calls a use case
- Use case interacts with repository
- Repository returns or saves domain models
- Result propagates back to ViewModel
- ViewModel updates UI
- UI triggers AI action
- ViewModel calls
SuggestSummaryUseCase,SuggestTagsUseCase, orRewriteNoteUseCase - Use case retrieves note from repository
- Use case extracts text content
- Use case calls
NoteAiService - AI returns a proposed result
- ViewModel receives the proposal
- If confirmed,
ApplySummaryUseCase,ApplyTagsUseCase, orApplyRewriteUseCaseupdates the note
- Android-agnostic
- Storage-agnostic
- AI-implementation-agnostic
- “Suggest” and “Apply” AI operations are separated
- Models are extensible
Unit tests cover:
- Creating, updating, deleting notes and folders
- Moving notes between folders
- Observing notes and folders
- Getting AI-generated summaries, tags, and rewrites
- Applying summaries, tags, and rewrites
- Error handling for missing notes
Fake repositories and fake AI service enable testing without Android or OpenVINO dependencies.