Skip to content

Deploying Blinko

Blinko is an AI-powered, self-hosted personal note-taking application that combines the simplicity of quick note capture with the intelligence of advanced AI search and retrieval. Built with TypeScript and designed for privacy-conscious users, Blinko enables you to capture fleeting thoughts, ideas, and information instantly while leveraging artificial intelligence to intelligently search and retrieve your notes using natural language. Whether you’re managing personal notes, project ideas, research notes, or daily reminders, Blinko provides a fast, private, and intelligent note-taking platform under your complete control.

Why Blinko?

Blinko stands out as the premier choice for AI-powered, privacy-focused note-taking with exceptional features and user experience:

  • AI-Enhanced Search: Natural language RAG (Retrieval-Augmented Generation) for intelligent note discovery
  • Complete Privacy: All notes stored on your servers with zero external data collection
  • Self-Hosted: Full control over notes, data, and platform infrastructure
  • Fast Capture: Instantly capture ideas and thoughts with minimal friction
  • Markdown Support: Full Markdown support for rich text formatting
  • Lightweight Architecture: Built with Tauri for efficient, lightweight performance
  • Multi-Platform: Native support for macOS, Windows, Linux, Android
  • Open Source: Fully transparent code available on GitHub
  • Zero Dependencies on Third Parties: No cloud services or external APIs required
  • Tag and Categorize: Organize notes with custom tags and collections
  • Full-Text Search: Rapid search across entire note library
  • Note Sharing: Share notes with specific users or publicly
  • Collaboration Features: Real-time collaboration on shared notes
  • Mobile-Friendly: Responsive web interface for mobile devices
  • API Access: Programmatic access for integrations
  • Dark Mode: Beautiful dark interface option
  • Keyboard Shortcuts: Power user keyboard shortcuts for efficiency
  • Offline Support: Work offline with automatic sync
  • Backup and Export: Export notes in multiple formats
  • User Management: Multi-user support with role-based access

Blinko is ideal for individuals seeking privacy, teams wanting private knowledge bases, researchers managing notes, students organizing study materials, and anyone preferring intelligent, AI-powered note retrieval. With persistent storage on Klutch.sh, your notes are permanently secure and accessible from anywhere.

Prerequisites

Before deploying Blinko, ensure you have:

  • A Klutch.sh account
  • A GitHub repository with your Blinko deployment configuration
  • Basic familiarity with Docker and Git
  • A custom domain name (recommended for production)
  • Sufficient storage for your notes (typically 10-50GB based on usage)
  • Optional: OpenAI API key for advanced AI features
  • Optional: PostgreSQL knowledge for production deployments

Important Considerations

Deploying Blinko

  1. Create a New Project

    Log in to your Klutch.sh dashboard and create a new project for your Blinko deployment.

  2. Prepare Your Repository

    Create a GitHub repository with the following structure for your Blinko deployment:

    blinko-deploy/
    ├─ Dockerfile
    ├─ .env.example
    ├─ docker-entrypoint.sh
    ├─ .gitignore
    └─ README.md

    Here’s a Dockerfile for Blinko:

    FROM node:20-alpine
    # Install system dependencies
    RUN apk add --no-cache \
    curl \
    git \
    bash \
    ca-certificates \
    postgresql-client
    # Set working directory
    WORKDIR /app
    # Clone Blinko repository
    RUN git clone https://github.com/blinko-space/blinko.git . && \
    git checkout main
    # Install dependencies with bun or npm
    RUN npm install -g bun && \
    bun install
    # Create necessary directories
    RUN mkdir -p /app/data \
    /app/logs \
    /app/storage && \
    chmod -R 755 /app
    # Build application
    RUN bun run build
    # Copy entrypoint script
    COPY docker-entrypoint.sh /
    RUN chmod +x /docker-entrypoint.sh
    # Expose port
    EXPOSE 3010
    # Health check
    HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
    CMD curl -f http://localhost:3010 || exit 1
    # Run entrypoint
    ENTRYPOINT ["/docker-entrypoint.sh"]
    CMD ["start"]

    Create a docker-entrypoint.sh file:

    #!/bin/bash
    set -e
    # Create necessary directories
    mkdir -p /app/data \
    /app/logs \
    /app/storage
    # Set proper permissions
    chmod -R 755 /app/data
    chmod -R 755 /app/storage
    # Check database connection if using PostgreSQL
    if [ -n "$DATABASE_URL" ]; then
    echo "Waiting for database connection..."
    MAX_ATTEMPTS=30
    ATTEMPTS=0
    while [ $ATTEMPTS -lt $MAX_ATTEMPTS ]; do
    if nc -z $(echo $DATABASE_URL | cut -d@ -f2 | cut -d: -f1) \
    $(echo $DATABASE_URL | cut -d: -f4 | cut -d/ -f1) 2>/dev/null || \
    pg_isready -h $(echo $DATABASE_URL | cut -d@ -f2 | cut -d: -f1) \
    -p $(echo $DATABASE_URL | cut -d: -f4 | cut -d/ -f1) 2>/dev/null; then
    echo "Database is ready!"
    break
    fi
    ATTEMPTS=$((ATTEMPTS + 1))
    sleep 1
    done
    fi
    # Run migrations if needed
    if [ ! -f /app/data/.migrated ]; then
    echo "Running database migrations..."
    bun run prisma migrate deploy || true
    touch /app/data/.migrated
    fi
    if [ "$1" = "start" ]; then
    # Start the application
    bun run start
    else
    exec "$@"
    fi

    Create a .env.example file:

    Terminal window
    # Blinko Configuration
    NODE_ENV=production
    PORT=3010
    APP_URL=https://notes.yourdomain.com
    # Database Configuration
    DATABASE_URL=postgresql://blinko:password@db:5432/blinko
    # Authentication
    JWT_SECRET=your-secure-jwt-secret-here
    SESSION_SECRET=your-secure-session-secret-here
    # Admin User
    ADMIN_EMAIL=admin@yourdomain.com
    ADMIN_PASSWORD=secure_password_here
    # Storage Configuration
    STORAGE_PATH=/app/storage
    DATA_PATH=/app/data
    LOG_PATH=/app/logs
    # AI Configuration (Optional)
    ENABLE_AI_SEARCH=true
    OPENAI_API_KEY=
    OPENAI_MODEL=gpt-3.5-turbo
    # Features
    ENABLE_PUBLIC_SHARING=true
    ENABLE_COLLABORATION=true
    ENABLE_TAGS=true
    MAX_NOTE_SIZE=10485760
    # Security
    FORCE_HTTPS=true
    SESSION_TIMEOUT_MINUTES=1440
    # Logging
    LOG_LEVEL=info

    Commit and push to your GitHub repository:

    Terminal window
    git init
    git add .
    git commit -m "Initial Blinko deployment"
    git remote add origin https://github.com/yourusername/blinko-deploy.git
    git push -u origin main
  3. Create a New App

    In the Klutch.sh dashboard:

    • Click “Create New App”
    • Select your GitHub repository containing the Dockerfile
    • Choose the branch (typically main or master)
    • Klutch.sh will automatically detect the Dockerfile in the root directory
  4. Configure Environment Variables

    Set up these essential environment variables in your Klutch.sh dashboard:

    VariableDescriptionExample
    NODE_ENVNode environmentproduction
    PORTApplication port3010
    APP_URLYour application domainhttps://notes.yourdomain.com
    DATABASE_URLPostgreSQL connection stringpostgresql://user:pass@host/db
    JWT_SECRETJWT signing secret (generate secure)secure-random-string
    SESSION_SECRETSession secret (generate secure)secure-random-string
    ADMIN_EMAILAdmin account emailadmin@yourdomain.com
    ADMIN_PASSWORDAdmin account passwordsecure_password
    STORAGE_PATHPath to note storage/app/storage
    DATA_PATHPath to application data/app/data
    LOG_PATHPath to application logs/app/logs
    ENABLE_AI_SEARCHEnable AI-powered searchtrue
    ENABLE_PUBLIC_SHARINGAllow note sharingtrue
    ENABLE_COLLABORATIONEnable collaborative editingtrue
    FORCE_HTTPSForce HTTPS connectionstrue
    LOG_LEVELLogging verbosityinfo
  5. Configure Persistent Storage

    Blinko requires persistent storage for notes and application data. Add persistent volumes:

    Mount PathDescriptionRecommended Size
    /app/storageNote files and attachments100GB+
    /app/dataDatabase and application data50GB
    /app/logsApplication logs20GB

    In the Klutch.sh dashboard:

    • Navigate to your app settings
    • Go to the “Volumes” section
    • Click “Add Volume” for each mount path
    • Set mount paths and sizes as specified above
  6. Set Network Configuration

    Configure your app’s network settings:

    • Select traffic type: HTTP (Blinko uses standard web ports)
    • Recommended internal port: 3010 (as specified in Dockerfile)
    • Klutch.sh will automatically handle HTTPS termination via reverse proxy
    • Ensure ports 80 and 443 are accessible from your domain
  7. Configure Custom Domain

    Blinko works best with a custom domain for professional note-taking:

    • Navigate to your app’s “Domains” section in Klutch.sh
    • Click “Add Custom Domain”
    • Enter your domain (e.g., notes.yourdomain.com)
    • Configure DNS with a CNAME record to point to your Klutch.sh app
    • Update APP_URL environment variable to match your domain
    • Klutch.sh will automatically provision SSL certificates
  8. Deploy Your App

    • Review all settings and environment variables
    • Verify all persistent volumes are properly configured
    • Click “Deploy”
    • Klutch.sh will build the Docker image and start your Blinko instance
    • Wait for the deployment to complete (typically 5-10 minutes)
    • Access your Blinko instance at your configured domain
    • Log in with admin credentials to begin creating notes

Initial Setup and Configuration

After deployment completes, access your Blinko instance to complete setup.

Accessing Blinko

Navigate to your domain: https://notes.yourdomain.com

Log in with the admin credentials you configured in environment variables.

Creating Your First Note

Start capturing ideas and notes:

  1. Click the ”+” button or “New Note” option
  2. Enter your note title
  3. Type your note content with Markdown support
  4. Add tags for organization (e.g., #ideas, #project, #research)
  5. Click save to store your note
  6. Notes are automatically indexed for AI search

Understanding Note Organization

Organize your notes effectively:

  1. Tags: Add hashtags to categorize notes (#work, #personal, #research)
  2. Collections: Create collections for grouping related notes
  3. Starred Notes: Mark important notes as favorites for quick access
  4. Pinned Notes: Pin frequently accessed notes to top of list
  5. Search: Use AI-powered natural language search to find notes

Enable AI-powered note retrieval:

  1. Navigate to “Settings” → “AI Configuration”
  2. AI search enabled by default with local embeddings
  3. Optional: Add OpenAI API key for advanced features
    • Log in to your OpenAI account
    • Generate API key
    • Paste key in Blinko settings
  4. Test AI search by querying notes naturally
  5. AI learns from your note patterns over time

Creating User Accounts

Set up accounts for team members:

  1. Navigate to “Settings” → “Users”
  2. Click “Invite User”
  3. Enter email address
  4. Set user role (Admin, Editor, or Viewer)
  5. Send invitation link
  6. User completes account setup

Sharing Notes

Share notes with other users:

  1. Select a note
  2. Click “Share” button
  3. Choose sharing method:
    • Share with specific users
    • Create public link (optional)
    • Set permissions (view only or edit)
  4. Copy share link and send to recipient
  5. Recipient can view or edit note

Setting Up Collections

Organize notes into collections:

  1. Navigate to “Collections” or “Library”
  2. Click “Create New Collection”
  3. Name your collection
  4. Add description
  5. Add notes to collection by dragging or selecting
  6. Organize collections hierarchically if needed

Environment Variable Examples

Basic Configuration

Terminal window
NODE_ENV=production
PORT=3010
APP_URL=https://notes.yourdomain.com
DATABASE_URL=postgresql://blinko:password@db:5432/blinko
JWT_SECRET=secure-random-string
SESSION_SECRET=secure-random-string
ADMIN_EMAIL=admin@yourdomain.com
ADMIN_PASSWORD=secure_password

Complete Production Configuration

Terminal window
# Application Settings
NODE_ENV=production
PORT=3010
APP_URL=https://notes.yourdomain.com
LOG_LEVEL=info
# Database Configuration
DATABASE_URL=postgresql://blinko_user:secure_password@postgres:5432/blinko
# Security
JWT_SECRET=your-very-secure-jwt-secret-key
SESSION_SECRET=your-very-secure-session-secret-key
SESSION_TIMEOUT_MINUTES=1440
FORCE_HTTPS=true
# Admin Configuration
ADMIN_EMAIL=admin@yourdomain.com
ADMIN_PASSWORD=secure_admin_password
# Storage Configuration
STORAGE_PATH=/app/storage
DATA_PATH=/app/data
LOG_PATH=/app/logs
MAX_NOTE_SIZE=10485760
# AI Configuration
ENABLE_AI_SEARCH=true
OPENAI_API_KEY=sk-your-openai-api-key
OPENAI_MODEL=gpt-3.5-turbo
# Features
ENABLE_PUBLIC_SHARING=true
ENABLE_COLLABORATION=true
ENABLE_TAGS=true
ENABLE_EXPORT=true
# Performance
DATABASE_POOL_SIZE=20
CACHE_ENABLED=true
CACHE_TTL=3600
# Logging and Monitoring
DEBUG=false
SENTRY_DSN=

Sample Code and Getting Started

Python - Blinko API Integration

import requests
import json
from typing import Optional, List, Dict
class BlinkoClient:
def __init__(self, base_url: str, email: str, password: str):
self.base_url = base_url.rstrip('/')
self.api_url = f'{self.base_url}/api'
self.email = email
self.password = password
self.access_token = None
self.login()
def login(self) -> bool:
"""Authenticate with Blinko API"""
try:
response = requests.post(
f'{self.api_url}/auth/login',
json={'email': self.email, 'password': self.password}
)
response.raise_for_status()
data = response.json()
self.access_token = data.get('token')
return bool(self.access_token)
except requests.exceptions.RequestException as e:
print(f"Login failed: {e}")
return False
def get_headers(self) -> Dict:
"""Get request headers with authentication"""
return {
'Content-Type': 'application/json',
'Authorization': f'Bearer {self.access_token}'
}
def create_note(self, title: str, content: str,
tags: List[str] = None) -> Optional[Dict]:
"""Create a new note"""
try:
payload = {
'title': title,
'content': content,
'tags': tags or []
}
response = requests.post(
f'{self.api_url}/notes',
headers=self.get_headers(),
json=payload
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error creating note: {e}")
return None
def get_note(self, note_id: str) -> Optional[Dict]:
"""Retrieve a specific note"""
try:
response = requests.get(
f'{self.api_url}/notes/{note_id}',
headers=self.get_headers()
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error retrieving note: {e}")
return None
def list_notes(self, limit: int = 50, offset: int = 0) -> Optional[List[Dict]]:
"""List all notes"""
try:
response = requests.get(
f'{self.api_url}/notes',
headers=self.get_headers(),
params={'limit': limit, 'offset': offset}
)
response.raise_for_status()
return response.json().get('data', [])
except requests.exceptions.RequestException as e:
print(f"Error listing notes: {e}")
return None
def search_notes(self, query: str) -> Optional[List[Dict]]:
"""Search notes using natural language AI search"""
try:
response = requests.get(
f'{self.api_url}/notes/search',
headers=self.get_headers(),
params={'q': query}
)
response.raise_for_status()
return response.json().get('data', [])
except requests.exceptions.RequestException as e:
print(f"Error searching notes: {e}")
return None
def update_note(self, note_id: str, title: str = None,
content: str = None, tags: List[str] = None) -> Optional[Dict]:
"""Update an existing note"""
try:
payload = {}
if title:
payload['title'] = title
if content:
payload['content'] = content
if tags:
payload['tags'] = tags
response = requests.put(
f'{self.api_url}/notes/{note_id}',
headers=self.get_headers(),
json=payload
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error updating note: {e}")
return None
def delete_note(self, note_id: str) -> bool:
"""Delete a note"""
try:
response = requests.delete(
f'{self.api_url}/notes/{note_id}',
headers=self.get_headers()
)
response.raise_for_status()
return True
except requests.exceptions.RequestException as e:
print(f"Error deleting note: {e}")
return False
def get_tags(self) -> Optional[List[str]]:
"""Get all tags in the library"""
try:
response = requests.get(
f'{self.api_url}/tags',
headers=self.get_headers()
)
response.raise_for_status()
return response.json().get('data', [])
except requests.exceptions.RequestException as e:
print(f"Error getting tags: {e}")
return None
def create_collection(self, name: str, description: str = '') -> Optional[Dict]:
"""Create a new collection"""
try:
payload = {
'name': name,
'description': description
}
response = requests.post(
f'{self.api_url}/collections',
headers=self.get_headers(),
json=payload
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error creating collection: {e}")
return None
def add_note_to_collection(self, collection_id: str, note_id: str) -> bool:
"""Add note to collection"""
try:
payload = {'note_id': note_id}
response = requests.post(
f'{self.api_url}/collections/{collection_id}/notes',
headers=self.get_headers(),
json=payload
)
response.raise_for_status()
return True
except requests.exceptions.RequestException as e:
print(f"Error adding note to collection: {e}")
return False
def export_notes(self, format: str = 'markdown') -> Optional[bytes]:
"""Export all notes in specified format"""
try:
response = requests.get(
f'{self.api_url}/export',
headers=self.get_headers(),
params={'format': format}
)
response.raise_for_status()
return response.content
except requests.exceptions.RequestException as e:
print(f"Error exporting notes: {e}")
return None
# Usage example
if __name__ == "__main__":
client = BlinkoClient('https://notes.yourdomain.com', 'admin@yourdomain.com', 'password')
# Create a note
note = client.create_note(
'Project Ideas',
'# My Project Ideas\n- Idea 1\n- Idea 2\n- Idea 3',
tags=['projects', 'ideas']
)
if note:
print(f"Note created: {note['id']}")
# List all notes
notes = client.list_notes(limit=10)
if notes:
print(f"Total notes: {len(notes)}")
for note in notes:
print(f"- {note['title']}")
# Search notes
results = client.search_notes('important projects')
print(f"Search results: {results}")
# Get tags
tags = client.get_tags()
print(f"Available tags: {tags}")
# Create collection
collection = client.create_collection('Work Projects', 'Collection of work-related projects')
if collection:
collection_id = collection['id']
# Add note to collection
if note:
client.add_note_to_collection(collection_id, note['id'])
# Export notes
export_data = client.export_notes(format='markdown')
if export_data:
with open('notes_backup.md', 'wb') as f:
f.write(export_data)

JavaScript - Blinko Web Client

const NOTES_API_URL = 'https://notes.yourdomain.com/api';
class BlinkoNoteApp {
constructor(email, password) {
this.email = email;
this.password = password;
this.accessToken = null;
this.currentNote = null;
}
async login() {
try {
const response = await fetch(`${NOTES_API_URL}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: this.email,
password: this.password
})
});
if (!response.ok) throw new Error('Login failed');
const data = await response.json();
this.accessToken = data.token;
return true;
} catch (error) {
console.error('Login error:', error);
return false;
}
}
getHeaders() {
return {
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': 'application/json'
};
}
async createNote(title, content, tags = []) {
try {
const response = await fetch(`${NOTES_API_URL}/notes`, {
method: 'POST',
headers: this.getHeaders(),
body: JSON.stringify({ title, content, tags })
});
if (!response.ok) throw new Error('Failed to create note');
return await response.json();
} catch (error) {
console.error('Create note error:', error);
return null;
}
}
async listNotes(limit = 50) {
try {
const response = await fetch(
`${NOTES_API_URL}/notes?limit=${limit}`,
{ headers: this.getHeaders() }
);
if (!response.ok) throw new Error('Failed to list notes');
return await response.json();
} catch (error) {
console.error('List notes error:', error);
return { data: [] };
}
}
async searchNotes(query) {
try {
const response = await fetch(
`${NOTES_API_URL}/notes/search?q=${encodeURIComponent(query)}`,
{ headers: this.getHeaders() }
);
if (!response.ok) throw new Error('Search failed');
return await response.json();
} catch (error) {
console.error('Search error:', error);
return { data: [] };
}
}
async updateNote(noteId, updates) {
try {
const response = await fetch(`${NOTES_API_URL}/notes/${noteId}`, {
method: 'PUT',
headers: this.getHeaders(),
body: JSON.stringify(updates)
});
if (!response.ok) throw new Error('Failed to update note');
return await response.json();
} catch (error) {
console.error('Update error:', error);
return null;
}
}
async deleteNote(noteId) {
try {
const response = await fetch(`${NOTES_API_URL}/notes/${noteId}`, {
method: 'DELETE',
headers: this.getHeaders()
});
return response.ok;
} catch (error) {
console.error('Delete error:', error);
return false;
}
}
async getTags() {
try {
const response = await fetch(`${NOTES_API_URL}/tags`, {
headers: this.getHeaders()
});
if (!response.ok) throw new Error('Failed to fetch tags');
return await response.json();
} catch (error) {
console.error('Tags fetch error:', error);
return { data: [] };
}
}
async shareNote(noteId, userEmail, permission = 'view') {
try {
const response = await fetch(
`${NOTES_API_URL}/notes/${noteId}/share`,
{
method: 'POST',
headers: this.getHeaders(),
body: JSON.stringify({
email: userEmail,
permission: permission
})
}
);
if (!response.ok) throw new Error('Failed to share note');
return await response.json();
} catch (error) {
console.error('Share error:', error);
return null;
}
}
async exportNotes(format = 'markdown') {
try {
const response = await fetch(
`${NOTES_API_URL}/export?format=${format}`,
{ headers: this.getHeaders() }
);
if (!response.ok) throw new Error('Export failed');
return await response.blob();
} catch (error) {
console.error('Export error:', error);
return null;
}
}
}
// Usage example
(async () => {
const app = new BlinkoNoteApp('admin@yourdomain.com', 'password');
// Login
const loggedIn = await app.login();
if (!loggedIn) {
console.error('Failed to login');
return;
}
// Create note
const note = await app.createNote(
'Meeting Notes',
'# Team Meeting\n\n- Discussion point 1\n- Discussion point 2\n- Action items',
['meetings', 'work']
);
console.log('Created note:', note);
// List notes
const notes = await app.listNotes();
console.log('All notes:', notes.data);
// Search notes
const searchResults = await app.searchNotes('important meeting');
console.log('Search results:', searchResults.data);
// Get tags
const tags = await app.getTags();
console.log('Available tags:', tags.data);
// Share note
if (note) {
const shared = await app.shareNote(note.id, 'colleague@example.com', 'edit');
console.log('Note shared:', shared);
}
// Export notes
const exportBlob = await app.exportNotes('markdown');
if (exportBlob) {
const url = window.URL.createObjectURL(exportBlob);
const a = document.createElement('a');
a.href = url;
a.download = 'notes_backup.md';
a.click();
}
})();

cURL - API Integration Examples

Terminal window
# Login to Blinko
curl -X POST https://notes.yourdomain.com/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "admin@yourdomain.com",
"password": "your-password"
}'
# Create a new note
curl -X POST https://notes.yourdomain.com/api/notes \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{
"title": "My First Note",
"content": "# Markdown Note\n\nThis is my first note with **bold** text",
"tags": ["idea", "important"]
}'
# List all notes
curl -X GET "https://notes.yourdomain.com/api/notes?limit=20" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
# Get specific note
curl -X GET https://notes.yourdomain.com/api/notes/{note-id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
# Search notes with AI
curl -X GET "https://notes.yourdomain.com/api/notes/search?q=important%20projects" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
# Update a note
curl -X PUT https://notes.yourdomain.com/api/notes/{note-id} \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{
"title": "Updated Title",
"content": "Updated note content"
}'
# Delete a note
curl -X DELETE https://notes.yourdomain.com/api/notes/{note-id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
# Get all tags
curl -X GET https://notes.yourdomain.com/api/tags \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
# Share a note
curl -X POST https://notes.yourdomain.com/api/notes/{note-id}/share \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{
"email": "colleague@example.com",
"permission": "edit"
}'
# Export all notes
curl -X GET "https://notes.yourdomain.com/api/export?format=markdown" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-o notes_backup.md

Bash - Note Backup Script

#!/bin/bash
# Blinko Notes Backup Script
BACKUP_DIR="/backups/blinko"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=30
API_URL="https://notes.yourdomain.com/api"
EMAIL="admin@yourdomain.com"
PASSWORD="your-password"
# Create backup directory
mkdir -p $BACKUP_DIR
echo "Starting Blinko backup..."
# Get access token
TOKEN=$(curl -s -X POST $API_URL/auth/login \
-H "Content-Type: application/json" \
-d "{\"email\":\"$EMAIL\",\"password\":\"$PASSWORD\"}" \
| grep -o '"token":"[^"]*' | cut -d'"' -f4)
if [ -z "$TOKEN" ]; then
echo "Failed to authenticate"
exit 1
fi
# Export notes in markdown format
echo "Exporting notes..."
curl -s -X GET "$API_URL/export?format=markdown" \
-H "Authorization: Bearer $TOKEN" \
-o $BACKUP_DIR/blinko_notes_$TIMESTAMP.md
# Export notes in JSON format
echo "Exporting notes as JSON..."
curl -s -X GET "$API_URL/export?format=json" \
-H "Authorization: Bearer $TOKEN" \
-o $BACKUP_DIR/blinko_notes_$TIMESTAMP.json
# Compress backups
tar -czf $BACKUP_DIR/blinko_backup_$TIMESTAMP.tar.gz \
$BACKUP_DIR/blinko_notes_$TIMESTAMP.md \
$BACKUP_DIR/blinko_notes_$TIMESTAMP.json
# Cleanup old backups
echo "Cleaning up old backups..."
find $BACKUP_DIR -name "blinko_backup_*" -mtime +$RETENTION_DAYS -delete
find $BACKUP_DIR -name "blinko_notes_*" -mtime +0 -delete
# Backup summary
echo "Backup completed: $TIMESTAMP"
ls -lh $BACKUP_DIR | tail -5
# Optional: Upload to cloud storage (S3 example)
# aws s3 cp $BACKUP_DIR/blinko_backup_$TIMESTAMP.tar.gz s3://your-bucket/backups/

Docker Compose for Local Development

For local testing before deploying to Klutch.sh:

version: '3.8'
services:
blinko:
image: blinkospace/blinko:latest
container_name: blinko-app
environment:
NODE_ENV: development
PORT: 3010
APP_URL: http://localhost:3010
DATABASE_URL: postgresql://blinko:blinko@db:5432/blinko
JWT_SECRET: dev-secret-key-change-in-production
SESSION_SECRET: dev-session-secret-change-in-production
ADMIN_EMAIL: admin@localhost
ADMIN_PASSWORD: admin123
STORAGE_PATH: /app/storage
DATA_PATH: /app/data
LOG_PATH: /app/logs
ports:
- "3010:3010"
volumes:
- ./storage:/app/storage
- ./data:/app/data
- ./logs:/app/logs
depends_on:
- db
restart: unless-stopped
db:
image: postgres:15-alpine
container_name: blinko-db
environment:
POSTGRES_USER: blinko
POSTGRES_PASSWORD: blinko
POSTGRES_DB: blinko
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
postgres_data:

To run locally:

Terminal window
docker-compose up -d

Access Blinko at http://localhost:3010

Note Management and Organization

Best Practices for Note-Taking

Develop efficient note-taking habits:

  1. Use Clear Titles: Descriptive titles make notes searchable
  2. Leverage Tags: Organize with consistent tags (#work, #personal, #research)
  3. Write in Markdown: Use formatting for better readability
  4. Regular Reviews: Review and update notes periodically
  5. Archive Old Notes: Move completed projects to archive collections
  6. Link Related Notes: Reference other notes for context
  7. Use Templates: Create templates for recurring note types

Markdown Formatting

Write rich notes with Markdown:

# Main Heading
## Subheading
### Sub-subheading
**Bold text** and *italic text*
- Bullet point 1
- Bullet point 2
- Nested bullet
1. Numbered item
2. Another item
<a href="https://example.com" target="_blank" rel="noopener noreferrer">Link text</a>
`inline code` and
\`\`\`
code block
\`\`\`
| Header 1 | Header 2 |
|----------|----------|
| Cell 1 | Cell 2 |

AI Search Usage

Maximize AI-powered search effectiveness:

  1. Natural Language: Query in conversational language
  2. Context Clues: Include relevant context in searches
  3. Example Searches:
    • “meetings with Sarah about Q4 planning”
    • “Python code snippets for API calls”
    • “Restaurant recommendations from travel notes”
  4. Search History: Review previous searches for patterns
  5. Refine Queries: Adjust search terms for better results

User Management and Permissions

Creating User Accounts

Set up multiple users:

  1. Admin user created during setup
  2. Invite additional users via email
  3. Users complete account registration
  4. Users log in with their credentials

User Roles

Define access levels:

RolePermissions
AdminCreate users, manage settings, access all notes
EditorCreate and edit notes, share notes
ViewerView shared notes only

Sharing and Collaboration

Collaborate on notes:

  1. Select note to share
  2. Click “Share” or “Collaborate”
  3. Choose sharing method:
    • Share with specific users
    • Create public link (optional)
  4. Set permissions (view or edit)
  5. Collaborators can real-time edit notes

Advanced Features

Setting Up Collections

Organize notes into collections:

  1. Create collection for project
  2. Add related notes to collection
  3. Create nested sub-collections
  4. Share entire collection with team
  5. Archive completed collections

Public Sharing

Share notes publicly:

  1. Enable public sharing in settings
  2. Click “Make Public” on note
  3. Copy public link
  4. Share link on social media or website
  5. Readers access without login

Export and Backup

Regularly backup your notes:

  1. Click “Export” in settings
  2. Choose format (Markdown, JSON, PDF)
  3. Download exported file
  4. Store backups securely
  5. Test restore procedures regularly

API Access

Use Blinko API for integrations:

  1. Generate API token in settings
  2. Use token for authentication
  3. Build custom applications
  4. Integrate with other services
  5. Automate note management

Security and Performance

Data Protection

Secure your notes:

  1. HTTPS enforced for all connections
  2. Strong passwords enforced
  3. JWT tokens for API access
  4. Secure session management
  5. Regular security updates

Backup and Recovery

Implement backup strategy:

  1. Automated daily backups
  2. Store backups in multiple locations
  3. Test recovery procedures
  4. Document backup location
  5. Monitor backup integrity

Database Performance

Optimize for growth:

  1. Use PostgreSQL for production
  2. Create database indexes
  3. Monitor query performance
  4. Archive old notes
  5. Regular database maintenance

Troubleshooting

Common Issues and Solutions

Issue: Cannot login to Blinko

Solutions:

  • Verify email and password are correct
  • Check if user account is created
  • Review application logs
  • Check database connectivity
  • Restart application container

Issue: AI search not working

Troubleshooting:

  • Verify AI search is enabled in settings
  • Check OpenAI API key if using external AI
  • Ensure notes are properly indexed
  • Review API logs for errors
  • Try manual indexing of notes

Issue: Notes not saving

Solutions:

  • Check database connection
  • Verify storage permissions
  • Monitor disk space
  • Review application logs
  • Check network connectivity

Issue: Slow performance with many notes

Solutions:

  • Switch to PostgreSQL if using SQLite
  • Create database indexes
  • Archive old notes
  • Enable caching
  • Monitor system resources

Updating Blinko

To update Blinko to a newer version:

  1. Read the release notes carefully
  2. Backup all notes before updating
  3. Update your Dockerfile:
    RUN git checkout latest-version
  4. Commit and push to GitHub
  5. Klutch.sh will automatically rebuild
  6. Test all features after upgrade
  7. Monitor logs for any issues

Use Cases

Personal Note-Taking

  • Capture daily ideas and thoughts
  • Create personal knowledge base
  • Quick reference for information
  • Daily journal and reflections

Professional Documentation

  • Project notes and documentation
  • Team meeting notes
  • Technical snippets and solutions
  • Knowledge sharing with team

Research and Learning

  • Research notes and citations
  • Learning notes from courses
  • Article summaries and highlights
  • Reference material organization

Creative Projects

  • Story ideas and plot notes
  • Character development
  • Brainstorming sessions
  • Writing drafts and outlines

Additional Resources

Conclusion

Deploying Blinko on Klutch.sh provides you with a completely private, AI-powered note-taking platform that maintains full control over your personal knowledge base. With intelligent natural language search, complete privacy, multi-user support, note sharing, and collaborative editing, Blinko enables you to capture and organize ideas effortlessly while leveraging AI to find exactly what you need. Klutch.sh’s managed infrastructure ensures your notes are always available, secure, and performant, allowing you to focus on capturing and organizing your thoughts.

Start hosting your private AI-powered note-taking platform today by deploying Blinko on Klutch.sh and transform how you capture, organize, and retrieve your ideas.