Note
Data Entity
Description
A freeform text note authored by a peer mentor or coordinator, optionally linked to a contact. Supports draft auto-save and offline-first mutation via Drift. Scoped to a single organization; soft-deleted only.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Surrogate primary key, generated client-side for offline-first compatibility | PKrequiredunique |
organization_id |
uuid |
Tenant scope. Every query must filter by this column. References organizations table. | required |
user_id |
uuid |
The peer mentor or coordinator who authored the note. References users table. | required |
contact_id |
uuid |
Optional link to the contact this note concerns. Null for standalone/general notes. | - |
title |
string |
Short optional heading for the note. Max 200 characters. | - |
body |
text |
Main note content, plain text or light markdown. Required when note is finalized. | required |
draft_body |
text |
Auto-saved draft content before the user explicitly saves. Managed by draft-auto-save-handler. Null once finalized. | - |
is_draft |
boolean |
True while the note has unsaved draft content and has not been explicitly published. | required |
is_pinned |
boolean |
Whether the note is pinned to the top of the notes list for quick access. | required |
is_deleted |
boolean |
Soft-delete flag. Deleted notes are excluded from all listings but retained for audit. | required |
deleted_at |
datetime |
Timestamp when the note was soft-deleted. Null if active. | - |
deleted_by_user_id |
uuid |
User who performed the soft delete. Required when is_deleted is true. | - |
created_at |
datetime |
UTC timestamp when the note was first saved. | required |
updated_at |
datetime |
UTC timestamp of the last substantive edit to body or title. | required |
Database Indexes
idx_notes_org_user
Columns: organization_id, user_id
idx_notes_contact
Columns: contact_id
idx_notes_org_created
Columns: organization_id, created_at
idx_notes_user_active
Columns: user_id, is_deleted
idx_notes_pinned
Columns: user_id, is_pinned, is_deleted
Validation Rules
body_not_empty
error
Validation failed
title_max_length
error
Validation failed
deleted_at_consistency
error
Validation failed
contact_exists
error
Validation failed
user_active
error
Validation failed
updated_at_monotonic
error
Validation failed
Business Rules
org_scope_isolation
Every read and write query must include organization_id matching the authenticated user's active org context. Cross-org note access is forbidden regardless of user role.
soft_delete_only
Notes must never be hard-deleted. is_deleted=true with deleted_at and deleted_by_user_id set is the only permitted removal path, preserving audit trail for Bufdir.
author_or_coordinator_edit
Only the original author (user_id) or a coordinator within the same organization may edit or delete a note. Peer mentors cannot edit other peer mentors' notes.
draft_promotion
When a note is saved explicitly, draft_body is copied to body and draft_body is cleared. is_draft is set to false. The transition is atomic.
contact_org_match
If contact_id is provided, the referenced contact must belong to the same organization_id as the note. Cross-org contact linking is rejected.
offline_optimistic_mutation
Note creates and updates are written to the Drift local store immediately and queued in mutation-outbox-service. On sync, server conflicts are resolved by last-write-wins on updated_at.
pin_limit
A user may have at most 10 pinned notes per organization. Attempting to pin beyond the limit produces a warning and is rejected.