Updated README.md with project description and deployment instructions
This commit is contained in:
parent
adf4ab5d92
commit
78ec0debf6
273
README.md
273
README.md
@ -1,3 +1,272 @@
|
||||
# mnemosyne
|
||||
# Mnemosyne
|
||||
|
||||
Task manager to help remember periodic or upcoming tasks with Telegram front-end.
|
||||
A self-hosted, single-user task manager built around long-timeframe recurring tasks. Its job is to keep things **on the radar** — recurring obligations, periodic maintenance, and someday/maybe items — without the bloat of a full project management system.
|
||||
|
||||
The primary interface is a Telegram bot. Every morning it delivers a **Day at a Glance** digest: what's overdue, what's due today, what's coming up in the next week, and a rotation of floating reminders. Everything else is query-on-demand. No mid-day push notifications, ever.
|
||||
|
||||
The name is Mnemosyne — the Greek personification of memory. The app remembers so you don't have to.
|
||||
|
||||
---
|
||||
|
||||
## Task classes
|
||||
|
||||
Five scheduling models cover most recurring-task patterns:
|
||||
|
||||
| Class | Description | Example |
|
||||
|---|---|---|
|
||||
| `monthly_date` | Fixed day of the month | Pay rent on the 1st |
|
||||
| `monthly_weekday` | Nth weekday of the month | First Thursday, last Friday |
|
||||
| `every_n_period` | Every N days/weeks/months from an anchor date | Every 2 weeks from 2026-01-06 |
|
||||
| `interval` | Every N days, clock resets on completion | Change oil every 90 days |
|
||||
| `floating` | No fixed date; surfaces by priority rotation | Call parents, learn Spanish |
|
||||
|
||||
Missed dated tasks roll into an **Overdue** section rather than disappearing. Slippage is a feature, not an error.
|
||||
|
||||
---
|
||||
|
||||
## Telegram commands
|
||||
|
||||
| Command | What it does |
|
||||
|---|---|
|
||||
| `/today` or `/glance` | Day at a Glance digest on demand |
|
||||
| `/list [filter]` | Browse tasks; filter by class, priority, or `inactive` |
|
||||
| `/add` | Create a task via guided wizard |
|
||||
| `/done <id\|title>` | Mark a task complete |
|
||||
| `/edit <id> <field> <value>` | Update a single field |
|
||||
| `/disable <id\|title>` | Hide a task without deleting it |
|
||||
| `/delete <id\|title>` | Permanently delete (with confirmation) |
|
||||
| `/settime HH:MM` | Change the morning digest delivery time |
|
||||
| `/help` | List commands |
|
||||
|
||||
Actionable tasks in digests and list results get inline **Mark Done** buttons. Tapping one completes the task immediately and replaces the button with **Undo** in case of misclicks.
|
||||
|
||||
---
|
||||
|
||||
## Stack
|
||||
|
||||
- **Perl** — application logic
|
||||
- **SQLite** — single-file database via `DBD::SQLite`; WAL mode
|
||||
- **Mojolicious** — webhook receiver and outbound Telegram API calls (`Mojo::UserAgent`)
|
||||
- **nginx** — TLS termination and reverse proxy; bot binds to localhost only
|
||||
- **systemd** — long-running webhook service with `Restart=always`
|
||||
- **cron** — morning digest (runs every 5 minutes; the script checks the configured time)
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A Linux server with a public IP (AlmaLinux 10 / RHEL family recommended; Debian/Ubuntu also supported)
|
||||
- A domain or subdomain with an A record pointing at the server
|
||||
- A Telegram bot token from [@BotFather](https://t.me/BotFather)
|
||||
- Your Telegram chat ID ([@userinfobot](https://t.me/userinfobot) will tell you)
|
||||
- Perl 5.26+, nginx, certbot, sqlite3
|
||||
|
||||
---
|
||||
|
||||
## Deployment
|
||||
|
||||
### 1. Clone the repo
|
||||
|
||||
```bash
|
||||
git clone https://git.castlehollow.com/rodger/mnemosyne.git
|
||||
cd mnemosyne
|
||||
```
|
||||
|
||||
### 2. Run the install script
|
||||
|
||||
Must be run as root. Safe to re-run — it will not overwrite an existing database or config file.
|
||||
|
||||
```bash
|
||||
sudo bash scripts/install.sh
|
||||
```
|
||||
|
||||
This will:
|
||||
- Install system packages (Perl, cpanminus, sqlite3, gcc) via `dnf` or `apt-get`
|
||||
- Install CPAN dependencies from `cpanfile` via `cpanm`
|
||||
- Create a `mnemosyne` system user and group
|
||||
- Deploy application files to `/opt/mnemosyne`
|
||||
- Install the systemd service (enabled but **not started** until you configure it)
|
||||
- Install a cron job at `/etc/cron.d/mnemosyne` for the digest and daily backup
|
||||
|
||||
Default paths (override with flags if needed):
|
||||
|
||||
| Flag | Default |
|
||||
|---|---|
|
||||
| `--app-dir` | `/opt/mnemosyne` |
|
||||
| `--config-dir` | `/etc/mnemosyne` |
|
||||
| `--data-dir` | `/var/lib/mnemosyne` |
|
||||
|
||||
### 3. Edit the config file
|
||||
|
||||
```bash
|
||||
sudo nano /etc/mnemosyne/mnemosyne.conf
|
||||
```
|
||||
|
||||
Fields to fill in:
|
||||
|
||||
```ini
|
||||
[bot]
|
||||
token = YOUR_BOT_TOKEN_HERE # from @BotFather
|
||||
webhook_secret = ... # openssl rand -hex 32
|
||||
webhook_url = https://bot.example.com/hook/YOUR_RANDOM_PATH
|
||||
listen_port = 8765
|
||||
allowed_chat_ids = 123456789 # your Telegram chat ID
|
||||
|
||||
[db]
|
||||
path = /var/lib/mnemosyne/mnemosyne.db
|
||||
|
||||
[app]
|
||||
timezone = America/New_York # any IANA timezone name
|
||||
digest_time = 06:30
|
||||
```
|
||||
|
||||
The `webhook_url` path segment (`/hook/YOUR_RANDOM_PATH`) should be a hard-to-guess string — it acts as a second layer of security alongside the `webhook_secret` header. Generate one with `openssl rand -hex 16`.
|
||||
|
||||
### 4. Configure nginx
|
||||
|
||||
Copy the example config and adjust the server name and port:
|
||||
|
||||
```bash
|
||||
sudo cp /opt/mnemosyne/nginx/mnemosyne.conf.example \
|
||||
/etc/nginx/conf.d/mnemosyne.conf
|
||||
sudo nano /etc/nginx/conf.d/mnemosyne.conf
|
||||
# Replace mnemosyne.example.com with your subdomain
|
||||
# Replace 8765 with your listen_port if you changed it
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### 5. Obtain a TLS certificate
|
||||
|
||||
Telegram requires HTTPS. Use certbot:
|
||||
|
||||
```bash
|
||||
sudo certbot --nginx -d bot.example.com
|
||||
```
|
||||
|
||||
Verify the nginx config still works after certbot modifies it:
|
||||
|
||||
```bash
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
### 6. Start the bot
|
||||
|
||||
```bash
|
||||
sudo systemctl start mnemosyne-bot
|
||||
sudo systemctl status mnemosyne-bot
|
||||
sudo journalctl -u mnemosyne-bot -f
|
||||
```
|
||||
|
||||
### 7. Register the Telegram webhook
|
||||
|
||||
This tells Telegram where to send updates. Run it once, and again any time the `webhook_url` changes:
|
||||
|
||||
```bash
|
||||
sudo -u mnemosyne /opt/mnemosyne/bin/mnemosyne-webhook \
|
||||
--config /etc/mnemosyne/mnemosyne.conf
|
||||
```
|
||||
|
||||
To remove the webhook (e.g. before switching servers):
|
||||
|
||||
```bash
|
||||
sudo -u mnemosyne /opt/mnemosyne/bin/mnemosyne-webhook \
|
||||
--config /etc/mnemosyne/mnemosyne.conf --delete
|
||||
```
|
||||
|
||||
### 8. Verify
|
||||
|
||||
Send `/today` to your bot. You should receive a digest (or an "all clear" message if no tasks are due).
|
||||
|
||||
---
|
||||
|
||||
## AlmaLinux / RHEL-specific notes
|
||||
|
||||
**SELinux** — if nginx cannot connect to the local bot port, allow it:
|
||||
|
||||
```bash
|
||||
sudo setsebool -P httpd_can_network_connect 1
|
||||
```
|
||||
|
||||
**Firewall** — the bot port (`8765` by default) does not need to be open to the internet; nginx proxies to it locally. Only ports 80 and 443 need to be reachable.
|
||||
|
||||
**Perl modules** — some CPAN modules require `perl-devel` and `gcc` for XS compilation. The install script handles this, but if you install manually:
|
||||
|
||||
```bash
|
||||
sudo dnf install -y perl-devel gcc make
|
||||
sudo cpanm --notest --installdeps .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backup and restore
|
||||
|
||||
The install script sets up a daily backup cron at 02:15. You can also run it manually:
|
||||
|
||||
```bash
|
||||
sudo -u mnemosyne /opt/mnemosyne/scripts/backup.sh \
|
||||
--config /etc/mnemosyne/mnemosyne.conf
|
||||
```
|
||||
|
||||
Backups land in `/var/backups/mnemosyne/` and are retained for 30 days by default. Override with `--keep-days N`.
|
||||
|
||||
The backup uses SQLite's Online Backup API, so it's safe to run while the bot is live — no downtime required.
|
||||
|
||||
**Restore:**
|
||||
|
||||
```bash
|
||||
sudo systemctl stop mnemosyne-bot
|
||||
sudo cp /var/backups/mnemosyne/mnemosyne-YYYYMMDD-HHMMSS.db \
|
||||
/var/lib/mnemosyne/mnemosyne.db
|
||||
sudo chown mnemosyne:mnemosyne /var/lib/mnemosyne/mnemosyne.db
|
||||
sudo systemctl start mnemosyne-bot
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
cd /path/to/mnemosyne-repo
|
||||
git pull
|
||||
sudo bash scripts/install.sh # re-runs safely; does not touch config or database
|
||||
sudo systemctl restart mnemosyne-bot
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Repository layout
|
||||
|
||||
```
|
||||
mnemosyne/
|
||||
├── bin/
|
||||
│ ├── mnemosyne-bot # webhook receiver (Mojolicious app, run by systemd)
|
||||
│ ├── mnemosyne-digest # morning digest sender (run by cron)
|
||||
│ └── mnemosyne-webhook # one-shot webhook registration helper
|
||||
├── lib/Mnemosyne/
|
||||
│ ├── Config.pm # INI config loader
|
||||
│ ├── DB.pm # SQLite connection, schema, migration
|
||||
│ ├── Digest.pm # Day at a Glance builder and renderer
|
||||
│ ├── Schedule.pm # per-class due/overdue/upcoming resolver
|
||||
│ ├── Task.pm # task CRUD + completions
|
||||
│ ├── Telegram.pm # Bot API client and keyboard factories
|
||||
│ └── Webhook.pm # update routing, command and callback handlers
|
||||
├── config/
|
||||
│ └── mnemosyne.conf.example
|
||||
├── nginx/
|
||||
│ └── mnemosyne.conf.example
|
||||
├── scripts/
|
||||
│ ├── backup.sh
|
||||
│ ├── install.sh
|
||||
│ └── print-digest # debug: render a digest to the terminal
|
||||
├── share/
|
||||
│ └── schema.sql
|
||||
├── systemd/
|
||||
│ └── mnemosyne-bot.service
|
||||
└── t/ # test suite
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
Loading…
Reference in New Issue
Block a user