Operations
Deployment begins the operational life of an application rather than ending the development process.
Once an application is in production, databases, dependencies, external services, credentials, content, and infrastructure continue to change. Operational practices are intended to make those changes manageable and to make failures visible, understandable, and recoverable.
For this site, those practices are intentionally proportional to the size and importance of the application. Additional infrastructure is introduced when it solves an operational problem rather than simply because it is available.
Backups and Recovery
Persistent application data is backed up independently of the running application instances.
The PostgreSQL database is backed up regularly using the capabilities of the managed database platform. Uploaded files are stored separately in Amazon S3 rather than on the application filesystem.
This separation is important because Heroku application instances are disposable. Anything that must survive a deployment, restart, or replacement of an application instance belongs in a persistent data service rather than on the instance filesystem.
A backup is useful only if the data can be restored. Recovery planning therefore includes understanding what data is persistent, where it is stored, how it is backed up, and what would be required to restore the application after a failure.
Application releases and database backups solve different problems. Rolling back application code does not restore modified data, and restoring a database does not necessarily reverse changes made to external systems.
Logging, Error Reporting, and Notifications
The application uses centralized logging to provide visibility into errors, unexpected requests, failed processes, and other operational information.
Application code records enough context to make failures diagnosable without unnecessarily logging sensitive information.
Not every logged event requires immediate attention. Conditions that may affect application availability, data integrity, or important application functionality can generate notifications rather than depending on someone periodically reviewing logs.
This creates a distinction between information that should be available for later investigation and conditions that should actively get someone’s attention.
Alerting is intended to make significant failures visible without turning routine application activity into unnecessary notifications.
Automated Maintenance
Routine operational work is automated when doing so reduces repetitive work or the risk that an important task will be forgotten.
Depending on the application, this can include activities such as:
database backups;
automated tests;
broken-link checks;
accessibility scans;
data synchronization;
cache or temporary-data cleanup; and
other scheduled maintenance tasks.
Not every possible task benefits from automation. A task is a better candidate when it is repetitive, can be performed predictably, and has a meaningful consequence if it is forgotten.
Automated processes should also make failures visible. A scheduled process that silently stops running can be more difficult to operate than the manual process it replaced.
Application Monitoring
Operational monitoring includes more than determining whether the web server returns a successful response.
A website can remain online while important parts of it deteriorate. Links can break, content changes can introduce accessibility problems, external services can fail, dependencies can become outdated, and application behavior can change in unexpected ways.
Automated checks are used where they provide useful signals, supplemented by application logging, tests, and manual review where automation cannot determine whether behavior is correct.
Monitoring is intended to answer a practical question: if something important stops working, how will someone know?
Dependencies and Platform Maintenance
The application depends on software and services that continue to evolve after deployment.
Python, Django, Wagtail, PostgreSQL, third-party libraries, Heroku, AWS services, browsers, and external APIs all change over time. Maintaining the application therefore includes periodically reviewing and updating these dependencies.
Dependency upgrades are treated as application changes. They are tested and move through the normal development and deployment workflow rather than being applied directly to production.
External integrations require similar attention. APIs can change, credentials can expire, authentication requirements can evolve, and services can be replaced or discontinued.
The fact that an integration has operated reliably for several years does not mean it no longer requires maintenance.
Security and Privacy
Security and privacy are ongoing operational concerns rather than one-time configuration tasks.
Framework and dependency updates are applied as part of normal maintenance. Credentials are kept outside the source repository and access to external services is limited to what the application requires.
Application behavior is also reviewed as the site changes. New forms, analytics, embedded services, integrations, or content features can introduce new security or privacy considerations even when the underlying application architecture remains unchanged.
Operational safeguards should evolve with the application rather than being treated as a checklist completed at launch.
Long-Term Ownership
The application is designed with the expectation that it may eventually need to be understood, maintained, or extended by someone who was not involved in its original development.
That affects how code is structured, how systems are documented, how administrative interfaces are designed, how deployments are performed, how failures are reported, and how routine maintenance is automated.
Where practical, the application should explain itself through conventional structure, predictable behavior, useful documentation, and administrative interfaces that do not depend on knowledge held only by the original developer.
This also favors maintainable, well-understood approaches over unnecessary complexity. A technically clever solution has limited value if the next person responsible for the application cannot reasonably understand, troubleshoot, or extend it.
Robustness does not mean that failures never occur. Databases, networks, APIs, credentials, dependencies, and external services will eventually create problems.
The objective is to design the application so that those problems are visible, recoverable, and understandable, even when the person responding to them is encountering the application for the first time.
Operational Principles
The operational approach can be summarized by a few principles:
Persistent data does not depend on disposable application instances.
Backups and recovery are treated as related but distinct responsibilities.
Important failures should become visible without requiring constant log review.
Automation should remove repetitive obligations without hiding failures.
Dependencies and external services require maintenance after launch.
Security and privacy requirements are reconsidered as the application changes.
Documentation is part of operating the application, not only developing it.
Systems should be understandable by people other than their original developers.
The goal is not to prevent every possible failure. It is to build and operate software so that failures can be detected, understood, and recovered from without relying on undocumented knowledge.