Files
website/README.md
T
2026-09-23 11:44:36 +02:00

82 lines
3.4 KiB
Markdown

# 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`.