# Diary A password-protected diary of reviews (books, movies, albums) and notes, built with Nuxt 4 + Nuxt UI on top of two self-hosted Baserow tables. ```bash pnpm install cp .env.example .env pnpm dev ``` ## Configuration | Variable | Purpose | |---|---| | `NUXT_BASEROW_URL` | Baserow instance, no trailing slash | | `NUXT_BASEROW_TOKEN` | Database token with read and create access to both tables | | `NUXT_BASEROW_REVIEWS_TABLE_ID` | Reviews table | | `NUXT_BASEROW_NOTES_TABLE_ID` | Notes table | | `NUXT_DIARY_PASSWORD` | Password that unlocks the diary | | `NUXT_SESSION_SECRET` | Signs the login cookie, at least 32 characters (`openssl rand -hex 32`) | In `app/app.config.ts`, `showCovers: true` shows a generated title tile next to each review. ## What it does - `/` is the only page: reviews and notes on one timeline, newest first, grouped by year. - Only entries with text are shown. Long text is collapsed behind "Read more". - Search matches every word against the kind (`review`, `note`), the medium (`book`, `movie`, `album`), the date (`aug 2025`, `2025-08`), the title, the author and the text. Matches in the text are highlighted. - "Log" opens a form with a Note / Review switch. - Until the password is entered, only a password prompt is shown and every API route except `/api/session` and `/api/login` returns 401. A correct password sets a signed, http-only cookie valid for 30 days. Changing `NUXT_SESSION_SECRET` logs out every browser. ## Code layout ``` app/ app.vue password gate around the page pages/index.vue the diary page components/ DiaryEntry.vue one timeline entry (date, title, text, read more) LogModal.vue Note / Review switch around the two forms NoteForm.vue, ReviewForm.vue PasswordModal.vue CoverTile.vue generated cover, used when showCovers is on composables/ useDiary.ts loads reviews + notes, searches, sorts and groups them by year useSaveEntry.ts shared submit logic of the forms useLog.ts open/close state of the Log modal utils/ dates, icons, search highlighting, error messages types/entry.ts a timeline entry (review or note) server/ middleware/auth.ts locks /api/* until unlocked api/ session, login, reviews and notes (GET list, POST create) utils/ baserow.ts Baserow client: listRows, createRow, listFields review.ts, note.ts Baserow row -> app type auth.ts session cookie and password check validation.ts readValidBody(event, zodSchema) shared/ types/ Review, Note utils/medium.ts the review media: label and creator label utils/schemas.ts zod schemas used by both forms and API ``` ## Baserow tables **Reviews:** `title`, `date` (ISO date), `author_or_director`, `review` (long text) and `medium` (single select: `Book` / `Movie` / `Album`). **Notes:** `Datum` (date) and `Notes` (long text). Rows without a date are skipped. Text is plain text: line breaks are kept and it is never rendered as HTML. ### Adding a medium 1. Add the option to the `medium` single select in Baserow. 2. Add it to `Medium` in `shared/types/review.ts`, to `MEDIUMS` in `shared/utils/medium.ts` (its `label` must match the Baserow option) and to `MEDIUM_ICONS` in `app/utils/icons.ts`.