Aipress24 Architecture¶
C4 Diagrams¶
The following C4 diagrams describe the current
architecture. They are rendered with Mermaid (source lives inline in this
page). Earlier PlantUML renders under diagrams/c4/ are kept for history but
are superseded by the diagrams below.
Context diagram (level 1)¶
Who uses Aipress24 and which external systems it depends on.
flowchart TB
guest["Guest / anonymous visitor"]
member["Registered member<br/>journalist 路 PR 路 expert 路 academic"]
staff["Aipress24 staff<br/>admin and moderation"]
a24["Aipress24<br/>digital workspace for press and PR"]
stripe["Stripe<br/>payments 路 subscriptions 路 invoices"]
smtp["Email / SMTP<br/>transactional mail"]
sentry["Sentry<br/>error monitoring"]
s3[("S3-compatible object store<br/>images and documents")]
guest -->|"browses public content (HTTPS)"| a24
member -->|"uses the platform (HTTPS)"| a24
staff -->|"administers (HTTPS)"| a24
a24 -->|"card payments and subscriptions (REST)"| stripe
a24 -->|"sends notifications"| smtp
a24 -->|"reports errors"| sentry
a24 -->|"stores and serves files"| s3
smtp -.->|"delivers email"| member
Container diagram (level 2)¶
The runtime pieces. Note there is no Redis: the Dramatiq job queue and the
wesh full-text index both live in PostgreSQL.
flowchart TB
user["Member / staff<br/>web browser"]
subgraph a24["Aipress24 platform"]
web["Web app<br/>Flask 路 WSGI / gunicorn<br/>Jinja + HTMX + PyWire 路 Vite assets"]
admin["Admin app<br/>Starlette + SQLAdmin<br/>ASGI / Granian"]
worker["Background workers<br/>Dramatiq + scheduler"]
db[("PostgreSQL<br/>app data 路 Dramatiq queue 路 wesh search index")]
end
s3[("S3-compatible<br/>object store")]
stripe["Stripe"]
smtp["Email / SMTP"]
sentry["Sentry"]
user -->|HTTPS| web
user -->|HTTPS| admin
web -->|"reads / writes"| db
admin -->|"reads / writes"| db
worker -->|"reads / writes"| db
web -->|"enqueues jobs"| worker
web -->|files| s3
web -->|payments| stripe
worker -->|email| smtp
web -->|errors| sentry
worker -->|errors| sentry
Component diagram (level 3)¶
Inside the web app: feature modules (Flask blueprints) sit on top of shared
cross-cutting layers.
flowchart TB
subgraph mods["Feature modules (Flask blueprints)"]
wire["wire<br/>News"]
swork["swork<br/>Social"]
wip["wip<br/>Work / Newsroom"]
biz["biz<br/>Marketplace"]
events["events"]
bw["bw<br/>Business Wall"]
kyc["kyc<br/>Registration"]
searchm["search<br/>full-text (wesh)"]
notif["notifications"]
stripem["stripe<br/>billing"]
prefs["preferences"]
pub["public 路 dashboard"]
end
subgraph shared["Shared layers"]
security["Security and RBAC<br/>Flask-Security-Too, role checks"]
services["Services (svcs DI)<br/>emails 路 stats 路 notifications 路 sessions"]
ui["PyWire components<br/>+ WTForms renderer"]
models["Models and repositories<br/>SQLAlchemy 2.0 / Advanced-Alchemy"]
end
db[("PostgreSQL")]
s3[("Object store")]
queue["Dramatiq workers"]
mods --> security
mods --> ui
mods --> services
mods --> models
searchm -->|"BM25 index (in Postgres)"| db
services --> queue
services --> s3
models --> db
models --> s3
Modules¶
See Modules.
Services¶
See Services.
Architecture Notes¶
Core Framework Features (Flask)¶
- Routing: Uses Blueprints (
app/modules/*/__init__.py) to organise routes, combining standard Flask@blueprint.routewith flask-classful class-based views for CRUD (app/modules/wip/crud/cbvs/). Navigation entries are declared withconfigure_nav(...). - Request/Response Handling: Uses Flask’s
requestandResponseobjects, handling GET/POST in view functions and CBVs. Usesredirect,jsonify,send_file. - Templating (Jinja2): Uses Jinja2 via Flask’s default integration.
- Template Loading: Loads templates from
app/templates. - Context Processors: Injects variables globally into templates (
app/flask/hooks.py,app/flask/jinja.py). - Custom Filters: Defines custom template filters (
app/ui/datetime_filter.py, registered inapp/flask/main.py). - Custom Macros/Globals: Defines and registers custom macros/global functions (
app/ui/macros/,app/flask/lib/macros.py).
- Template Loading: Loads templates from
- Middleware / Request Lifecycle Hooks:
- Flask: Uses
before_requesthooks (e.g., authentication, injecting extensions) andafter_request(e.g., performance monitoring). Error handlers (errorhandler) are registered. (app/flask/hooks.py,app/flask/main.py). - Dramatiq: Uses custom middleware (
AppContextMiddleware) to manage Flask’s application context within background tasks.
- Flask: Uses
- Configuration Management: Uses
Dynaconffor layered configuration from files (etc/settings.toml,etc/secrets.toml) and environment variables (app/flask/config.py). - Application Factory Pattern:
app/flask/main.py(create_app) uses functions to create and configure the application instances. This allows for different configurations (e.g., testing). - Static File Serving: Implicitly uses Flask’s static file handling (
app/static). Also integrates withFlask-Vitefor modern frontend asset management. - Session Management:
- Uses Flask’s standard session mechanism (likely cookie-based initially).
- A custom
SessionService(app/services/sessions/) built on top of a database model (Session) provides a more persistent, user-or-session-id-tied storage mechanism.
Flask Extensions & Integrations¶
- Database Integration (ORM):
- Flask-SQLAlchemy: Used for integrating SQLAlchemy with Flask (
app/flask/extensions.py). Includes session management tied to the request lifecycle. Defines models using declarative base (app/models/). - Flask-Migrate: Handles database schema migrations based on model changes.
- SQLAlchemy-Utils: Used for utility types like
ArrowType.
- Flask-SQLAlchemy: Used for integrating SQLAlchemy with Flask (
- Authentication & Authorization:
- Flask-Security-Too: Manages user registration, login, password hashing, roles (
User,Rolemodels,SQLAlchemySessionUserDatastore), session authentication, and potentially other security features like email confirmation (though not explicitly shown being used everywhere). Decorators like@roles_requiredmight be used (or custom checks likehas_role).
- Flask-Security-Too: Manages user registration, login, password hashing, roles (
- Forms Handling:
- Flask-WTF: Used for creating and validating forms (
app/modules/wip/crud/cbvs/_forms.py). - WTForms Custom Fields: Custom field types are defined (
app/flask/lib/wtforms/fields/) for richer UI elements (DateTime, Image, RichSelect, RichText). - Custom Form Rendering: A
FormRenderer(app/flask/lib/wtforms/renderer.py) is used to render WTForms with custom structure/styling (likely Tailwind/DaisyUI). The KYC module (app/modules/kyc/dynform.py) uses a dynamic form generation approach based on spreadsheet definitions.
- Flask-WTF: Used for creating and validating forms (
- Internationalization (i18n/l10n):
- Flask-Babel: Integrated for handling different languages and timezones (
app/flask/extensions.py), although explicit usage (like_()translation calls) isn’t visible. Timezone handling (pytz) is used.
- Flask-Babel: Integrated for handling different languages and timezones (
- Email Sending:
- Flask-Mailman: Used for sending emails (
app/flask/extensions.py,app/services/emails/).
- Flask-Mailman: Used for sending emails (
- Background Tasks & Scheduling:
- Dramatiq: Used as a background task queue, likely with Redis as a broker (
app/dramatiq/). Includes custom middleware for Flask app context. - APScheduler: Used within the Dramatiq setup (
@crontab) for cron-like scheduling of background tasks (app/dramatiq/scheduler.py). - Schedule library: Used in the main
server/scheduler.pyfor a simpler, in-process scheduler running in a separate thread.
- Dramatiq: Used as a background task queue, likely with Redis as a broker (
- Command-Line Interface (CLI):
- Flask CLI: Integrated via
flask_super(@command,@group) to add custom commands for tasks like database management (db2,fake), bootstrapping, listing components/pages, running jobs, and managing the search index. (app/flask/cli/).
- Flask CLI: Integrated via
- Security Headers:
- Flask-Talisman: Used to set security-related HTTP headers, including Content Security Policy (CSP), in non-debug environments.
- Frontend Integration:
- Flask-Vite: Manages integration with the Vite frontend build tool.
- Flask-HTMX: Provides server-side support for HTMX interactions (detecting HTMX requests via
htmx.boosted). - Custom Component System (PyWire): A custom system inspired by Livewire/HTMX for building interactive UI components with server-side rendering and state management (
app/flask/lib/pywire/). Handles component rendering (markup_component) and AJAX updates (/livewire/message/route).
- Admin Interface:
- SQLAdmin: Used in the separate
adminapp(Starlette-based) to provide a CRUD interface for database models.
- SQLAdmin: Used in the separate
Architectural Patterns & Other Features¶
- Modular Application Structure (Blueprints): Flask Blueprints are used to structure the application into logical modules (
app/modules/*). - Service Layer / Dependency Injection: Uses
svcsfor registering and accessing services (app/flask/services.py,app/services/). Promotes decoupling. - Repository Pattern: Data access is often abstracted through Repository classes (
app/models/repositories.py,app/services/repositories/). - Model Mixins: Reusable model functionalities (like ID generation, timestamps, ownership, address fields) are implemented using mixins (
app/models/mixins.py). - Class-Based Views: CRUD-heavy modules use flask-classful class-based views (
app/modules/wip/crud/cbvs/) on top of a shared table/form/renderer layer, rather than plain function views. (An older customPageabstraction has been removed.) - ASGI/WSGI Compatibility: The admin app (
adminapp, Starlette/Granian) is ASGI; the main Flask app is WSGI and can be mounted under ASGI viaasgiref.wsgi.WsgiToAsgi. - Application Server: The main app runs under gunicorn (WSGI); the Starlette-based
adminappruns under Granian (ASGI). Development processes are orchestrated with honcho (Procfile-dev). - Search Index Integration: Full-text search is backed by an embedded wesh BM25 index (a single index keyed on the database URL), managed via the
flask searchCLI (app/modules/search/). (Note: earlier revisions of this doc referenced Typesense.)
Tooling¶
- Package Management:
uvmanages dependencies and virtual environments (the project is migrating away from Poetry). Build backend:pdm-backend. - Quality Gates:
ruff(lint + format), thetytype checker (primary) andpyrefly(secondary), plus import-linting,banditandvulture, run viamake lint. - Continuous Integration: Runs on GitHub Actions (
.github/workflows/:ci.yml,tests.yml,lint.yml) and, historically, SourceHut builds (.builds/). Deployment to Fly.io is wired viafly-deploy.yml.