A personal journaling application with workspaces and topics, featuring local-first data storage with optional cloud sync.
┌─────────────────────────────────────────┐
│ journal.encinas.casa (Netlify) │
│ Next.js Frontend + API Routes │
└─────────────────┬───────────────────────┘
│
┌─────────┴─────────┐
▼ ▼
┌───────────────┐ ┌───────────────┐
│ Supabase │ │ Mac (Local) │
│ (Cloud) │ │ │
│ │ │ • Python API │
│ • Metadata │ │ • SQLite DB │
│ • Sync state │ │ • Full content│
└───────────────┘ └───────────────┘
-
Start the application:
./start.sh
This starts both the Python backend (port 8789) and Next.js frontend (port 3009).
-
Open in browser: http://localhost:3009
start.sh binds Next.js and the Python server to 0.0.0.0 by default so they accept connections from your LAN and from your Tailscale tailnet (the service listens on all interfaces; Tailscale traffic arrives like any other).
-
On the machine running the journal stack, note its Tailscale IP (e.g.
100.x.y.z). -
On the client (laptop, phone browser, or another dev machine), set in
.env.local:NEXT_PUBLIC_LOCAL_API_URL=http://100.x.y.z:8789 -
Rebuild or restart Next so the client points at the Mac / Mac Mini hosting SQLite.
The deployed site on Netlify cannot reach 100.x.x.x from the cloud; only browsers on your tailnet can. See Jaime’s hybrid-app notes: use NEXT_PUBLIC_LOCAL_API_URL with the host’s tailnet address when you need the UI to talk to SQLite from another device.
To force localhost-only binding:
NEXTJS_HOST=127.0.0.1 API_BIND_HOST=127.0.0.1 ./start.sh
Full agent runbook (launch, health checks, Tailscale, curls): docs/OPENCLAW.md
Standard JSON envelope and catalog (per family app conventions):
| Endpoint | Notes |
|---|---|
GET http://localhost:3009/api/v1/health |
Next.js liveness (no auth). |
GET http://localhost:3009/api/v1/manifest |
Full endpoint list (Next + Python). |
GET http://localhost:8789/health |
Python liveness; body uses { success, data, meta }. |
Example:
curl -s http://localhost:3009/api/v1/health | jq .
curl -s http://localhost:3009/api/v1/manifest | jq .
curl -s http://localhost:8789/health | jq .Optional header for future secured routes: X-API-Key (env OPENCLAW_API_KEY). The SQLite Python CRUD routes stay usable from the browser without a key; prefer Tailscale ACLs for exposure control.
If you prefer to start servers separately:
# Terminal 1: Python backend
cd backend
python3 api_server.py
# Terminal 2: Next.js frontend (add -H 0.0.0.0 for Tailscale/LAN, same as start.sh)
npm run dev -- -p 3009 -H 0.0.0.0- Workspaces: Organize your journal into different areas (e.g., Professional, Personal, Ideas)
- Topics: Further categorize entries within each workspace
- Full-text search: Search across all your entries
- Markdown support: Write entries in markdown
- Tags: Add tags to entries for quick filtering
- Local-first: All content stored locally in SQLite for privacy
- Cloud sync: Metadata synced to Supabase for backup (optional)
- Workspace Summaries: AI-generated summaries of all notes in a workspace that update incrementally as you add new content
- AI Writing Companion: Get help while writing - ask for suggestions, explore ideas, or get feedback
- Related Notes: Find connections between your entries - the AI suggests related notes you can link to
If you have existing VooDoo Pad (.vpdoc) documents:
# Place .vpdoc files in import_data/ folder
python3 backend/import_voodoopad.py import_data/journaling/
├── src/ # Next.js frontend
│ ├── app/ # App router pages
│ ├── components/ # React components
│ │ └── journal/ # Journal-specific components
│ │ ├── ai-companion.tsx # AI writing assistant
│ │ ├── workspace-summary.tsx # Workspace AI summary
│ │ └── ...
│ └── lib/ # Utilities and API client
├── backend/
│ ├── api_server.py # Python HTTP server
│ ├── ai_service.py # Claude AI integration
│ ├── import_voodoopad.py # VooDoo Pad importer
│ ├── venv/ # Python virtual env (for anthropic)
│ └── db/ # SQLite database
├── supabase/
│ └── schema.sql # Cloud schema
└── start.sh # Launch script
See .env.local.example. Create .env.local with at least:
NEXT_PUBLIC_LOCAL_API_URL=http://localhost:8789
NEXT_PUBLIC_SUPABASE_URL=https://absicuhkgkmyjbsswjlr.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_key
NEXT_PUBLIC_APP_NAME=journal
# AI Features (optional - set for AI companion and workspace summaries)
ANTHROPIC_API_KEY=your_anthropic_api_key
# Optional — OpenClaw / agents on new Next.js API routes you protect with validateApiKey
# OPENCLAW_API_KEY=...
To use AI features, you need to:
- Get an API key from https://console.anthropic.com/
- Add it to your
.env.localfile - The Python backend will automatically pick it up
For production deployment to Netlify:
- Push to GitHub
- Connect repo to Netlify
- Set environment variables
- Add custom domain:
journal.encinas.casa
Note: The local backend needs to run on your machine for full functionality.
- Frontend: Next.js 16, TypeScript, Tailwind CSS, shadcn/ui
- Local Backend: Python 3, SQLite
- Cloud: Supabase (PostgreSQL)