Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@

Thanks for helping improve Loreo. This guide captures the repo's current contribution flow and quality gates.

## Philosophy

Loreo is intentionally focused on calm, intentional reading and revisitability.
Feature proposals are evaluated against that philosophy; if it adds noise or moves
Loreo toward a general-purpose tool, it's probably not a fit. Open an issue to
discuss before building something substantial.

## Before You Start

- Read `README.md` for setup and repo structure.
- Check whether your change is already covered by an active plan under `docs/plans/` or `context/features/`.
- Keep secrets, credentials, and local environment values out of commits.

## Branches
Expand Down
52 changes: 41 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,23 @@

![Cover](./docs/images/cover.png)

Loreo is a read-it-later app for saving articles worth revisiting, built with self-hosting in mind
Loreo is a read-it-later app for saving articles worth revisiting, built with self-hosting in mind.

## Demo

[Demo](https://loreo-demo.onrender.com)

> The demo runs on a free tier Render instance, expect a cold start on first visit (~30s). Self-hosted instances don't have this limitation
> The demo is read-only, you can't save or edit articles
> The demo runs on a free tier Render instance, expect a cold start on first visit (~30s). Self-hosted instances don't have this limitation.
> The demo is read-only, you can't save or edit articles.

## Screenshots

<table>
<tr>
<td><img src="docs/images/reading-list.png" alt="Article list" /></td>
<td><img src="docs/images/reading-view.png" alt="Archive view" /></td>
</tr>
</table>

## Features

Expand Down Expand Up @@ -48,7 +57,7 @@ The goal is not productivity maximization, but creating a calmer relationship wi

## Why this exists

I was a [Pocket](https://getpocket.com) user for a decade, but they decided to [shut down their service](https://blog.mozilla.org/en/mozilla/building-whats-next/). I tried finding alternatives, but most of them either just bookmark links without actually saving the content, have cluttered dashboards, or have too many features that I don't need. So I decided to build a calm, focused read-it-later app that I could self-host myself
I was a [Pocket](https://getpocket.com) user for a decade, but they decided to [shut down their service](https://blog.mozilla.org/en/mozilla/building-whats-next/). I tried finding alternatives, but most of them either just bookmark links without actually saving the content, have cluttered dashboards, or have too many features that I don't need. So I decided to build a calm, focused read-it-later app that I could self-host myself.

## Behind the Name

Expand Down Expand Up @@ -91,11 +100,36 @@ This is a monorepo project using pnpm workspaces based on my [monorepo template]

## Note About Development

This project is built as a personal tool I use daily, with a focus on intentional design decisions over feature accumulation. I'm open to suggestions and contributions that align with that philosophy
This project is built as a personal tool I use daily, with a focus on intentional design decisions over feature accumulation. I'm open to suggestions and contributions that align with that philosophy.

## License & Philosophy

Loreo is open source because personal reading infrastructure should be inspectable,
moddable, and self-hostable; not locked behind a service that can shut down.
AGPL-3.0 ensures that hosted forks remain open to the community.

This means:

- You can self-host, modify, and use Loreo freely
- If you host a modified version for others, you must publish your changes under AGPL-3.0
- Commercial use requires a separate agreement

Loreo is not a permissive-licensed library. It is a product with a philosophy.

Licensed under [AGPL-3.0](LICENSE).

## Contributing

Contributions are welcome. Please open an issue before submitting a PR so we can
discuss the approach first. See [CONTRIBUTING.md](CONTRIBUTING.md) for more details.

Loreo is intentionally focused on calm, intentional reading and revisitability.
Feature proposals are evaluated against that philosophy — if it adds noise or moves
Loreo toward a general-purpose tool, it's probably not a fit.

## Acknowledgements

Open-source software and transparent architecture discussions helped Loreo tremendously during development, so proper attribution feels important
Open-source software and transparent architecture discussions helped Loreo tremendously during development, so proper attribution feels important.

- [Karakeep](https://github.com/karakeep-app/karakeep) — inspiration for how scraping works and self-hosting patterns

Expand Down Expand Up @@ -311,7 +345,7 @@ Loreo supports decoupling services for better scalability and reliability. You c
- **Redis**: For job queue and caching (e.g., Upstash)
- **Storage**: S3-compatible storage for images and other assets (e.g., Cloudflare R2)

I have tested this with Neon as the database provider, Upstash as the Redis provider, and Cloudflare R2 as the storage provider. To get the best performance, make sure each service's region is close to your server location
I have tested this with Neon as the database provider, Upstash as the Redis provider, and Cloudflare R2 as the storage provider. To get the best performance, make sure each service's region is close to your server location.

### Examples

Expand Down Expand Up @@ -342,7 +376,3 @@ STORAGE_SECRET_ACCESS_KEY=<your-cloudflare-r2-secret-access-key>

- Article extraction uses a Playwright-compatible Camoufox websocket configured by `BROWSER_URL`.
- Local storage is available by default; S3-compatible storage is supported through server env vars.

## License

Loreo is licensed under the [AGPL-3.0](LICENSE)
16 changes: 10 additions & 6 deletions docs/SELF_HOSTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This guide walks through deploying Loreo with Docker Compose, including domain s

![Loreo Architecture](./images/architecture.png)

Loreo's production stack consists of four containers:
Loreo's production stack consists of five containers:

| Service | Image | Role |
| ---------------- | ------------------------------------ | --------------------------------------- |
Expand All @@ -16,7 +16,9 @@ Loreo's production stack consists of four containers:
| `loreo-server` | `ghcr.io/technowizard/loreo-server` | Hono API, background jobs |
| `loreo-web` | `ghcr.io/technowizard/loreo-web` | Nginx + static React app |

The web container serves the React app through nginx and proxies API requests to the server. The server connects to Postgres, Redis, and the browser service internally. No services other than the web and server containers are exposed on host ports.
The web container serves the React app through nginx and proxies API requests to the server.

The server connects to Postgres, Redis, and the browser service internally. No services other than the web and server containers are exposed on host ports.

## Prerequisites

Expand Down Expand Up @@ -115,7 +117,7 @@ The server uses `STORAGE_PROVIDER: local-docker` by default, storing uploaded fi

### Web

The web container is **portable** — it does not require rebuilding when your deployment URL or server port changes. The browser calls the API on the same origin (through nginx's reverse proxy), and the nginx template resolves `${API_UPSTREAM}` at container startup.
The web container is portable: it does not require rebuilding when your deployment URL or server port changes. The browser calls the API on the same origin (through nginx's reverse proxy), and the nginx template resolves `${API_UPSTREAM}` at container startup.

The default `API_UPSTREAM=http://loreo-server:3000` works for standard Docker Compose deployments. You only need to change it if you rename the server service or run containers on different Docker networks.

Expand Down Expand Up @@ -206,22 +208,24 @@ Add these to the `loreo-server` environment block in `docker-compose.prod.yml`.

### Backup

Replace `<POSTGRES_USER>` and `<POSTGRES_DB>` with the values from your `.env.prod`.

```bash
docker exec loreo-prod-loreo-postgres-1 pg_dump -U loreo loreo > loreo-backup-$(date +%Y%m%d).sql
docker exec loreo-prod-loreo-postgres-1 pg_dump -U <POSTGRES_USER> <POSTGRES_DB> > loreo-backup-$(date +%Y%m%d).sql
```

### Restore

```bash
docker exec -i loreo-prod-loreo-postgres-1 psql -U loreo loreo < loreo-backup-YYYYMMDD.sql
docker exec -i loreo-prod-loreo-postgres-1 psql -U <POSTGRES_USER> <POSTGRES_DB> < loreo-backup-YYYYMMDD.sql
```

### Automated Backups

Add a cron job for daily backups:

```bash
0 2 * * * docker exec loreo-prod-loreo-postgres-1 pg_dump -U loreo loreo > /backups/loreo-$(date +\%Y\%m\%d).sql
0 2 * * * docker exec loreo-prod-loreo-postgres-1 pg_dump -U <POSTGRES_USER> <POSTGRES_DB> > /backups/loreo-$(date +\%Y\%m\%d).sql
```

## Updating
Expand Down
Binary file modified docs/images/cover.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/reading-list.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/reading-view.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.