Second Brain is a private, self-hosted AI journal. You write one entry per day, the app extracts structured metadata from it, stores embeddings with pgvector, and lets you chat only against your own saved journal context.
The project is intended to be open source and reusable by anyone. It does not hardcode personal aliases or diary-specific knowledge in source code.
Write your day · Ask your second brain · Navigate your knowledge
The current MVP is working and includes:
- owner-only authentication with Supabase Auth
- protected
journal,chat, andaliasespages - one journal entry per user per day
- overwrite/update support for today's entry
- server-side OpenAI processing on save
- pgvector embeddings stored in Postgres
- semantic retrieval for chat
- normalized
projectsandpeopletables - JSON metadata on
journal_entries - alias management UI and API
Current metadata extracted from each entry:
topicstoolseventsmediaobservationsemotionsactionItemslessonsideasexperiencesworkKnowledge
projects and people are kept as normalized tables. Everything else above is stored as native JSON arrays directly on journal_entries.
When you save a journal entry:
- The app upserts a single entry for
userId + entryDate. - OpenAI generates a summary, projects, people, metadata arrays, and an embedding.
- The app resolves aliases from the database.
projectsandpeopleare upserted into normalized tables.- Journal-to-project and journal-to-person joins are replaced.
- Metadata arrays are stored on the journal row as JSON.
- The embedding is stored in Postgres using
pgvector.
If you rewrite today's entry and save again, the same row for today is updated. This is expected behavior in the current MVP.
Aliases exist so the app can normalize recurring names without hardcoding user-specific rules in code.
Example:
- extracted value:
personal blog - alias type:
project - canonical name:
personal_blog - display name:
Personal Blog
After that, future entries that mention that alias resolve automatically.
Alias behavior:
- aliases are stored in
entity_aliases - aliases are scoped per user
- if an alias exists, the canonical name from the database is used
- if no alias exists, the app falls back to generic normalization
You can manage aliases from:
/aliases
Available alias entity types:
projectpersontopictooleventmediaobservationemotion
- Next.js App Router
- TypeScript
- Tailwind CSS
- Prisma
- Supabase Auth
- Supabase Postgres / PostgreSQL
- OpenAI API
pgvector- Vercel
Before running this project, you need:
- a Supabase project
- a Postgres database
- the
vectorextension available in Postgres - an OpenAI API key
- a Vercel account if you want hosted deployment
Recommended setup for this repo:
- Supabase Auth for login/session handling
- Supabase Postgres for the database
- Vercel for hosting the Next.js app
See .env.example.
Required variables:
DATABASE_URLDIRECT_URLNEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEYOPENAI_API_KEYOPENAI_SUMMARY_MODELOPENAI_EMBEDDING_MODELOWNER_EMAIL
Notes:
OWNER_EMAILis the only email allowed to access the appDATABASE_URLis used by Prisma at runtimeDIRECT_URLis used for Prisma migrations- Supabase service role is not required in the current implementation
- Install dependencies:
npm install- Create your env file:
cp .env.example .env.local-
Fill in real values for Supabase, Postgres, OpenAI, and
OWNER_EMAIL. -
Generate Prisma client:
npm run prisma:generate- Run migrations:
npm run prisma:migrate- Start the app:
npm run devImportant storage rules in the current implementation:
- JSON metadata is stored as native JSON arrays, not stringified JSON
- embeddings are stored as native
pgvectorvalues, not text or JSON projectsandpeopleare normalized tables- metadata categories remain on
journal_entriesfor MVP simplicity
Useful scripts:
npm run prisma:generate
npm run prisma:migrate
npm run backfill:aliasesnpm run backfill:aliases is idempotent and re-resolves existing stored data through the entity_aliases table.
This app currently uses Supabase only for authentication and session handling.
What Supabase is used for:
- magic link / auth session flow
- protected owner-only access
- browser/server session cookies
What Supabase is not used for:
- application data ORM access
Journal data is handled through Prisma against Postgres.
To deploy on Vercel:
- Create a Vercel project connected to this repo.
- Add the same environment variables from your local env.
- Make sure your database URLs are reachable from Vercel.
- Make sure Supabase Auth redirect URLs include your Vercel domain.
- Deploy.
Deployment notes:
- the project is currently pinned to
next 15.5.9 - this was updated to satisfy current Next.js security requirements enforced by Vercel
- if Vercel reports an outdated or vulnerable Next.js version later, upgrade to the latest patched release in the current line
Main app routes:
/login/journal/chat/aliases
API routes:
POST /api/journal/saveGET /api/journal/todayPOST /api/chatGET /api/aliasesPOST /api/aliasesPATCH /api/aliases/:idDELETE /api/aliases/:idPOST /api/logout
- one entry per day, no version history yet
- owner-only access, not multi-user yet
- chat answers only from retrieved journal context and may say context is insufficient
- aliases are manual; they are not auto-created from guesses
- metadata quality still depends partly on LLM extraction quality
The goal is to make it easy for anyone to run a private AI journal that grows into a personal second brain through normal daily writing, while keeping the architecture simple enough to evolve over time.



