**Microblog** is a Flask-based social networking application following the application factory pattern with a modular blueprint architecture. The application is started from `microblog.py`, which calls `create_app()` in `app/__init__.py` to build the Flask instance, initialize all extensions, register blueprints, and wire up background task infrastructure.
The system is organized into four main blueprint modules — **auth** (registration, login, password reset), **main** (primary feed and profile views), **api** (REST endpoints, token auth), and **errors** (HTTP error handlers) — plus service modules for background jobs, full-text search, email delivery, and translation. Configuration is centralized in `config.py`, loaded from environment variables / `.env`.
The **data layer** lives in `app/models.py`: SQLAlchemy models (`User`, `Post`, `Message`, `Notification`, `Task`) augmented by two mixins — `SearchableMixin` (hooks `before_commit`/`after_commit` to keep Elasticsearch in sync) and `PaginatedAPIMixin` (provides `to_collection_dict` for paginated REST responses). API clients authenticate via bearer tokens stored on the `User` model; browser clients use Flask-Login sessions.
**Background work** (e.g. exporting posts) runs as RQ jobs enqueued into Redis. `app/tasks.py` defines the job handlers, `app/search.py` wraps Elasticsearch, `app/translate.py` calls the Microsoft Translator API, and `app/email.py` dispatches mail through a background thread to avoid blocking request handling.
---
---
| File | Purpose | Notes |
|---|---|---|
| `microblog.py` | Entry point & Flask shell context | Exposes `app`, `db`, `User`, `Post` etc. in `flask shell` |
| `config.py` | Centralised `Config` class | Reads all settings from env / `.env`; SQLite fallback for DB |
| `app/__init__.py` | App factory (`create_app`) | Initialises extensions, registers blueprints, configures logging |
| `app/models.py` | All SQLAlchemy models + mixins | `SearchableMixin` wires ES; `PaginatedAPIMixin` powers REST lists |
| `app/api/users.py` | REST CRUD for users | Token-authenticated; `update_user` enforces ownership |
| `app/api/auth.py` | HTTP Basic + Bearer token auth | `token_auth` used to protect every API endpoint |
| `app/api/tokens.py` | Token issue / revoke | `POST /api/tokens` → token; `DELETE /api/tokens` → revoke |
| `app/auth/routes.py` | Browser auth flows | Login, register, password-reset request, password-reset confirm |
| `app/main/routes.py` | Main app views | Index feed, user profile, follow/unfollow, messages, notifications |
| `app/errors/handlers.py` | Error pages | Custom HTML (browser) and JSON (API) for 404 / 500 |
| `app/email.py` | Email dispatch | Sends via background thread to avoid blocking; uses Flask-Mail |
| `app/tasks.py` | Background RQ jobs | `export_posts` example; updates job progress via RQ meta |
| `app/search.py` | Elasticsearch wrapper | `add_to_index`, `remove_from_index`, `query_index` |
| `app/translate.py` | Translation helper | Calls Microsoft Translator REST API; requires `MS_TRANSLATOR_KEY` |
| `app/cli.py` | CLI blueprint | `flask translate init/update/compile` wrappers around pybabel |
| File | Function | Complexity | Git Churn | Has Test? | Risk Score |
|---|---|---|---|---|---|
| app\api\users.py | update_user | 8 | 0 | ❌ | 0.7 |
| config.py | Config | 5 | 11 | ✅ | 0.6667 |
| app\models.py | after_commit | 7 | 0 | ❌ | 0.6 |
| app\__init__.py | create_app | 10 | 0 | ✅ | 0.6 |
| app\auth\routes.py | login | 7 | 0 | ❌ | 0.6 |
| app\api\users.py | create_user | 6 | 0 | ❌ | 0.5 |
| app\models.py | PaginatedAPIMixin | 5 | 0 | ❌ | 0.4 |
| app\models.py | from_dict | 5 | 0 | ❌ | 0.4 |
| app\main\routes.py | index | 5 | 0 | ❌ | 0.4 |
| microblog.py | make_shell_context | 1 | 6 | ❌ | 0.3273 |
| app\email.py | send_email | 4 | 0 | ❌ | 0.3 |
| app\models.py | SearchableMixin | 4 | 0 | ❌ | 0.3 |
| app\models.py | to_collection_dict | 4 | 0 | ❌ | 0.3 |
| app\translate.py | translate | 4 | 0 | ❌ | 0.3 |
| app\auth\routes.py | reset_password_request | 4 | 0 | ❌ | 0.3 |
Files checked against code: `app/__init__.py`, `app/auth/routes.py`,
`app/main/routes.py`, `app/api/users.py`, `requirements.txt`, `tests.py`,
`.flaskenv`.
---
Each candidate finding was verified by running the code before being included.
All three candidates were invalidated:
| Candidate | Claim | Actual behaviour |
|---|---|---|
| `requirements.txt` Flask-Mail 0.9.1 + Flask 3.0 | `from flask_mail import Mail` would raise `ImportError` | Import succeeds — Flask-Mail 0.9.1 works under Flask 3.0 in this environment |
| `tests.py` missing Redis stub | `create_app()` raises `ConnectionError` without Redis | `redis.Redis.from_url()` and `rq.Queue()` are lazy; they construct without a live server and only fail on the first actual command |
| `.flaskenv` `FLASK_DEBUG=1` | Logger has no handlers, all output silently dropped | Flask's own debug mode attaches a `StreamHandler` to stderr; `app.logger` is never silent |
The README contains no technical claims to contradict. The deployment files
(`Dockerfile`, `boot.sh`, `Procfile`) are consistent with what `microblog.py`
and `app/__init__.py` actually do.