base on Markdown note-taking web application designed for simplicity <p align="center">
<img src="art/logo.png" width="400" />
</p>
<p align="center">
<img alt="Latest version" src="https://img.shields.io/github/v/release/brufdev/many-notes?label=version" />
<img alt="PHP version" src="https://img.shields.io/badge/PHP-8.4-777BB4?logo=php" />
<img alt="Tests" src="https://img.shields.io/github/check-runs/brufdev/many-notes/main?label=tests" />
<img alt="License" src="https://img.shields.io/github/license/brufdev/many-notes" />
</p>
Many Notes is a Markdown note-taking web application designed for simplicity! Easily create or import your vaults and organize your thoughts right away.
It uses a database to power its features, but your files are also saved in the filesystem, giving you full control over your vault structure and making it easy to access or transfer your files to another application.
Vaults are simply storage containers for your files, and Many Notes lets you choose to keep all your files in one vault or organize them into separate vaults.
## Screenshots

*Light theme*

*Dark theme*
## Features
- **Multiple users**: Protect your files behind authentication
- **Multiple vaults per user**: Choose how to organize your files
- **OAuth support**: Authenticate using one of the supported providers
- **Collaboration**: Invite other users to access your vaults
- **Broadcasting**: Real-time, live-updating user interfaces
- **File search**: Experience a fast and typo-tolerant search
- **Tree view explorer**: Fast navigation with relevant actions in the context menu
- **Smart Markdown editor**: Write your Markdown notes faster
- **Automatic saving**: Focus on writing; saving is automatic
- **Templates**: Maintain consistent formatting for your notes
- **Links/backlinks/tags**: Improve note organization by connecting related notes
- **Import/export vaults**: Easily back up and restore your vaults
- **Starter vault**: Helps you get started with Many Notes
- **Light/dark theme**: Automatically selected based on your OS setting
- **Mobile friendly**: Provides a similar experience to the desktop
## Installation
Choose your preferred method to install Many Notes:
- Docker with volumes, for a simpler installation (read below)
- Docker with bind mounts, for easy access to shared paths from the host ([read here](docs/installation/docker-bind-mounts.md))
- Docker with a different database, if you prefer not to use SQLite ([read here](docs/installation/docker-different-database.md))
### Docker with volumes
**Read the [upgrading guide](UPGRADING.md) if you are upgrading from a previous version.**
Create a `compose.yaml` file with:
```yaml
services:
php:
image: brufdev/many-notes:latest
restart: unless-stopped
environment:
- APP_URL=http://localhost # change url
volumes:
- database:/var/www/html/database/sqlite
- logs:/var/www/html/storage/logs
- private:/var/www/html/storage/app/private
- typesense:/var/www/html/typesense
ports:
- 80:8080
volumes:
database:
logs:
private:
typesense:
```
Feel free to change anything else if you know what you're doing, and read the customization section below before continue. Then run:
```shell
docker compose up -d
```
## Customization
To customize Many Notes, add environment variables to the `compose.yaml` file if using the Docker installation. If you chose the non-Docker installation, you should add the environment variables to the `.env` file instead.
### Custom URL (default: http://localhost)
If you change the default port from 80 or use a reverse proxy with a custom URL, make sure to configure the application URL accordingly. For example, if you change the port to 8080, add:
```yaml
environment:
- APP_URL=http://localhost:8080
```
### Custom timezone (default: UTC)
Check all available timezones [here](https://www.php.net/manual/en/timezones.php). For example, if you want to set the timezone to Amsterdam, add:
```yaml
environment:
- APP_TIMEZONE=Europe/Amsterdam
```
### Custom upload size limit (default: 500M)
Increase the upload size limit to allow for the import of larger files. For example, if you want to increase the limit to 1 GB, add:
```yaml
environment:
- PHP_POST_MAX_SIZE=1G
- PHP_UPLOAD_MAX_FILE_SIZE=1G
```
### Registration enabled (default: true)
In case you want to disable registration for new users, add:
```yaml
environment:
- SETTINGS_REGISTRATION_ENABLED=false
```
### Enable OAuth providers
Many Notes supports a convenient way to authenticate with OAuth providers. Typically, these credentials may be retrieved by creating a "developer application" within the dashboard of the service you wish to use. Many Notes currently supports authentication via Facebook, Twitter, LinkedIn, Google, GitHub, GitLab, Bitbucket, Slack, Authelia, Authentik, Keycloak, and Zitadel. You can enable multiple providers simultaneously by adding the corresponding environment variables.
For example, to enable GitHub OAuth, add:
```yaml
environment:
- GITHUB_CLIENT_ID=CLIENT_ID # change id
- GITHUB_CLIENT_SECRET=CLIENT_SECRET # change secret
- GITHUB_REDIRECT_URI=http://localhost/oauth/github/callback # change domain and provider
```
Authelia, Authentik, Keycloak, and Zitadel providers require additional configuration. Read the [OAuth documentation](docs/customization/oauth.md) for more information.
### Custom email service
Configure an email service to send registration and password reset emails by adding:
```yaml
environment:
- MAIL_MAILER=smtp
- MAIL_HOST=127.0.0.1
- MAIL_PORT=2525
- MAIL_USERNAME=null
- MAIL_PASSWORD=null
- MAIL_ENCRYPTION=null
-
[email protected]
- MAIL_FROM_NAME="Many Notes"
```
## Frequently Asked Questions
Read the [FAQs](docs/support/faqs.md) to find the answers to the most common questions.
## License
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for the full license text.
", Assign "at most 3 tags" to the expected json: {"id":"13974","tags":[]} "only from the tags list I provide: [{"id":77,"name":"3d"},{"id":89,"name":"agent"},{"id":17,"name":"ai"},{"id":54,"name":"algorithm"},{"id":24,"name":"api"},{"id":44,"name":"authentication"},{"id":3,"name":"aws"},{"id":27,"name":"backend"},{"id":60,"name":"benchmark"},{"id":72,"name":"best-practices"},{"id":39,"name":"bitcoin"},{"id":37,"name":"blockchain"},{"id":1,"name":"blog"},{"id":45,"name":"bundler"},{"id":58,"name":"cache"},{"id":21,"name":"chat"},{"id":49,"name":"cicd"},{"id":4,"name":"cli"},{"id":64,"name":"cloud-native"},{"id":48,"name":"cms"},{"id":61,"name":"compiler"},{"id":68,"name":"containerization"},{"id":92,"name":"crm"},{"id":34,"name":"data"},{"id":47,"name":"database"},{"id":8,"name":"declarative-gui "},{"id":9,"name":"deploy-tool"},{"id":53,"name":"desktop-app"},{"id":6,"name":"dev-exp-lib"},{"id":59,"name":"dev-tool"},{"id":13,"name":"ecommerce"},{"id":26,"name":"editor"},{"id":66,"name":"emulator"},{"id":62,"name":"filesystem"},{"id":80,"name":"finance"},{"id":15,"name":"firmware"},{"id":73,"name":"for-fun"},{"id":2,"name":"framework"},{"id":11,"name":"frontend"},{"id":22,"name":"game"},{"id":81,"name":"game-engine "},{"id":23,"name":"graphql"},{"id":84,"name":"gui"},{"id":91,"name":"http"},{"id":5,"name":"http-client"},{"id":51,"name":"iac"},{"id":30,"name":"ide"},{"id":78,"name":"iot"},{"id":40,"name":"json"},{"id":83,"name":"julian"},{"id":38,"name":"k8s"},{"id":31,"name":"language"},{"id":10,"name":"learning-resource"},{"id":33,"name":"lib"},{"id":41,"name":"linter"},{"id":28,"name":"lms"},{"id":16,"name":"logging"},{"id":76,"name":"low-code"},{"id":90,"name":"message-queue"},{"id":42,"name":"mobile-app"},{"id":18,"name":"monitoring"},{"id":36,"name":"networking"},{"id":7,"name":"node-version"},{"id":55,"name":"nosql"},{"id":57,"name":"observability"},{"id":46,"name":"orm"},{"id":52,"name":"os"},{"id":14,"name":"parser"},{"id":74,"name":"react"},{"id":82,"name":"real-time"},{"id":56,"name":"robot"},{"id":65,"name":"runtime"},{"id":32,"name":"sdk"},{"id":71,"name":"search"},{"id":63,"name":"secrets"},{"id":25,"name":"security"},{"id":85,"name":"server"},{"id":86,"name":"serverless"},{"id":70,"name":"storage"},{"id":75,"name":"system-design"},{"id":79,"name":"terminal"},{"id":29,"name":"testing"},{"id":12,"name":"ui"},{"id":50,"name":"ux"},{"id":88,"name":"video"},{"id":20,"name":"web-app"},{"id":35,"name":"web-server"},{"id":43,"name":"webassembly"},{"id":69,"name":"workflow"},{"id":87,"name":"yaml"}]" returns me the "expected json"