# RustPad RustPad is a collaborative Markdown editor with standalone notes and workspaces. ## Development setup ```bash ./dev.sh ``` The script creates `data/db` and `data/files`, builds the project, and starts it with Cargo. If Cargo is unavailable, it runs `docker compose up --build` instead. ## Workspace features - Real-time collaborative editing over WebSocket. - Nicknames stored in `localStorage`. - Change authors shown in history. - Line numbering enabled by default, with a persistent toggle. - Owner color displayed next to each line. - Image and file uploads to `data/files/pads/_/` or `data/files/notes/_/`. - Automatic Markdown link insertion after upload. - Markdown and Mermaid diagram rendering. - History with snippets, previews, and version restore. - Alert blocks: `success`, `info`, `warning`, and `danger`. - Table of contents generated with `[TOC]`. - Optional line numbers in fenced code blocks. ## Fenced code blocks and language aliases RustPad recognizes common language names and aliases, including: - JavaScript: `js`, `javascript`, `jsx` - TypeScript: `ts`, `typescript`, `tsx` - Python: `py`, `python` - PHP: `php` - Rust: `rs`, `rust` - Shell: `sh`, `shell`, `bash`, `zsh` - C and C++: `c`, `h`, `cpp`, `c++`, `cxx`, `hpp` - C#: `cs`, `c#`, `csharp` - Java, Kotlin, Go, Swift, Dart, Scala - HTML, XML, SVG, CSS, SCSS, Sass, Less - JSON, YAML, TOML, INI, SQL, GraphQL - Markdown, Dockerfile, Makefile, PowerShell - Lua, Perl, R, MATLAB, Nginx, Apache, Diff, and plain text Standard code block: ````markdown ```python print("Hello") ``` ```` Code block with line numbers starting from line 1: ````markdown ```python= print("Hello") ``` ```` Code block with line numbers starting from a custom value: ````markdown ```python=101 print("Hello") ``` ```` The `=number` suffix is a RustPad extension and may not be supported by other Markdown renderers. ## Data - SQLite database: `data/db/rustpad.db` - Attachments: `data/files/pads/_/` and `data/files/notes/_/` - Public attachment URL: `/f//` In Docker, both directories are located under `/data`. ## Publishing a note as a page Use the **Page** button in the editor. RustPad creates a permanent public `/s/` URL, copies it to the clipboard, and opens it in a new tab. The page displays the current note and renders Markdown, images, links, and Mermaid diagrams. Publishing a protected note requires its password, but the generated public page itself is accessible without that password. ## Upload limit Configure the maximum size of a single uploaded file with `UPLOAD_MAX_SIZE_MB` in `.env`, for example: ```env UPLOAD_MAX_SIZE_MB=50 ``` The default limit is 20 MB. Restart the project with `./dev.sh` after changing it. ## Database selection RustPad selects the database engine through `DATABASE_URL`: - SQLite: `sqlite:///data/db/rustpad.db?mode=rwc&journal_mode=WAL&busy_timeout=5000` - PostgreSQL: `postgres://rustpad:rustpad@postgres:5432/rustpad` - MySQL: `mysql://rustpad:rustpad@mysql:3306/rustpad` SQLite remains the default for development and small installations. WAL mode allows reads during writes, but SQLite still performs only one write at a time. `busy_timeout=5000` waits briefly instead of immediately returning a `database is locked` error. PostgreSQL or MySQL is recommended for many concurrent editors or multiple application instances. Optional databases in Docker Compose: ```bash # PostgreSQL docker compose --profile postgres up -d postgres DATABASE_URL=postgres://rustpad:rustpad@postgres:5432/rustpad docker compose up -d rustpad # MySQL docker compose --profile mysql up -d mysql DATABASE_URL=mysql://rustpad:rustpad@mysql:3306/rustpad docker compose up -d rustpad ``` Migrations are stored in `migrations/sqlite`, `migrations/postgres`, and `migrations/mysql`. Runtime SQL statements are centralized in `src/queries.rs`, while `src/database.rs` selects the driver and configures the connection. ## Optional user accounts and password reset Nicknames can be used anonymously while they remain unregistered. Registering a nickname reserves it and requires a valid login session before it can be used in editor WebSocket connections. Configure `PUBLIC_URL`, `SMTP_HOST`, `SMTP_PORT`, `SMTP_USERNAME`, `SMTP_PASSWORD`, and `SMTP_FROM` to enable password-reset emails. Reset links expire after 30 minutes and can be used only once. ## Diagnostics and logging Server logs use `tracing`. Configure verbosity with `RUST_LOG`, for example: ```env RUST_LOG=rustpad=debug,tower_http=info ``` Important lifecycle, database, authentication, password-reset, and WebSocket events are logged. Passwords, session tokens, reset tokens, SMTP credentials, and authorization headers are never logged. Browser diagnostics are configured separately with `FRONTEND_LOG_LEVEL`. Supported values are `off`, `error`, `warn`, `info`, and `debug`; the default is `warn`. URL parameters cannot enable diagnostics. Use `debug` only in trusted development environments. Production should normally use `warn` or `error`. ## Registration and SMTP Set `REGISTRATION_ENABLED=true` to enable registration. After an account is created, the application sends an SMTP message containing the nickname and `PUBLIC_URL`. Set `ACCOUNT_CONFIRMATION_REQUIRED=true` to require users to click a confirmation link before signing in. This option is disabled by default and requires SMTP configuration. ## Attachment storage RustPad supports two interchangeable attachment backends selected in `.env`: - `STORAGE_DRIVER=local` stores files under `FILES_DIR` and is the default. - `STORAGE_DRIVER=s3` uses an S3-compatible service such as AWS S3, Garage, Ceph RGW, OpenStack, or MinIO. Public application URLs remain `/f/{token}/{filename}` for both backends. RustPad validates access and streams objects through the API, so the bucket does not need to be public and existing database records do not require migration. For the optional Docker Garage service, configure the S3 variables shown in `.env.example`, use strong unique credentials, and run: ```sh docker compose --profile s3 up -d --build ``` Garage runs as a separate Compose service. Existing PostgreSQL and MySQL profiles remain unchanged. The included single-node setup is intended for local or self-hosted development without redundancy. Production Garage deployments should use a properly designed multi-node configuration.