Metadata-Version: 2.4
Name: overflask
Version: 0.10.0
Summary: Flask scaffolding CLI with component architecture and support for SQLAlchemy, Redis caching, async tasks, and Elasticsearch analytics
Author: rklaus
License-Expression: MIT
Project-URL: Repository, https://gitlab.com/overflask/overflask
Project-URL: Tracker, https://gitlab.com/overflask/overflask/-/issues
Project-URL: Changelog, https://gitlab.com/overflask/overflask/-/blob/main/CHANGELOG.md
Keywords: flask,scaffolding,cli,sqlalchemy,redis,elasticsearch,tasks,analytics
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Framework :: Flask
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
Classifier: Topic :: Software Development :: Code Generators
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Requires-Python: >=3.14
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click>=8.0
Requires-Dist: flask>=3.0
Requires-Dist: packaging>=24.0
Requires-Dist: python-dotenv>=1.0
Requires-Dist: sqlalchemy>=2.0
Requires-Dist: redis>=5.0
Requires-Dist: elasticsearch<9,>=8.0
Requires-Dist: croniter>=3.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-tmp-files>=0.0.2; extra == "dev"
Requires-Dist: ruff>=0.8; extra == "dev"
Requires-Dist: build>=1.0; extra == "dev"
Requires-Dist: twine>=5.0; extra == "dev"
Requires-Dist: alembic>=1.13; extra == "dev"
Dynamic: license-file

# overflask

A CLI tool that scaffolds Flask projects with component-based architecture, and a runtime library that adds SQLAlchemy models, Redis caching, async/recurring tasks, and Elasticsearch analytics on top of Flask.

## Create a project

Via Docker (no install required):

```bash
docker run --rm -it -u $(id -u):$(id -g) -v $(pwd):/workspace overflask/overflask create myapp
```

Or install and run locally:

```bash
pip install overflask @ git+https://gitlab.com/overflask/overflask.git
overflask create myapp
```

The CLI prompts for an initial component name and Postgres/Redis connection details, generates the project, pre-fills `.env`, and optionally starts the database containers.

```
myapp/
├── manage.py              # project CLI
├── settings.py            # configuration
├── pyproject.toml         # dependencies
├── compose.yaml           # Docker Compose
├── compose.override.yaml  # your volumes and services
├── conftest.py            # pytest fixtures
├── ops/
│   ├── env.template
│   ├── migrations/        # Alembic
│   └── setup-traefik.sh
├── overflask-docs/
└── components/
    └── myapp/
        ├── models.py
        ├── views.py
        ├── services.py
        ├── cli.py
        ├── tasks.py
        └── tests.py
```

## Add a component

```bash
python manage.py component add auth
```

Creates `components/auth/` with the same structure and registers it in `settings.COMPONENTS`.

## Upgrade a project

A generated project holds both the installed package and the files scaffolded from it.
Upgrading moves both:

```bash
pip install -e ".[dev]"   # after bumping the pin in pyproject.toml
overflask sync            # bring scaffolded files up to the installed version
```

Then review [CHANGELOG.md](CHANGELOG.md) and update `VERIFIED_OVERFLASK_VERSION` in
`settings.py` — overflask warns on every debug-mode start while it trails the installed
version.

`sync` overwrites the framework-owned files (`manage.py`, `compose.yaml`, `pyproject.toml`,
`conftest.py`, the Alembic config, `overflask-docs/`) and merges `.env` and
`ops/env.template` at their `### IMPORTANT` marker, keeping existing values. It never
rewrites `settings.py`, `README.md` or `compose.override.yaml`. See the *Upgrading
overflask* section of `overflask-docs/README-overflask.md` in a generated project for the
full breakdown.

## Runtime library

Generated projects import directly from `overflask`:

### Views

Blueprints declared in a component's `views.py` are discovered and registered automatically — no wiring needed:

```python
from flask import Blueprint

auth_bp = Blueprint("auth", __name__, url_prefix="/auth")

@auth_bp.route("/health")
def health():
    return {"status": "ok"}
```

For REST APIs, generated projects ship with [rest-canvas](https://gitlab.com/overflask/rest-canvas), which drives routing and validation from an OpenAPI spec. `RestCanvas` instances are discovered the same way — declare one and decorate your endpoints, and overflask registers the routes:

```python
from rest_canvas import RestCanvas, Request, PagePagination

api = RestCanvas("openapi.yaml", mount_point="/api/v1")

@api.endpoint("GET /users")
def list_users(request: Request[PagePagination]):
    return [u.to_json_object() for u in query_users(request.pagination)]
```

No `register_flask_routes()` call — overflask owns the app and does it for you.

See `overflask-docs/rest-canvas.md` in a generated project for the full feature set.

### Models

```python
from overflask import ModelBase
from sqlalchemy.orm import Mapped, mapped_column

class User(ModelBase):
    # __tablename__ auto-set to "auth_users"
    id: Mapped[int] = mapped_column(primary_key=True)
    email: Mapped[str] = mapped_column(String(255), unique=True)
```

Table names are derived automatically as `{component}_{plural_snake_case_model_name}`.

### Redis cache

```python
from overflask import cached

@cached(ttl=300)
def get_user(user_id: int):
    ...
```

Backed by Redis db 15 with stampede prevention via locking.

### Async tasks

```python
from overflask import async_task

@async_task
def send_welcome_email(user_id: int, email: str) -> None:
    ...

# Enqueue immediately or with a delay
send_welcome_email.queue(user_id=42, email="alice@example.com")
send_welcome_email.queue(timedelta(minutes=5), user_id=42, email="alice@example.com")
```

### Recurring tasks

```python
from overflask import recurring_task

@recurring_task("0 9 * * MON-FRI")
def daily_report() -> None:
    ...
```

Tasks are stored in Elasticsearch and dispatched via Redis. Run the supporting processes:

```bash
python manage.py tasks scheduler   # polls ES, dispatches due tasks
python manage.py tasks worker      # executes tasks from Redis queue
```

### Analytics

```python
from overflask.analytics import Analytics

Analytics.record("user.registered", area="auth", plan="free")
Analytics.record("purchase.completed", area="billing", amount=99)
```

Events are buffered in-process and bulk-flushed to Elasticsearch in the background. Each `area` gets its own monthly index (`myapp_analytics_auth-2026.03`).

## Database migrations

```bash
python manage.py db migrate -m "add users table"
python manage.py db upgrade
python manage.py db downgrade 001
```

## Testing

```bash
pytest               # all tests
pytest -m unit       # unit tests only (no DB)
pytest -m integration
pytest -n auto       # parallel
```

Integration tests run against a real PostgreSQL instance using a cloned template database — fast isolation without `create_all()` per test. Redis is always replaced with fakeredis.

## Deployment

The generated project ships with a Gunicorn config and Traefik integration for HTTPS:

```bash
bash ops/setup-traefik.sh   # one-time Traefik setup per server
docker compose up -d
docker compose exec web python manage.py db upgrade
```

See `overflask-docs/traefik.md` and `overflask-docs/gunicorn.md` in the generated project for details.

## Development

```bash
pip install -e ".[dev]"
pytest
ruff check src/ tests/
ruff format src/ tests/
```
