A modern HTML-native preprint server for academic research documents. Built with FastAPI, Scroll Press accepts research from any authoring tool that produces HTML—Typst, Quarto, MyST, Jupyter, or handwritten HTML. Format freedom, instant publication, permanent URLs.
Governance: Press is fully community-owned—open source, community contributions accepted, roadmap driven by community needs, forever free. Supported by community donations and academic grants.
- HTML-native publishing: Upload complete HTML documents with embedded CSS and JavaScript
- Session-based authentication: Secure user registration and login system with email verification
- Email verification: Token-based email verification with password reset functionality
- GDPR compliance: Data export endpoint for user data portability (Article 20)
- Subject categorization: Organize research by academic disciplines
- Preview and publish workflow: Review uploads before publishing
- Scroll cards: Browse recent submissions with rich metadata
- Responsive design: Clean, academic-focused UI with HTMX interactions
- Performance optimized: Static file caching with CDN-ready headers
- Python 3.11+
- PostgreSQL database
- uv package manager
justto run common commandspandocfor building documentation (install:brew install pandocon macOS)
-
Clone the repository
git clone <repository-url> cd press
-
Set up environment
cp .env.example .env # Edit .env with your database URL, port, and email service credentialsRequired environment variables:
DATABASE_URL: PostgreSQL connection stringPORT: Server port (default: 7999)RESEND_API_KEY: API key for Resend email service (for email verification)FROM_EMAIL: Email address to send from (default: noreply@updates.aris.pub)BASE_URL: Base URL for email links (defaults to https://127.0.0.1:{PORT})
-
Initialize the project (REQUIRED)
just init
This command is essential for correct setup. It will:
- Install all Python dependencies
- Build documentation templates from markdown
- Run database migrations
- Seed the database with sample data
- Install git hooks (pre-commit linting)
Important: Always run
just initwhen setting up the repository for the first time or after pulling major changes. -
Start the development server
just dev
Visit https://localhost:7999 to access Scroll Press (HTTPS with self-signed certificate).
app/
├── auth/ # Session-based authentication and token management
│ ├── session.py # Session handling
│ └── tokens.py # Email verification and password reset tokens
├── emails/ # Email service integration
│ ├── service.py # Resend email service
│ └── templates.py # Email HTML templates
├── models/ # SQLAlchemy database models
│ ├── user.py # User model with email verification
│ ├── token.py # Token model for verification/reset
│ ├── scroll.py # Research manuscript model
│ └── subject.py # Academic subject categorization
├── routes/ # FastAPI route handlers
├── templates/ # Jinja2 templates with component macros
│ └── auth/ # Authentication templates (login, register, verify, reset)
└── database.py # Async database configuration
static/
├── css/ # Stylesheet
└── images/ # Static assets
docs/ # Documentation source (markdown)
├── quick-start.md # Quick start guide (source)
├── faq.md # FAQ (source)
├── docs-meta-template.html # Jinja wrapper template
└── build.sh # Build script (markdown → HTML templates)
tests/ # Comprehensive test suite
Documentation pages are written in Markdown and built into Jinja2 templates at build time:
Source files (edit these):
docs/quick-start.md- Quick start guidedocs/faq.md- Frequently asked questionsdocs/docs-meta-template.html- Wrapper template with Jinja blocks
Generated files (do not edit directly):
app/templates/docs/quick-start.html- Built from quick-start.mdapp/templates/docs/faq.html- Built from faq.md
When to build:
just buildRun this command whenever you:
- Edit any
.mdfile indocs/ - Edit
docs-meta-template.html - After pulling changes that modify documentation source
The build process uses pandoc to convert Markdown to HTML fragments, then injects them into the Jinja template wrapper. At runtime, these are served as normal Jinja templates with full access to base template styling and navigation.
- Backend: FastAPI with async/await patterns
- Database: PostgreSQL with SQLAlchemy 2.0 async
- Authentication: Session-based with in-memory storage and token-based email verification
- Email Service: Resend API for transactional emails (verification, password reset)
- Frontend: Jinja2 templates with HTMX for dynamic interactions
- Security: HTTPS-only development with self-signed certificates
- Testing: pytest with asyncio support, parallel execution, and Playwright e2e tests
- Database Setup & Models - Database configuration, migrations, and data models
- Authentication - Session management, email verification, and security
- GDPR Compliance - Data export and privacy features
- Testing - Unit, integration, and E2E testing guide
- Deployment - Production deployment instructions
- Backup Setup - Database backup configuration
- Run all checks:
just check(includes lint, unit tests, and e2e tests) - Follow existing patterns: Session-based auth, macro components, async/await
- Write tests: All new features should include test coverage
- Documentation changes: Edit
.mdfiles indocs/, then runjust build - Read the docs: See Testing Guide for testing best practices
Contributions are welcome! Please open an issue to discuss major changes before submitting a PR.
This project is licensed under the MIT License - see the LICENSE file for details.
For issues and questions, please use the GitHub issue tracker.