Current version: 1.0.0-beta.22
The idea for this app came from using my Hobonichi Techo planner every morning to write down what I needed to accomplish that day & using it for scratching down random thoughts and notes as the day went on. The closest thing I've seen to an app for replacing this system is Noteplan, but I don't use a Mac or an iOS device, and it's not self-hostable, so I decided to write my own.
Since I had the need for keeping track of to-dos throughout the day, regular Markdown didn't work for me since it doesn't natively support tasks. So as an alternative I'm using Github Flavored Markdown (GFM). I really wanted it to feel like an actual text editor and not just a textbox, so I decided to use CodeMirror to handle all the input. Fira Code is used to provide font ligatures. Some other nice features include code highlighting, text/code folding, and a task list where you can toggle the status of any task from any date or note.
I'd like to try add include at least of some the following features to get to a final v1.0 release:
- iCal support
- HTML preview (instead of just markdown)
- Kanban board for tasks (and new syntax to attach meta info like swimlane and project for each task)
- Nested tagging
- Generate or rotate a private read-only ICS URL with
GET/POST /api/calendar_token(requires auth). - Subscribe in Google Calendar via Settings -> Add calendar -> From URL using
/api/calendar.ics?token=<your_token>. - Each daily note becomes an all-day event; the feed updates when notes change (Google polls periodically).
- Rotate the token to immediately revoke previous subscriptions or disable sharing with
DELETE /api/calendar_token. - You can now subscribe to external ICS feeds (e.g., Google private links) in Settings; DailyNotes shows those events on the matching day.
Here is some screenshots of what it looks like:
Main editor:
Search page:
Task list:
The recommended way of running is to pull the image from Docker Hub.
| Environment Variable | Description | Default |
|---|---|---|
| API_SECRET_KEY | Used to sign API tokens. | Will be generated automatically if not passed in. |
| DATABASE_URI | Connection string for DB. | Will create and use a SQLite DB if not passed in. |
| DB_ENCRYPTION_KEY | Secret key for encrypting data. Length must be a multiple of 16. Warning: If changed data will not be able to be decrypted! |
Will be generated automatically if not passed in. |
| PREVENT_SIGNUPS | Disable signup form? Anything in this variable will prevent signups. | False |
| BASE_URL | Used when using a subfolder on a reverse proxy | None |
| PUID | User ID (for folder permissions) | None |
| PGID | Group ID (for folder permissions) | None |
| DEFAULT_TIMEZONE | Optional TZ name (e.g., America/Denver) for external ICS events; falls back to server local time |
None |
| Volume Name | Description |
|---|---|
| /app/config | Used to store DB and environment variables. This is not needed if you pass in all of the above environment variables. |
By default, the easiest way to get running is:
docker run -p 8000:8000 -v /config_dir:/app/config xhenxhe/dailynotesOr with the original image:
docker run -p 8000:8000 -v /config_dir:/app/config m0ngr31/dailynotesHere is a complete docker-compose example with all configuration options:
services:
dailynotes:
image: xhenxhe/dailynotes:latest
container_name: DailyNotes
ports:
- '8000:8000'
volumes:
# Persistent storage for database and config
- ./dailynotes-data:/app/config
environment:
# Required: Secret key for signing JWT tokens
# Generate with: openssl rand -hex 32
API_SECRET_KEY: 'your-secure-api-secret-key-here'
# Required: Encryption key for data at rest (must be multiple of 16)
# Generate with: openssl rand -hex 32
# WARNING: Changing this will make existing data unreadable!
DB_ENCRYPTION_KEY: 'your-secure-db-encryption-key-here'
# Optional: Database connection string
# Default: SQLite database in /app/config/app.db
# Examples:
# PostgreSQL: postgresql://user:password@localhost:5432/dailynotes
# MySQL: mysql://user:password@localhost:3306/dailynotes
# DATABASE_URI: "sqlite:////app/config/app.db"
# Optional: Prevent new user signups (set to any value to disable)
# PREVENT_SIGNUPS: "true"
# Optional: Base URL when using a reverse proxy subfolder
# Example: If accessing via https://example.com/notes, set to "/notes"
# BASE_URL: ""
# Optional: Set user/group ID for file permissions
# Useful for matching host user permissions
# PUID: "1000"
# PGID: "1000"
restart: unless-stopped
# Optional: Health check
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:8000/']
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# Optional: Use with PostgreSQL
# postgres:
# image: postgres:15-alpine
# container_name: dailynotes-db
# environment:
# POSTGRES_DB: dailynotes
# POSTGRES_USER: dailynotes
# POSTGRES_PASSWORD: your-secure-db-password
# volumes:
# - ./postgres-data:/var/lib/postgresql/data
# restart: unless-stoppedQuick Start with Docker Compose:
-
Save the above as
docker-compose.yml -
Generate secure keys:
# Generate API secret key openssl rand -hex 32 # Generate DB encryption key openssl rand -hex 32
-
Update the
API_SECRET_KEYandDB_ENCRYPTION_KEYvalues -
Start the application:
docker-compose up -d
-
Access at
http://localhost:8000
Important Notes:
- The
DB_ENCRYPTION_KEYencrypts all your notes. Never change it after initial setup or your data will be unreadable! - The
./dailynotes-datadirectory will store your database and configuration - The default port is now
8000for better compatibility
The easiest way to get started with development is using Docker. This approach provides:
- ✅ Consistent environment across all platforms (macOS, Linux, Windows)
- ✅ No need to install Python, Node.js, or manage versions
- ✅ Hot-reloading for both frontend and backend code
- ✅ Automatic database setup and migrations
- ✅ Isolated environment that won't affect your system
Quick Start:
# Start the development environment (builds, starts, and opens browser)
./devThat's it! The script will:
- Build the development Docker image
- Start both Flask (port 5001) and Vue.js (port 8080) servers
- Set up the database and run migrations
- Open your browser to http://localhost:8080
Development Workflow:
All your code changes will be automatically detected:
- Python/Flask changes: Flask server auto-reloads
- Vue.js changes: Hot module replacement (HMR) updates the browser instantly
- Database: Persisted in
./config/app.dbon your host machine
Useful Commands:
# View live logs from both servers
docker compose -f docker-compose.dev.yml logs -f
# Stop the development environment
docker compose -f docker-compose.dev.yml down
# Restart services
docker compose -f docker-compose.dev.yml restart
# Access the container shell (for debugging)
docker exec -it dailynotes-dev bash
# Rebuild after dependency changes
docker compose -f docker-compose.dev.yml buildFile Structure:
Dockerfile.dev- Development Docker image with both Python and Node.jsdocker-compose.dev.yml- Development compose config with volume mountsdocker-entrypoint-dev.sh- Startup script that runs both serversdev-docker- Convenience script to start everything and open browser
What's Mounted:
The following directories are mounted from your host to enable hot-reloading:
./app/- Python backend code./client/src/- Vue.js source code./client/public/- Static assets./config/- Database and environment variables (persisted)./migrations/- Database migrations
Environment Variables:
By default, the development environment will auto-generate secure keys in ./config/.env. To customize:
# Edit docker-compose.dev.yml
environment:
API_SECRET_KEY: 'your-dev-key'
DB_ENCRYPTION_KEY: 'your-16-char-multiple-key'
PREVENT_SIGNUPS: 'true' # Optional: disable signupsIf you prefer to run services directly on your host machine:
The easiest way to set up your development environment is to use the automated setup script:
./dev-setup.shThis script will:
- Check for Python 3 and Node.js
- Automatically use Node.js 16 via nvm (if available)
- Create a Python virtual environment
- Install all Python dependencies
- Install all Node.js dependencies
- Generate environment configuration
After setup completes, run the development servers:
# Backend (in one terminal)
source venv/bin/activate
./run.sh
# Frontend (in another terminal)
cd client
npm run dev # Uses Node 16 via nvm automaticallyNote: The project includes a .nvmrc file that specifies Node.js 16. If you have nvm installed, it will automatically use the correct version.
If you're on Windows or prefer to set up manually:
You need Python (works on 2 and 3) and Node.js 16 installed.
Recommended: Use nvm (macOS/Linux) or nvm-windows to manage Node.js versions. The project includes a .nvmrc file that specifies Node.js 16.
# If using nvm (recommended)
nvm install 16
nvm use 16
# Create and activate virtual environment (recommended)
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
cd client
npm ciYou can use the environment variables from above, or you can generate new ones by running the following:
./verify_env.pyKeep in mind that since the data is encrypted, if you modify the DB_ENCRYPTION_KEY variable, your data will not be accessible anymore.
During development you need to run the client and server simultaneously
# Activate virtual environment first
source venv/bin/activate # On Windows: venv\Scripts\activate
# Run backend
./run.sh# In a separate terminal
cd client
# If using nvm, switch to Node 16 first (or run npm run dev)
nvm use # Reads from .nvmrc file
# Start frontend dev server
npm run serve
# Or use the dev script which automatically uses Node 16:
npm run dev

