108 lines
3.8 KiB
Markdown
108 lines
3.8 KiB
Markdown
# Val-Friendbook
|
|
|
|
A small self-hosted friendbook for the lovely peeps I meet on there. Everyone can submit their own page (name, fun fact, favorite color, mood, badge images, ...). New entries stay hidden until an admin approves them.
|
|
|
|
Plain Express + Multer, with a JSON file as the "database".
|
|
|
|
## Features
|
|
|
|
- Public gallery of approved entries, newest first
|
|
- Submission form with up to 5 badge images per entry (PNG, JPG, GIF, WEBP, max. 3 MB each; easily my favourite feature lol)
|
|
- Moderation: new entries are `pending` until approved in the admin panel
|
|
- Denying an entry deletes it and its uploaded images
|
|
- Admin panel at `/admin`, protected by a password
|
|
|
|
## Requirements
|
|
|
|
- Node.js 18 or newer
|
|
|
|
## Quick start
|
|
|
|
```bash
|
|
git clone https://gitea.nkelabs.xyz/nke4/Val-Friendbook.git
|
|
cd Val-Friendbook
|
|
npm install
|
|
ADMIN_PASSWORD='choose-a-strong-password' npm start
|
|
```
|
|
|
|
The app runs on `http://localhost:3030` by default.
|
|
|
|
## Configuration
|
|
|
|
| Variable | Default | Description |
|
|
| ---------------- | ---------- | --------------------------------------------------------- |
|
|
| `ADMIN_PASSWORD` | `changeme` | Password for the admin panel. **Always set this.** |
|
|
| `PORT` | `3030` | Port the server listens on (the Dockerfile sets `3000`). |
|
|
|
|
If `ADMIN_PASSWORD` is not set, the server falls back to `changeme` and prints a warning in the log on startup.
|
|
|
|
## Deployment
|
|
|
|
### pm2
|
|
|
|
```bash
|
|
ADMIN_PASSWORD='choose-a-strong-password' PORT=3000 pm2 start server.js --name friendbook
|
|
pm2 save
|
|
```
|
|
|
|
To change the environment of an existing process:
|
|
|
|
```bash
|
|
ADMIN_PASSWORD='new-password' pm2 restart friendbook --update-env
|
|
pm2 save
|
|
```
|
|
|
|
### Docker
|
|
|
|
```bash
|
|
docker build -t val-friendbook .
|
|
docker run -d --name val-friendbook \
|
|
-p 3000:3000 \
|
|
-e ADMIN_PASSWORD='choose-a-strong-password' \
|
|
-v "$(pwd)/data:/app/data" \
|
|
-v "$(pwd)/uploads:/app/uploads" \
|
|
val-friendbook
|
|
```
|
|
|
|
## Data
|
|
|
|
| Path | Contents |
|
|
| ------------------- | ------------------------------ |
|
|
| `data/entries.json` | All entries (pending + approved) |
|
|
| `uploads/` | Uploaded badge images |
|
|
|
|
Both are created automatically on first start and are excluded from git. Back them up or mount them as volumes so entries survive restarts and redeploys.
|
|
|
|
## Admin panel
|
|
|
|
Open `/admin` and log in with `ADMIN_PASSWORD`. From there you can approve or deny pending entries.
|
|
|
|
## API
|
|
|
|
| Method | Route | Auth | Description |
|
|
| ------ | ---------------------------------- | ----- | ---------------------------------------- |
|
|
| GET | `/api/entries` | - | List approved entries |
|
|
| POST | `/api/entries` | - | Submit a new entry (multipart, `badges`) |
|
|
| POST | `/api/admin/login` | admin | Check the admin password |
|
|
| GET | `/api/admin/entries` | admin | List all entries |
|
|
| POST | `/api/admin/entries/:id/approve` | admin | Approve an entry |
|
|
| POST | `/api/admin/entries/:id/deny` | admin | Delete an entry and its images |
|
|
|
|
Admin routes expect the password in the `x-admin-password` header.
|
|
|
|
## Project structure
|
|
|
|
```
|
|
.
|
|
├── server.js # Express backend, JSON storage, admin routes
|
|
├── public/ # Frontend (index, admin panel, styles, scripts)
|
|
├── Dockerfile
|
|
└── package.json
|
|
```
|
|
|
|
## Notes
|
|
|
|
- The admin password is sent in a header on every admin request. Run the app behind HTTPS (reverse proxy or tunnel) when exposing it publicly.
|
|
- Entries are stored in a single JSON file, which is fine for a small friend group but not meant for large scale, any help with this is appreciated, since I can't code for shit
|
|
|
|
## Enjoy! :3 |