- TypeScript 48.2%
- Python 47.5%
- HTML 2.7%
- Dockerfile 1.6%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .forgejo/workflows | ||
| frontend | ||
| templates | ||
| tests | ||
| .dockerignore | ||
| .gitignore | ||
| config.example.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| main.py | ||
| README.md | ||
| requirements-dev.txt | ||
| requirements.txt | ||
Poemata Editor
A lightweight web application for managing text files with a RESTful API and web interface. Built with FastAPI and React (using Vite as the bundler).
Features
- Web-based file management interface
- RESTful API for file operations
- File preview functionality with customizable templates
- Search and filter capabilities
- Responsive design
Project Structure
.
├── main.py # FastAPI application
├── requirements.txt # Python dependencies
├── storage/ # Directory for storing text files (created automatically)
├── templates/ # HTML templates for file preview
├── frontend/ # React frontend application (using Vite)
│ ├── dist/ # Built frontend files
│ ├── src/ # Source code
│ └── package.json # Node.js dependencies
└── README.md # This file
API Endpoints
File Management
GET /api/files/- List all files (with optional search query)GET /api/files/{filepath}- Read a filePOST /api/poems- Create a poem from a title (filename is derived from it)POST /api/files/{filepath}- Create a new filePUT /api/files/{filepath}- Update an existing fileDELETE /api/files/{filepath}- Delete a file
File Preview
GET /api/preview/{filepath}?template={template}- Preview a file using a specific HTML template
Authentication
GET /api/me- Session info (auth_enabled,email)GET /auth/login- Start OAuth loginGET /auth/callback- OAuth callback (configure this URL with the provider)GET /auth/logout- Sign out
Web Interface
GET /- Main web application
Authentication
OAuth login is configured in config.yml (copy from config.example.yml). Only emails listed in oauth.allowed_emails may sign in. Without a filled-in config.yml the app runs without login.
secret_key: "<random string>" # python -c "import secrets; print(secrets.token_urlsafe(32))"
base_url: "https://poemata.example.com"
oauth:
provider: google # "google" or "github"
client_id: "..."
client_secret: "..."
allowed_emails:
- someone@example.com
- Create an OAuth app with the provider, using
{base_url}/auth/callbackas the redirect URI - Set
base_urlwhen running behind a proxy so redirects use the public URL - All
/apiendpoints require login onceconfig.ymlis filled in
config.yml is gitignored. A custom path can be set with POEMATA_CONFIG; docker-compose.yml mounts config.yml into the container.
Getting Started
Prerequisites
- Python 3.8+
- Node.js (for frontend development)
Installation
- Clone the repository
- Install Python dependencies:
pip install -r requirements.txt - Run the application:
uvicorn main:app --reload
Frontend Development
The frontend is built with React and Vite:
- Navigate to the frontend directory:
cd frontend - Install dependencies:
npm install - Start the development server:
npm run dev - Build for production:
npm run build
Tests
Backend API tests live in tests/ and use pytest:
pip install -r requirements-dev.txt
python -m pytest
The CI workflow (.forgejo/workflows/docker-publish.yml) runs the tests and a
production frontend build before the Docker image is built and pushed, so a
failing test blocks the image.
Docker Deployment
The application includes a multi-stage Dockerfile that:
- Builds the React frontend using Node.js
- Serves the FastAPI backend with the built frontend
To run with Docker:
docker build -t poemata-editor .
docker run -p 8000:8000 poemata-editor
Or use docker-compose:
docker-compose up
Usage
- Access the web interface at
http://localhost:8000 - Use the API endpoints to manage files programmatically
- Preview files using the
/api/previewendpoint with appropriate templates
File Format
Text files should follow this structure:
- First line: Title
- Middle lines: Content
- Last line: Footer/Author information
New poems are created from a title: the title becomes the first line, the
filename is derived from it, and the footer is filled in from the optional
footer section of config.yml at creation time (so dates stay fixed):
footer:
template: "{authorname} {city} {date}"
author: "Jan Kowalski"
city: "Warszawa"
date_format: "%m.%d.%Y"
Placeholders: {author}/{authorname}, {city}, {date}/{date.now} (the
date can also be formatted inline, e.g. {date:%d.%m.%Y}). Without a footer
configuration the last line defaults to Stopka. Poems sharing a title are
listed as Title (1), Title (2), ...
Templates
HTML templates in the templates/ directory can be used to preview files with different styling. The template receives:
title: First line of the filecontent: Array of middle linesfooter: Last line of the file
Contributing
- Fork the repository
- Create a feature branch
- Commit your changes
- Push to the branch
- Create a pull request
License
This project is licensed under the MIT License.