Live Site: https://eterpoetic-62a49da213d8.herokuapp.com/
This README is structured for a Django project with multiple apps
EterPoetic is an interactive and content-rich web application for lovers of poetry and creative writing. Designed for readers and writers, it provides a platform to explore curated poem collections and insightful blog posts. It combines a personal reading experience with community engagement, allowing registered users to favorite poems, comment on articles, and connect with the team.
Key Features:
poetry: Manages all poem and collection content; handles user favoriting logic.blog: Manages all blog posts and user comments.about: Displays team information and provides a “collaborator” application form.accounts: Manages user registration, login, and logout.
EterPoetic is an interactive and content-rich web application for lovers of poetry and creative writing. Designed for readers and writers, it provides a platform to explore curated poem collections and insightful blog posts. It combines a personal reading experience with community engagement, allowing registered users to favorite poems, comment on articles, and connect with the team.
Core Technologies
Live Site: https://eterpoetic-62a49da213d8.herokuapp.com/
Admin Panel: https://eterpoetic-62a49da213d8.herokuapp.com/admin
All pages were designed with Responsive Design to provide a consistent experience across various screen sizes and devices.
| Section | Image Purpose | Example Images |
|---|---|---|
| Core Views | Show how the main views adapt across screen sizes. | Home (Poetry List) View shown on Mobile, Tablet, and Desktop. |
| Key Functionality | Show the Blog or About page in a mobile layout. | A screenshot demonstrating the mobile hamburger menu or mobile comment form. |
This section is for high-quality images that showcase the aesthetic design and key features of your live application. These images should demonstrate the “look and feel” and the user’s interaction flow.
| Section | Image Purpose | Example Images |
|---|---|---|
| Login/Auth Flow | Show the secure sign-in process. | Social Login (Facebook/Google screens), Password Reset flow, Logout confirmation. |
| My Favorites | Demonstrate a core personalized feature. | A view of the “My Favorites” list with multiple poems marked. |
| Site Navigation | Show the main page elements. | Final image of the footer, image of the header bar. |
Readers, emerging writers, and poetry enthusiasts seeking curated content, insightful blog posts, and an engaging community centered around creative writing.
UX Goals: Readability, engagement, responsiveness, accessibility
about app form).| User Story | GitHub Issue | Priority | Status |
|---|---|---|---|
| As a reader, I can access the poetry library so that I can browse and select poems to read. | p4_eterpoetic#1 | Could-Have | Done |
| As a customer I can mark my favorites items so that i can easily identify them. As a logged-in customer, I can easily mark and manage poems as my favorites so that I can quickly find and revisit them later for potential purchase or inspiration. | p4_eterpoetic#7 | Won’t-Have | Done |
| As a user I can register, login in and log out so that i can access to leave comments and participate. As a new or returning visitor, I can securely register an account and manage my login session so that I can fully participate by leaving comments and accessing members-only features. | p4_eterpoetic#5 | Must-Have | Done |
| As a Site Owner, I can receive, review and store collaboration request in the database, so that I can efficiently manage, review and respond to new opportunities. | django-blog#13 | Could-Have | Done |
| As a Site Admin I can create or update the About page content so that it is available on the site. | django-blog#11 | High | Done |
| As a Site User I can click the About link so that I can read about the site. | django-blog#10 | Must-Have | Done |
| As a Site Admin I can create, read, update and delete posts so that I can manage my blog content. | django-blog#7 | Must-Have | Done |
| As a a Site User I can click on a post so that I can read the full text. | django-blog#4 | Must-Have | Done |
| As a Site User I can leave comments on a post so that I can be involved in the conversation. | django-blog#5 | Could-Have | Done |
| As a Site Admin I can create draft post so that I can finish writing the content later. | django-blog#8 | High | Done |
| As a Site User / Admin I can view comments on an individual post so that I can read the conversation. | django-blog#3 | Must-Have | Done |
| As a Site Admin I can approve or disapprove comments so that I can filter out objectionable comments. | django-blog#9 | Could-Have | Done |
| As a Site User I can modify or delete my comment on a post so that I can be involved in the conversation. | django-blog#6 | Could-Have | Done |
| As a site user I can view a paginated list of post so that I can select which post I want to view. | django-blog#1 | Must-Have | Done |
| As a website visitor, I can easily switch the entire website interface and content between English and Spanish so that I can comfortably read and interact with the platform in my preferred language. | p4_eterpoetic#6 | Won’t-Have | In Review |
| As a customer (or user), I can easily order a custom-written poem so that I can receive a unique, personalized piece of poetry for a special occasion. | p4_eterpoetic#2 | Could-Have | Ready |
| As a satisfied customer, I can easily leave a public rating and review of the service so that I can share my experience and help future customers make a decision. | p4_eterpoetic#3 | Should Have | Ready |
| User Story | GitHub Issue | Priority | Status |
|---|---|---|---|
| As a reader, I can access the poetry library so that I can browse and select poems to read. | p4_eterpoetic#1 | Could-Have | Done |
| As a customer I can mark my favorites items so that i can easily identify them. As a logged-in customer, I can easily mark and manage poems as my favorites so that I can quickly find and revisit them later for potential purchase or inspiration. | p4_eterpoetic#7 | Won’t-Have | Done |
| As a user I can register, login in and log out so that i can access to leave comments and participate. As a new or returning visitor, I can securely register an account and manage my login session so that I can fully participate by leaving comments and accessing members-only features. | p4_eterpoetic#5 | Must-Have | Done |
| As a Site Owner, I can receive, review and store collaboration request in the database, so that I can efficiently manage, review and respond to new opportunities. | django-blog#13 | Could-Have | Done |
| As a Site Admin I can create or update the About page content so that it is available on the site. | django-blog#11 | High | Done |
| As a Site User I can click the About link so that I can read about the site. | django-blog#10 | Must-Have | Done |
| As a Site Admin I can create, read, update and delete posts so that I can manage my blog content. | django-blog#7 | Must-Have | Done |
| As a a Site User I can click on a post so that I can read the full text. | django-blog#4 | Must-Have | Done |
| As a Site User I can leave comments on a post so that I can be involved in the conversation. | django-blog#5 | Could-Have | Done |
| As a Site Admin I can create draft post so that I can finish writing the content later. | django-blog#8 | High | Done |
| As a Site User / Admin I can view comments on an individual post so that I can read the conversation. | django-blog#3 | Must-Have | Done |
| As a Site Admin I can approve or disapprove comments so that I can filter out objectionable comments. | django-blog#9 | Could-Have | Done |
| As a Site User I can modify or delete my comment on a post so that I can be involved in the conversation. | django-blog#6 | Could-Have | Done |
| As a site user I can view a paginated list of post so that I can select which post I want to view. | django-blog#1 | Must-Have | Done |
All core user stories were tested using the defined Acceptance Criteria (ACs) set in the corresponding GitHub Issues.
The ‘Access the poetry library’ feature passed the following criteria:
The ‘Mark my favorites items’ feature passed the following criteria, ensuring reliable item marking and list management:
1. Marking a Favorite (AC1-AC2)
2. Viewing and Managing Favorites (AC3-AC4)
The ‘Register, Log In, and Log Out’ feature passed the following criteria, ensuring a complete and secure user authentication flow:
The ‘Collaborator Submission Flow’ feature passed the following criteria, ensuring effective notification and administration:
The ‘Create or update the About page content’ feature passed the following criteria:
The ‘Click the About link’ feature passed the following criteria:
The ‘Blog Post Management (CRUD)’ feature passed the following criteria, ensuring authenticated users can control their content:
The ‘Click on a post’ feature passed the following criteria:
The ‘Blog Commenting and Threading’ feature passed the following criteria, ensuring community engagement and organized discussion:
The ‘Draft Blog Post Management’ feature passed the following criteria, ensuring content creators can work asynchronously:
The ‘View comments on an individual post’ feature passed the following criteria, ensuring transparency and easy moderation:
The ‘Approve or disapprove comments’ feature passed the following criteria, ensuring effective content moderation:
The ‘Modify or delete my comment on a post’ feature passed the following criteria, ensuring users can manage their own contributions:
The ‘View a paginated list of post’ feature passed the following criteria, ensuring users can manage their own contributions:
| User Story | GitHub Issue | Priority | Status | |—|—|—|—| | As a website visitor, I can easily switch the entire website interface and content between English and Spanish so that I can comfortably read and interact with the platform in my preferred language. | p4_eterpoetic#6 | Won’t-Have | In Review | | As a customer (or user), I can easily order a custom-written poem so that I can receive a unique, personalized piece of poetry for a special occasion. | p4_eterpoetic#2 | Could-Have | Ready | | As a satisfied customer, I can easily leave a public rating and review of the service so that I can share my experience and help future customers make a decision. | p4_eterpoetic#3 | Should Have | Ready |
Developer Goal: As the sole developer of this website, my mission is to provide an enjoyable and user-friendly experience by delivering clear, curated, and diverse written content, fostering a sense of community around poetry and creative writing.
User Experience Objectives: From the user’s perspective, I’ve built this site with the following priorities in mind:
This website is designed for readers and creative writers to explore diverse content, engage with the community, and enjoy an accessible reading experience while navigating through different pages.
The main fonts used are Inter and Roboto, with Sans Serif as the fallback. Roboto is chosen for its clean, professional appearance, ensuring optimal readability for long-form content like poetry and blog posts.
--color-primary-brand): #E86A33 (Red-Orange) — Used for main calls-to-action (CTAs) and highlights (Energy/Urgency).--bg-dark): #4C3A51 (Deep Purple/Gray) — Used for footers and navigation (Trust/Creativity).--color-text-dark): #1A2C42 (Deep Navy/Blue) — Ensures high contrast for readability.
--bg-body): #FBF9F6 (Soft Cream/Off-White) — Provides a comfortable background for long reading sessions.#C08A3E (Mustard Gold) — Provides distinct, high-contrast feedback on hover.The palette’s mood is designed to support the literary and creative focus of the platform:
Clear and attractive images support the theme and maintain strong contrast with text for optimal readability.
The logo visually captures the essence of the project:

The design combines an old book with a quill and ink well, representing the intimate act of writing and the poetic tradition that is inherited and continuously renewed. The quill symbolizes inspiration taking form, while the book evokes the lasting presence of written work. The design transforms the ethereal (the subtle, the delicate) into literary expression.
The classic serif typeface conveys elegance and refinement, evoking literary tradition, calmness, and the measured rhythm of timeless poetry.
The palette is composed of warm and natural tones:
Together, these colors suggest the movement of thought flowing toward the page, from the spirit into written expression.
Define goals and audience needs. Our objective is to create a professional platform that focuses on AAA readability and intuitive functionality. The design prioritizes content consumption and creative community engagement.
The following table scores project opportunities based on their Importance (How crucial is it?) and Viability (How realistic is it to implement?), with 5 being the highest score.
| Opportunity / Problem | Importance (Cruciality) | Viability (Feasibility) |
|---|---|---|
| 1. Attractive & functional website | 4 | 5 |
| 2. Engaging user interaction (JavaScript-Python) | 5 | 5 |
| 3. Concise and compelling content | 4 | 4 |
| 4. Convert visitors into customers | 4 | 3 |
| 5. Easy access to fill forms | 4 | 3 |
| TOTALS | 21 | 20 |
Conclusion: The project prioritized opportunities with the highest expected return on investment (Viability $\ge$ 4). The primary focus areas were Engaging User Interaction (Score 25) and ensuring a highly Attractive & Functional Website (Score 20), as these features were crucial (Importance $\ge$ 4) and highly feasible (Viability $\ge$ 5) to implement.
The site is designed around two core user actions:
The website is built using a Django MVT (Model-View-Template) architecture to separate concerns (HTML5, CSS3, JavaScript).
Website Pages/Apps:
Wireframes and layout structure. The website is designed to be clear and simple. The navigational hierarchy ensures easy flow from top to bottom and between main app areas.
Final aesthetic layers (colors, components, imagery). To create a pleasing and understandable view, the design utilizes a high-contrast, modern literary palette (Midnight Teal, Vibrant Terracotta, and Plum Ink) against a soft off-white background to ensure excellent readability.
This section details the structure of your core application models and their relationships, similar to an Entity Relationship Diagram (ERD).
| App | Purpose |
|---|---|
poetry |
Core Content & Business Logic: Manages the Poem and Collection models, search/filtering, and the main favoriting logic. |
blog |
Domain-Specific Features: Manages Blog Posts, Comment Models, and the comment moderation/threading logic. |
accounts |
Authentication & Profile Management: Handles user registration, login/logout, and user profiles (via django-allauth). |
about |
Static Content & Submission Flow: Manages the About page content and the collaborator application form submissions. |
authors |
Creator Metadata: Manages data and profiles for content creators. |
| Path | View | Public/Private | App |
|---|---|---|---|
/ |
PoetryHomeView | Public | poetry |
/poem/<slug:slug>/ |
PoemDetailView | Public | poetry |
/author/<slug:slug>/ |
AuthorDetailView | Public | poetry |
/favorites/ |
FavoritesListView | Private | poetry |
/blog/ |
BlogHomeView | Public | blog |
/blog/<slug:slug>/ |
PostDetailView | Public | blog |
/about/ |
AboutView | Public | about |
/accounts/login/ |
Allauth Login | Public | accounts |
| Model | Create | Read | Update | Delete | App |
|---|---|---|---|---|---|
| Poem/Collection | ✅ Admin | ✅ Public | ✅ Admin | ✅ Admin | poetry |
| Blog Post | ✅ Admin | ✅ Public | ✅ Admin | ✅ Admin | blog |
| User Comment | ✅ User | ✅ Public | ✅ Author | ✅ Author/Admin | blog |
| Favorites | ✅ User | ✅ User | ❌ N/A | ✅ User | poetry |
| Collaborator Req. | ✅ Public | ✅ Admin | ❌ N/A | ✅ Admin | about |
This section details the structure of your three models in the poetry application, which handles dynamic poems, favorites, collections, etc.
| Model | Key | Name | Type | Relationship | App |
|---|---|---|---|---|---|
| Poem | ManyToManyField | favorites |
User model | related_name=’favorite_poems’ (Favorites) | poetry |
| Collection | PrimaryKey | id |
Integer | Auto-generated ID | poetry |
| Author | PrimaryKey | id |
Integer | Auto-generated ID | authors |
| Key | Name | Type | Extra Info / Relationship |
|---|---|---|---|
| PrimaryKey | id |
Integer | Auto-generated ID |
| slug | SlugField | Unique | Used for clean URLs |
| ForeignKey | author |
Author model | CASCADE on delete |
| ForeignKey | collection |
Collection model | SET_NULL on delete (allows collection removal without losing poem) |
| ManyToManyField | favorites |
User model | related_name=’favorite_poems’ (Favorites feature) |
| title_en / title_es | CharField | Multilingual fields | |
| body_en / body_es | TextField | Multilingual content | |
| featured_image | CloudinaryField | Default placeholder | |
| created / updated | DateTimeField | Timestamps |
| Key | Name | Type | Extra Info / Relationship |
|---|---|---|---|
| PrimaryKey | id |
Integer | Auto-generated ID |
| slug | SlugField | Unique | Auto-generated on save |
| name_en / name_es | CharField | Multilingual names | |
| description_en / description_es | TextField | Multilingual descriptions | |
| collection_image | CloudinaryField | Default placeholder |
| Key | Name | Type | Extra Info / Relationship |
|---|---|---|---|
| PrimaryKey | id |
Integer | Auto-generated ID |
| name | CharField | ||
| slug | SlugField | Unique | |
| bio_en / bio_es | TextField | Multilingual bio | |
| photo | CloudinaryField | Default placeholder |
This section details the structure of your two models in the blog application, which handles dynamic content (posts, comments).
| Model | Key | Name | Type | Relationship | App |
|---|---|---|---|---|---|
| Post | ForeignKey | author |
User model | CASCADE on delete; related_name=”blog_posts” | blog |
| Comment | ForeignKey | post |
Post model | CASCADE on delete; related_name=”comments” | blog |
| Key | Name | Type | Extra Info / Relationship |
|---|---|---|---|
| PrimaryKey | id |
Integer | Auto-generated ID |
| title | CharField | Max length 200 | Unique |
| slug | SlugField | Max length 200 | Unique (Used for clean URLs) |
| ForeignKey | author |
User model | CASCADE on delete; related_name=”blog_posts” |
| featured_image | CloudinaryField | Default placeholder | |
| content | TextField | ||
| created_on | DateTimeField | auto_now_add=True | |
| status | IntegerField | Choices (Draft/Published) | Default 0 (Draft) |
| updated_on | DateTimeField | auto_now=True |
| Key | Name | Type | Extra Info / Relationship |
|---|---|---|---|
| PrimaryKey | id |
Integer | Auto-generated ID |
| ForeignKey | post |
Post model | CASCADE on delete; related_name=”comments” |
| ForeignKey | author |
User model | CASCADE on delete; related_name=”commenter” |
| body | TextField | ||
| created_on | DateTimeField | auto_now_add=True | |
| approved | BooleanField | Default False | Used for moderation |
This section details the structure of your two models in the about application, which handles static content and user submissions.
| Model | Key | Name | Type | Relationship | App |
|---|---|---|---|---|---|
| About | PrimaryKey | id |
Integer | Static Content | about |
| CollaborateRequest | PrimaryKey | id |
Integer | Form Submissions | about |
| Key | Name | Type | Extra Info / Relationship |
|---|---|---|---|
| PrimaryKey | id |
Integer | Auto-generated ID |
| title | CharField | Max length 200 | |
| profile_image | CloudinaryField | Default ‘placeholder’ | Used for owner/team photo |
| updated_on | DateTimeField | auto_now=True | Tracks last modification |
| content | TextField | Main text of the About page |
| Key | Name | Type | Extra Info / Relationship |
|---|---|---|---|
| PrimaryKey | id |
Integer | Auto-generated ID |
| name | CharField | Max length 200 | Collaborator’s name |
| EmailField | Collaborator’s contact email | ||
| message | TextField | Collaborator’s proposal/message | |
| read | BooleanField | Default False | Used by Admin to track review status |
This section describes the primary user-facing and administrator forms used throughout the ÉterPoético application and their core validation requirements.
| Form Class | Purpose | Model Used | Key Validation |
|---|---|---|---|
RegistrationForm |
Manages new user sign-up. | (Handled by allauth) |
Requires unique email, secure password length/complexity, and email confirmation. |
CommentForm |
Allows authenticated users to submit feedback on blog posts. | Comment |
Ensures the body field is not empty and links the submission to the correct authenticated User and Post object. |
BlogCreationForm |
Used by administrators/staff to create and edit new blog posts. | Post |
Ensures fields like title, slug, and content are present, and the status (Draft/Published) is correctly set before saving. |
CollaborateForm |
Submits user requests for collaboration. | CollaborateRequest |
Ensures the required fields (name, email, message) are submitted and validates the email format. |
All forms utilize Django’s CSRF (Cross-Site Request Forgery) token validation to ensure security against malicious external requests.
This section should list the URLs used for non-HTML data interaction, which may include features necessary for frontend interactivity.
| URL Path | HTTP Method | Description | Data Format |
|---|---|---|---|
/api/poems/toggle-favorite/<int:poem_id>/ |
POST |
Toggles the user’s favorite status on a poem (Used for seamless frontend updates). | JSON (Expected Success/Failure) |
/api/poems/<str:slug>/ |
GET |
Fetches specific poem data by slug (if using AJAX for detail views). | JSON |
/api/collaborate/submit/ |
POST |
Endpoint that receives the form data for a new collaborator request. | JSON (Expected Success/Error) |
The use of Social Media Login (OAuth) requires that you manage sensitive credentials (like Facebook App ID, Google Client Secret, and your main Django SECRET_KEY) securely.
[cite_start]The most crucial rule is that NO secret key or token should ever be committed to your GitHub repository[cite: 1, 2].
You must verify that all sensitive keys are set as Config Vars (Environment Variables) on Heroku.
| Key | Purpose | Required Location |
|---|---|---|
SECRET_KEY |
Django application security | Heroku Config Vars |
SOCIAL_AUTH_FACEBOOK_KEY & SOCIAL_AUTH_FACEBOOK_SECRET |
Facebook App ID & Facebook App Secret | Heroku Config Vars |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET |
Google Client_ID & Client_SECRET | Heroku Config Vars |
CLOUDINARY_URL |
cloudinary://API_KEY:API_SECRET@CLOUD_NAME |
Heroku Config Vars |
EMAIL_HOST |
smtp.gmail.com |
Heroku Config Vars |
You can check your existing Heroku Config Vars by running:
heroku config -a eterpoetic
| Language | Role in Project |
|---|---|
| Python | Primary Backend Language for the entire application, handling server-side logic, routing, and database interactions through the Django framework. |
| HTML5 | Used to build the basic structure of the website. |
| CSS3 | Styles the front-end to create a visually appealing design and enhance user experience. |
| JavaScript (JS) | Adds interactivity to the website, making the experience more dynamic and engaging for users. |
We relied on various software tools and platforms throughout the development and troubleshooting process, with Google’s SMTP used for secure email delivery instead of Brevo:
| Tool/Platform | Role in Project | Fixes Highlighted |
|---|---|---|
| Python/Django | Core application framework and programming language. | Resolving ModuleNotFoundError, template syntax errors, and URL reversal issues. |
| Heroku | Production deployment and hosting platform. | Fixing the deployment Server Error (500) and resolving CLI and migration sync issues. |
| VS Code / Gitpod | Integrated Development Environment (IDE). | Resolving VS Code Server connection failures and rebuilding native modules like node-pty. |
| Homebrew | Package manager used to install Heroku CLI in the Linux environment. | Resolving “Heroku CLI command not found” errors. |
| Google SMTP | [cite_start]External service used for secure, production-ready email delivery, requiring an App Password for authentication [cite: 594-596]. | [cite_start]Fixing email delivery for password resets and other user notifications by configuring EMAIL_HOST to 'smtp.gmail.com' and providing the 16-digit App Password [cite: 594-596]. |
| Bootstrap (5.3.3) | Frontend framework for responsiveness, styling, and components. | Used for consistent UI patterns and responsive design. |
| Hover.css / jQuery | Hover.css added float transitions; jQuery provided smooth scroll and DOM manipulation. | Used for interactive elements and visual polish. |
| Git / GitHub | Version control and remote repository storage. | Essential for collaboration and deployment via Heroku. |
To get a local copy up and running, follow these simple steps.
# Clone the repository
git clone <REPO_URL>
# Navigate into the project directory
cd <project-folder>
# Create a virtual environment
python -m venv venv
# Activate the virtual environment
# Windows: venv\Scripts\activate
# macOS/Linux: source venv/bin/activate
source venv/bin/activate
# Install core dependencies (including package to read .env file)
pip install -r requirements.txt
pip install python-dotenv
# Run migrations
python manage.py migrate
# Run the server
python manage.py runserver
Local development DEBUG=True, SQLite Production (Heroku) DEBUG=False, PostgreSQL
A detailed overview of the project’s directory structure.
This section details the necessary commands for setting up administrative access and loading initial data.
Use this command during the local setup phase to create the master administrator account:
python manage.py createsuperuser
This section outlines the strategy used to verify project functionality, structure, and accessibility.
To run the project’s test suite:
python manage.py test
This section documents the verification of site functionality across key browsers and device types, confirming a consistent user experience.
| Browser / Device | Key Functionality Tested | Status |
|---|---|---|
| Chrome (Desktop) | Login, Registration, Favorites Toggle, Comment Submission | Passed |
| Firefox (Desktop) | Blog readability, Search/Filtering, Page Navigation | Passed |
| Mobile Devices | Responsive Layout (Verified on Pixel 10 Pro & Samsung S25 Ultra/Edge), Favorites Toggle, Logout | Passed |
The site’s styling was verified for clean structure and adherence to standards.
This section verifies that all frontend JavaScript code adheres to specified style guides and standards (zero warnings or errors).
| JavaScript | JSHint/ESLint | Code adheres to style guide (zero warnings/errors) | (Insert screenshot of zero warnings/errors from the JSHint output here.)
This section verifies that all python code adheres to specified style guides and standards (zero warnings or errors).
The entire site was rigorously checked using the W3C HTML and CSS Validators.
| Validator | Target | Result |
|---|---|---|
| W3C Markup (HTML) | All Core Pages | Validation Passed |
| W3C CSS | Global & App Styles | Validation Passed |
| Area | Tool | Goal | Status |
|---|---|---|---|
| Accessibility | Manual + Lighthouse | WCAG compliance | |
| Responsiveness | DevTools | Works across devices | |
| JavaScript | JSHint/ESLint | Code adheres to style guide (zero warnings/errors) | Passed |
| Pyhton | pep8-ci (CI Python Linter) | Code adheres to style guide (zero warnings/errors) | Passed |
Conclusion: The validation results confirm that the HTML structure of all core public and authenticated pages is error-free, and the CSS styling is clean and valid, adhering to modern web standards.
Lighthouse audits were conducted on core public and authenticated pages to ensure compliance with WCAG (Web Content Accessibility Guidelines).
(Confirm no console errors…)
| Problem | What Caused It | How It Was Fixed |
|---|---|---|
| Admin Login Error | Django expected a “Site” entry in the database, but none existed. | Removed django.contrib.sites from INSTALLED_APPS. |
Missing dj_database_url |
The database-URL helper package wasn’t installed. | Installed it with pip. |
| Missing Cloudinary Modules | Cloudinary packages were required for media storage but not installed. | Installed cloudinary + django-cloudinary-storage. |
Missing crispy_forms |
Project used Crispy Forms, but it wasn’t installed. | Installed django-crispy-forms and crispy-bootstrap5. |
Missing django_summernote |
Summernote editor package wasn’t installed. | Installed django-summernote. |
| 500 Error (caused by NoReverseMatch) | A template tried to use a URL named "home" that didn’t exist. |
Turned on DEBUG locally to identify the issue → added the missing URL name → updated template. |
| POST Request Missing Trailing Slash | A POST was sent to /edit_comment/16 instead of /edit_comment/16/. |
Updated redirect logic to point to the correct URL. |
| Heroku 500 Startup Error | Heroku had an incorrect CLOUDINARY_URL value. |
Updated the Cloudinary environment variable. |
| Migrations Out of Sync | Heroku’s database was missing a Summernote migration. | Re-ran migrations on Heroku. |
| Missing Allauth Join Table | A required table for social login wasn’t created due to incomplete migrations. | Re-applied migrations to create the missing table correctly. |
| Local HTTPS Error | Browser tried to open the dev server using HTTPS. | Cleared HSTS settings and used http://127.0.0.1:8000. |
| Heroku CLI Not Found | Heroku CLI wasn’t installed or not in PATH. | Installed Homebrew → fixed PATH → installed Heroku CLI. |
| Local Email Not Working | Needed different setups for test vs production email. | Local: console backend. Production: Brevo SMTP in env vars. |
| VS Code Server Wouldn’t Connect | VS Code Server couldn’t download properly. | Reinstalled correctly, allowed firewall access, cleared cache, enabled cookies. |
| Tests Failing | Wrong URLs, bad redirects, misplaced variables, missing session messages. | Fixed URL names, added follow=True, moved variables, updated views. |
| Issue | What’s Going On |
|---|---|
| Password mismatch not caught | Confirm-password field is named password_again but allauth expects password2. Needs a custom signup form. |
| Static files not updating on Heroku | Browser/CDN caching sometimes keeps old files. Requires hard refresh or dyno restart. |
| Heroku argument parsing bug | Heroku sometimes breaks with flags like --noinput. Requires using: |
heroku run -- python manage.py collectstatic --noinput |
The EterPoetic application is deployed using Heroku and configured via environment variables to ensure security and portability. The steps below outline both production deployment and local setup so that another developer can successfully run and deploy the project independently.
| File | Content | Purpose |
|---|---|---|
Procfile |
web: gunicorn eterpoetic.wsgi |
Defines the primary web process, using Gunicorn to serve the application via the WSGI entry point. |
The application uses environment variables (Heroku Config Vars) for secure configuration. Sensitive values are not committed to the repository.
| Config Var | Purpose | Importance |
|---|---|---|
SECRET_KEY |
Django security key | Required. Must be set on Heroku |
DEBUG |
Enables/disables Django debug mode | Required. Set to False in production |
DATABASE_URL |
Postgres connection string | Required. |
CLOUDINARY_URL |
Cloudinary credentials for media storage | Required. Misconfiguration may cause server errors |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET |
Google OAuth authentication | Optional (only if Google login is enabled) |
FACEBOOK_APP_ID / FACEBOOK_APP_SECRET |
Facebook OAuth authentication | Optional (only if Facebook login is enabled) |
ALLOWED_HOSTS |
Allowed production domains/hostnames | Required. |
EMAIL_HOST |
SMTP server host | Optional |
EMAIL_HOST_USER |
SMTP username | Optional |
EMAIL_HOST_PASSWORD |
SMTP app password (e.g., 16-digit app password) | Optional |
DEFAULT_FROM_EMAIL |
Default sender email address | Optional |
Official Heroku Deployment Guide (Ctrl + click)
This application has been deployed from GitHub using Heroku. Here’s how:
Create an account at heroku.com
Heroku Official Page (Ctrl + click)
Create an app, give it a name for a Project, and select a region
Under resources search for postgres, and add a Postgres database to the app
#### Heroku Postgres Setup
Heroku automatically provides DATABASE_URL via Config Vars. This variable is not stored locally and not committed to version control (env.py/.env)
pip3 install dj-database-url psycopg2-binary gunicorn
Create a Procfile with the text: web: gunicorn eterpoetic.wsgi
Run pip3 freeze > requirements.txt so both are added to the requirements.txt file
In the settings.py ensure the connection is to the Heroku postgres database, no indentation if you are not using a separate test database env.py/.env Remove or comment out DATABASE_URL in .env locally for Local → SQLite (db.sqlite3). Heroku → Postgres (via Config Vars). Clean separation
DEBUG is controlled via environment variables (DEBUG=True locally, DEBUG=False in Heroku Config Vars)
Run “python3 manage.py showmigrations” to check the status of the migrations
heroku run python manage.py migrate -a <app-name>
heroku run python manage.py createsuperuser -a <app-name>
heroku run python manage.py loaddata your_fixture.json -a <app-name>
DISABLE_COLLECTSTATIC=1 may be used temporarily for troubleshooting and should be removed once static files are working correctly.
Ensure the following environment variables are set in Heroku
Connect the app to GitHub, and enable automatic deploys from main if you wish
Click deploy to deploy your application to Heroku for the first time
In Deploy, connect the Heroku app to the GitHub repository
Deploy the main branch.
heroku open -a <app-name>
heroku logs --tail -a <app-name>
The project can be run locally by following the steps below. This allows another developer to clone, configure, and run the application in a development environment.
Security Note: Local environment variables must be stored in a local .env (or env.py) file, and this file must be included in .gitignore to ensure sensitive data is not committed to the repository.
git clone <repository-url>
cd p4_eterpoetic
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
Configure local environment variables (do not commit secrets or data with compromised information):
| Config Var | Purpose | Importance |
|---|---|---|
SECRET_KEY |
Django Local security key. | Required. locally in .env |
DEBUG |
Development mode | True locally, False in production |
DATABASE_URL |
Local DB connection. | Required. PostgreSQL URL or a SQLite. |
CLOUDINARY_URL |
Media storage API. | Required. for images. |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET |
Google OAuth authentication. | Optional |
FACEBOOK_APP_ID / FACEBOOK_APP_SECRET |
Facebook OAuth authentication. | Optional |
EMAIL_HOST |
SMTP server host | Optional |
EMAIL_HOST_USER |
SMTP username | Optional |
EMAIL_HOST_PASSWORD |
SMTP app password | Optional |
DEFAULT_FROM_EMAIL |
Default sender email address | Optional |
ALLOWED_HOSTS |
Allowed hostnames | Required in production |
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver
| Problem | What Caused It | How It Was Fixed |
|---|---|---|
| Heroku 500 Error on Startup | Heroku was using an outdated or invalid CLOUDINARY_URL, causing the application to fail during startup. |
Updated the Cloudinary environment variable in Heroku to the correct, active one. |
| Model Changes Not Applied on Heroku | Heroku’s database did not include the latest django_summernote migrations, resulting in warnings about unapplied migrations. |
Ran migrations on Heroku after pushing updated migration files. |
| Heroku CLI “command not found” | The Heroku command-line tool wasn’t installed or the system PATH wasn’t configured. | Installed Homebrew → fixed PATH → installed the Heroku CLI via Homebrew. |
| Heroku Misreading Command Flags | Heroku interpreted Django flags (e.g., --noinput) as Heroku flags. |
Added -- before the Django command: heroku run -- python manage.py collectstatic --noinput |
| Known Issue | Status/Impact | Root Cause |
|---|---|---|
| Static File Deployment Cache | Intermittent: Front-end changes occasionally require hard refreshes (Ctrl/Cmd + Shift + R) to display on the live Heroku site. |
WhiteNoise + browser caching: static files are aggressively cached unless their hashed filenames change. If a file’s hash doesn’t update, browsers may continue serving the old version. |
To ensure code quality and a clear project history, please adhere to the following guidelines when contributing:
When you begin new work, create a branch using one of these prefixes to clearly define the nature of your changes:
| Prefix | Use Case | Example |
|---|---|---|
feat/ |
New features or adding significant functionality. | feat/user-onboarding-flow |
fix/ |
Bug fixes or corrections to existing incorrect behavior. | fix/social-account-table |
docs/ |
Changes to documentation only (README, Wiki, guides). | docs/update-readme-bugs |
Before a Pull Request can be merged into the main branch, it must satisfy these two core criteria:
This project was made possible by the following resources and collaborators: