Architecture

ushman.dev is a Django application with Wagtail providing the content management layer. The application uses PostgreSQL for persistent data and managed services for hosting, file storage, content delivery, and email.

The architecture is intentionally conventional. The site does not require a large number of independent services, and functionality is kept within the Django application unless there is a practical reason to move it elsewhere.

Application Architecture

Django provides the foundation of the application. It is responsible for URL routing, database access, forms, configuration, application logic, and integration with external services.

Wagtail runs within Django and provides content management functionality. Content-managed pages, images, documents, site settings, and reusable content components are managed through Wagtail, while functionality that does not require editorial control can be implemented directly in Django.

PostgreSQL stores application and CMS data.

Uploaded media and static assets are stored in Amazon S3 and delivered through CloudFront. The S3 bucket is private, with CloudFront providing the public delivery layer through Origin Access Control.

Application email is delivered through Amazon SES.

The Django application and PostgreSQL database are hosted on Heroku.

Application Components

The project is divided into Django applications according to responsibility.

basepage

Provides the common Wagtail page model used by content-managed pages. Shared page behavior, including SEO fields and other functionality required across page types, is defined here.

core

Contains application-wide functionality that does not belong to a specific content type. This includes site settings, template tags, administration customizations, SEO rendering, forms, utilities, and conventional Django views such as search.

content

Contains general-purpose content page types. These pages provide the primary building blocks for informational content that does not require a specialized application model.

blocks

Contains reusable Wagtail StreamField blocks and their templates. Components such as headings, rich text, cards, images, screenshots, notes, and architecture diagrams are defined here so that presentation and behavior remain consistent wherever they are used.

portfolio

Contains structured page types used to document projects and case studies. Project-specific metadata is stored in model fields, while narrative project content is composed from reusable StreamField blocks.

home

Contains the site’s home page and homepage-specific content structure.

This separation is intended to keep reusable infrastructure independent from individual content types while avoiding unnecessary abstraction into additional Django applications.

Content Architecture

Wagtail content is modeled using a combination of structured model fields and StreamField.

Information with a consistent meaning or application-level purpose is stored in explicit model fields. For example, a portfolio project can have a summary, featured image, project URL, source-code URL, and technology list independently of the narrative content describing the project.

Long-form page content is composed using StreamField. The available blocks represent meaningful content structures rather than arbitrary layout controls.

Examples include:

  • headings;

  • rich text;

  • card grids;

  • images;

  • screenshots;

  • notes; and

  • architecture diagrams.

Templates determine the HTML structure, responsive behavior, and accessibility of these components. Content editors therefore select the type of content they are creating without needing to control its underlying markup.

This also allows presentation and accessibility improvements to be made at the component level and applied consistently wherever that component is used.

Page Architecture

Content-managed pages inherit from a common Wagtail base page model.

The base page provides behavior that should remain consistent across page types, including shared SEO metadata. Individual page models extend that foundation with fields and behavior specific to their purpose.

Not every application URL is represented by a Wagtail page. Views that are primarily application behavior rather than managed content can remain conventional Django views.

Site-wide components are designed to support both cases. Navigation, search, site settings, and SEO rendering do not assume that every request contains a Wagtail page object.

This keeps the CMS responsible for managed content without requiring the entire application to be modeled as CMS pages.

Configuration

Configuration is separated from application code.

Settings shared by all environments are maintained in the project’s base Django settings. Environment-specific settings extend that configuration for local development and deployed environments.

Sensitive values and deployment-specific configuration are supplied through environment variables rather than committed to source control. These values include database connections, storage credentials, email configuration, secret keys, and other service-specific settings.

Local development uses local services where practical. For example, media files can use filesystem storage and email can be written to the console rather than requiring production AWS services.

Production configuration enables the managed services required by the deployed application without requiring application code to change between environments.

External Services

External services are kept behind defined application boundaries rather than being treated as part of the application’s core data model.

For this site, those services are intentionally limited:

  • Heroku provides application and database hosting.

  • Amazon S3 provides persistent file storage.

  • CloudFront provides public delivery of static files and media.

  • Amazon SES provides outbound email delivery.

Additional services are introduced only when the application has a requirement that justifies them. The current architecture does not require a task queue, distributed cache, dedicated search service, or separate application API.

Analytics and Privacy

Google Analytics 4 (GA4) is used for basic site-usage analytics. Analytics is optional and is not loaded until a visitor explicitly grants permission.

Consent is managed by a small first-party JavaScript implementation rather than a third-party consent-management platform. The visitor’s analytics preference is stored locally in the browser and can be changed at any time through the Privacy settings control in the site footer.

When analytics is not permitted, the Google Analytics JavaScript library is not loaded and no analytics requests are made by the site. If consent is revoked after analytics has been enabled, analytics is disabled for the current page and its first-party cookies are removed. Subsequent page loads do not load Google Analytics unless consent is granted again.

The implementation is intentionally limited to the site’s current requirements. It manages a single optional analytics service rather than attempting to provide a general-purpose consent-management platform.

Architecture Principles

The architecture follows a few recurring principles:

  • Django is the application platform; Wagtail is the content management layer within it.

  • Structured data is modeled explicitly when the application needs to understand its meaning.

  • StreamField is used for flexible narrative content without exposing arbitrary page layout to content editors.

  • Shared behavior is implemented once and reused across page types.

  • Environment-specific configuration remains outside the codebase.

  • Managed services are used where they remove meaningful operational work.

  • Additional infrastructure is introduced when requirements justify it, rather than in anticipation of hypothetical future needs.

The result is a relatively small application architecture with clear boundaries between application logic, managed content, persistent data, and external infrastructure.