reference

Visibility System for Notebooks and Journal Entries

Overview

The visibility system allows users to control who can see their notebooks and journal entries. It supports separate visibility controls for metadata (title, mood, tags, emotional tone) and content (the actual text).

Visibility Levels

  • user - Only the owner can see it (default)
  • team - All members of a specific team can see it
  • org - All members of a specific organization can see it
  • public - Anyone can see it

Separate Metadata and Content Visibility

You can set different visibility levels for metadata and content:

  • Metadata visibility - Controls who can see:

    • Title
    • Mood
    • Tags
    • Emotional tone/analysis (future feature)
    • Creation date
    • Other metadata fields
  • Content visibility - Controls who can see:

    • The actual journal entry content/text

Example Use Cases

  1. Share metadata only: Set metadata_visibility: 'team' and content_visibility: 'user'

    • Team members can see you wrote something and what mood you were in
    • But they can't read the actual content
  2. Share everything with team: Set both to 'team'

    • Team members can see both metadata and content
  3. Public mood tracking: Set metadata_visibility: 'public' and content_visibility: 'user'

    • Anyone can see your mood trends
    • But content remains private

Database Schema

Notebooks Table

metadata_visibility TEXT DEFAULT 'user' -- 'public', 'team', 'org', 'user'
content_visibility TEXT DEFAULT 'user'  -- 'public', 'team', 'org', 'user'
team_id UUID REFERENCES teams(id)      -- Required if visibility is 'team'
org_id UUID REFERENCES organizations(id) -- Required if visibility is 'org'

Journal Entries Table

metadata_visibility TEXT DEFAULT 'user' -- 'public', 'team', 'org', 'user'
content_visibility TEXT DEFAULT 'user'  -- 'public', 'team', 'org', 'user'
team_id UUID REFERENCES teams(id)       -- Required if visibility is 'team'
org_id UUID REFERENCES organizations(id) -- Required if visibility is 'org'

Inheritance

Journal entries can inherit visibility from their notebook:

  1. If an entry has explicit metadata_visibility or content_visibility set, it uses those
  2. If an entry's visibility is 'user' or NULL, it inherits from the notebook
  3. If the entry has no notebook, it defaults to 'user'

API Usage

Create Notebook with Visibility

POST /api/notebooks
{
  "name": "My Team Notebook",
  "metadata_visibility": "team",
  "content_visibility": "user",
  "team_id": "team-uuid-here"
}

Create Entry with Visibility

POST /api/journal
{
  "title": "Daily Reflection",
  "content": "Today was great...",
  "mood": "happy",
  "notebook_id": "notebook-uuid",
  "metadata_visibility": "team",
  "content_visibility": "user",
  "team_id": "team-uuid-here"
}

Update Visibility

PUT /api/notebooks/:id
{
  "metadata_visibility": "org",
  "org_id": "org-uuid-here"
}

Response Format

When fetching entries or notebooks, the API automatically filters based on visibility:

Entry Response (Content Hidden)

{
  "id": "entry-uuid",
  "title": "Daily Reflection",
  "mood": "happy",
  "tags": ["work", "personal"],
  "content": null,
  "content_hidden": true,
  "metadata_visibility": "team",
  "content_visibility": "user",
  "created_at": "2024-01-01T00:00:00Z"
}

Entry Response (Content Visible)

{
  "id": "entry-uuid",
  "title": "Daily Reflection",
  "content": "Today was great...",
  "mood": "happy",
  "tags": ["work", "personal"],
  "metadata_visibility": "team",
  "content_visibility": "team",
  "created_at": "2024-01-01T00:00:00Z"
}

Permission Checks

The system uses helper functions to check visibility:

TypeScript Helpers

import { 
  canViewNotebookMetadata,
  canViewNotebookContent,
  canViewEntryMetadata,
  canViewEntryContent,
  filterEntryForViewer
} from '@/database/visibility'

// Check if user can view entry metadata
const canView = await canViewEntryMetadata(supabase, userId, entry, notebook)

// Filter entry for viewer (removes content if not visible)
const filtered = await filterEntryForViewer(supabase, userId, entry, notebook)

Database Functions

-- Check if user can view notebook metadata
SELECT can_view_notebook_metadata(
  'viewer-user-id',
  notebook_user_id,
  metadata_visibility,
  team_id,
  org_id
)

-- Check if user can view entry content
SELECT can_view_entry_content(
  'viewer-user-id',
  entry_user_id,
  content_visibility,
  entry_team_id,
  entry_org_id,
  notebook_id
)

Row Level Security (RLS)

RLS policies ensure that:

  • Users can only see entries/notebooks they own OR have visibility access to
  • Super admins can see everything
  • Team/org members can see items shared with their team/org

Validation

The system validates that:

  • team_id is set when visibility is 'team'
  • org_id is set when visibility is 'org'
  • Visibility values are one of: 'public', 'team', 'org', 'user'

Future Enhancements

  • Emotional tone analysis that respects metadata visibility
  • Analytics/insights based on visible metadata
  • Granular permissions (e.g., specific users instead of just teams/orgs)
  • Time-based visibility (e.g., make public after 30 days)
VISIBILITY SYSTEM — Docs | HiveJournal